Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     Copyright 2016, 2019, 2022 Anton Krotov
  3.  
  4.     This file is part of fb2read.
  5.  
  6.     fb2read is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 3 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     fb2read is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with fb2read. If not, see <http://www.gnu.org/licenses/>.
  18. *)
  19.  
  20. MODULE Strings;
  21.  
  22. IMPORT sys := SYSTEM, KOSAPI;
  23.  
  24.  
  25. TYPE
  26.  
  27.   STRING* = ARRAY 1024 OF CHAR;
  28.  
  29.   UTF8*   = ARRAY 8 OF CHAR;
  30.  
  31.   CHARS*  = RECORD first*, last* : INTEGER END;
  32.  
  33.  
  34. VAR
  35.  
  36.   CS: BOOLEAN;
  37.  
  38.  
  39. PROCEDURE [ccall,   "base64.obj",      ""] base64_decode (inp, outp: INTEGER; Len: INTEGER): INTEGER; END;
  40. PROCEDURE [stdcall, "rasterworks.obj", ""] countUTF8Z (string, byteQuantity: INTEGER): INTEGER; END;
  41.  
  42. PROCEDURE DelLeft(VAR s: STRING; count: INTEGER);
  43. VAR i, max: INTEGER;
  44. BEGIN
  45.   max := LENGTH(s) - count - 1;
  46.   IF max >= 0 THEN
  47.     FOR i := 0 TO max DO
  48.       s[i] := s[i + count]
  49.     END
  50.   END
  51. END DelLeft;
  52.  
  53.  
  54. PROCEDURE Trim*(VAR s: STRING; ch: CHAR);
  55. VAR i, n: INTEGER;
  56. BEGIN
  57.   i := 0;
  58.   WHILE s[i] = ch DO
  59.     INC(i)
  60.   END;
  61.   DelLeft(s, i);
  62.   n := LENGTH(s) - 1;
  63.   IF n >= 0 THEN
  64.     i := n;
  65.     WHILE s[i] = ch DO
  66.       DEC(i)
  67.     END;
  68.     IF n # i THEN
  69.       s[i + 1] := 0X
  70.     END
  71.   END
  72. END Trim;
  73.  
  74.  
  75. PROCEDURE GetChar*(chars: CHARS; i: INTEGER): CHAR;
  76. VAR c: CHAR;
  77. BEGIN
  78.   ASSERT(chars.first + i <= chars.last);
  79.   sys.GET(chars.first + i, c)
  80.   RETURN c
  81. END GetChar;
  82.  
  83.  
  84. PROCEDURE Reverse*(VAR s: ARRAY OF CHAR);
  85. VAR i, j: INTEGER; c: CHAR;
  86. BEGIN
  87.   i := 0;
  88.   j := LENGTH(s) - 1;
  89.   WHILE i < j DO
  90.     c := s[i];
  91.     s[i] := s[j];
  92.     s[j] := c;
  93.     INC(i);
  94.     DEC(j)
  95.   END
  96. END Reverse;
  97.  
  98.  
  99. PROCEDURE IntToString*(x: INTEGER; VAR s: STRING);
  100. VAR n, i: INTEGER;
  101. BEGIN
  102.   i := 0;
  103.   REPEAT
  104.     n := x MOD 10;
  105.     x := x DIV 10;
  106.     s[i] := CHR(ORD("0") + n);
  107.     INC(i)
  108.   UNTIL x = 0;
  109.   s[i] := 0X;
  110.   Reverse(s)
  111. END IntToString;
  112.  
  113.  
  114. PROCEDURE isdigit(c: CHAR): BOOLEAN;
  115.   RETURN ("0" <= c) & (c <= "9")
  116. END isdigit;
  117.  
  118.  
  119. PROCEDURE CharsToInt*(s: CHARS; VAR err: BOOLEAN): INTEGER;
  120. VAR n, i, res, len: INTEGER; c: CHAR;
  121. BEGIN
  122.   res := 0;
  123.   len := s.last - s.first + 1;
  124.   err := len <= 0;
  125.   FOR i := 0 TO s.last - s.first DO
  126.     c := GetChar(s, i);
  127.     IF isdigit(c) THEN
  128.       n := ORD(c) - ORD("0");
  129.       res := res * 10 + n
  130.     ELSE
  131.       err := TRUE
  132.     END
  133.   END
  134.   RETURN res
  135. END CharsToInt;
  136.  
  137.  
  138. PROCEDURE Append*(VAR str1: STRING; str2: STRING);
  139. VAR
  140.   len1, len2 : INTEGER;
  141.   i, j       : INTEGER;
  142. BEGIN
  143.   len1 := LENGTH(str1);
  144.   len2 := LENGTH(str2);
  145.   ASSERT(len1 + len2 < LEN(str1));
  146.   j := len1;
  147.   FOR i := 0 TO len2 - 1 DO
  148.     str1[j] := str2[i];
  149.     INC(j)
  150.   END;
  151.   str1[j] := 0X
  152. END Append;
  153.  
  154.  
  155. PROCEDURE GetPath*(VAR S: STRING);
  156. VAR i, j: INTEGER;
  157. BEGIN
  158.   j := 0;
  159.   i := LENGTH(S) - 1;
  160.   WHILE i >= 0 DO
  161.     IF S[i] = "/" THEN
  162.       j := i;
  163.       i := 0
  164.     END;
  165.     DEC(i)
  166.   END;
  167.   S[j] := 0X
  168. END GetPath;
  169.  
  170.  
  171. PROCEDURE PutChar*(chars: CHARS; i: INTEGER; c: CHAR);
  172. BEGIN
  173.   ASSERT(chars.first + i <= chars.last);
  174.   sys.PUT(chars.first + i, c)
  175. END PutChar;
  176.  
  177.  
  178. PROCEDURE StrToChars*(str: ARRAY OF CHAR; VAR chars: CHARS);
  179. BEGIN
  180.   ASSERT(str # "");
  181.   chars.first := sys.ADR(str[0]);
  182.   chars.last  := sys.ADR(str[LENGTH(str) - 1])
  183. END StrToChars;
  184.  
  185.  
  186. PROCEDURE PtrToString*(ptr: INTEGER; VAR S: STRING);
  187. VAR i: INTEGER; c: CHAR;
  188. BEGIN
  189.   i := 0;
  190.   REPEAT
  191.     sys.GET(ptr, c);
  192.     S[i] := c;
  193.     INC(i);
  194.     INC(ptr)
  195.   UNTIL (c = 0X) OR (i = LEN(S));
  196.   S[i - 1] := 0X
  197. END PtrToString;
  198.  
  199.  
  200. PROCEDURE CharsEq*(chars1, chars2: CHARS): BOOLEAN;
  201. VAR
  202.   pos, len2  : INTEGER;
  203.   c1, c2     : CHAR;
  204.   Result     : BOOLEAN;
  205.  
  206.   PROCEDURE CAP(VAR c: CHAR);
  207.   BEGIN
  208.     IF ~CS & ("a" <= c) & (c <= "z") THEN
  209.       c := CHR(ORD(c) - 32)
  210.     END
  211.   END CAP;
  212.  
  213. BEGIN
  214.   pos  := chars1.last - chars1.first;
  215.   len2 := chars2.last - chars2.first;
  216.   IF pos = len2 THEN
  217.     REPEAT
  218.       c1 := GetChar(chars1, pos);
  219.       c2 := GetChar(chars2, pos);
  220.       CAP(c1);
  221.       CAP(c2);
  222.       DEC(pos)
  223.     UNTIL (c1 # c2) OR (pos = -1);
  224.     Result := c1 = c2
  225.   ELSE
  226.     Result := FALSE
  227.   END
  228.   RETURN Result
  229. END CharsEq;
  230.  
  231.  
  232. PROCEDURE CharsEqStr*(chars: CHARS; str: STRING): BOOLEAN;
  233. VAR
  234.   chars2: CHARS;
  235. BEGIN
  236.   StrToChars(str, chars2)
  237.   RETURN CharsEq(chars, chars2)
  238. END CharsEqStr;
  239.  
  240.  
  241. PROCEDURE SetCS*(value: BOOLEAN);
  242. BEGIN
  243.   CS := value
  244. END SetCS;
  245.  
  246.  
  247. PROCEDURE Utf8Length*(chars: CHARS): INTEGER;
  248.   RETURN countUTF8Z(chars.first, chars.last - chars.first + 1)
  249. END Utf8Length;
  250.  
  251.  
  252. PROCEDURE Replace*(VAR chars: CHARS; str1, str2: ARRAY OF CHAR);
  253. VAR
  254.   temp: CHARS;
  255.   s   : CHARS;
  256.   len1: INTEGER;
  257.   len2: INTEGER;
  258.   diff: INTEGER;
  259.  
  260.   PROCEDURE Put(first, last, len1, len2, diff: INTEGER; str2: ARRAY OF CHAR);
  261.   VAR i: INTEGER; c: CHAR;
  262.   BEGIN
  263.     sys.MOVE(sys.ADR(str2[0]), first, len2);
  264.     FOR i := first + len1 TO last DO
  265.       sys.GET(i, c);
  266.       sys.PUT(i - diff, c);
  267.     END
  268.   END Put;
  269.  
  270. BEGIN
  271.   len1 := LENGTH(str1);
  272.   len2 := LENGTH(str2);
  273.   diff := len1 - len2;
  274.   ASSERT(diff >= 0);
  275.   ASSERT(len1 > 0);
  276.   StrToChars(str1, s);
  277.   temp := chars;
  278.   temp.last := temp.first + len1 - 1;
  279.   WHILE temp.last <= chars.last DO
  280.     IF CharsEq(temp, s) THEN
  281.       Put(temp.first, chars.last, len1, len2, diff, str2);
  282.       chars.last := chars.last - diff;
  283.       temp.first := temp.first + len2;
  284.       temp.last  := temp.first + len1 - 1
  285.     ELSE
  286.       INC(temp.first);
  287.       INC(temp.last)
  288.     END
  289.   END
  290. END Replace;
  291.  
  292.  
  293. PROCEDURE utf8*(code: INTEGER; VAR uchar: UTF8);
  294. BEGIN
  295.   uchar[0] := 0X;
  296.   IF code < 80H THEN
  297.     uchar[0] := CHR(code);
  298.     uchar[1] := 0X
  299.   ELSIF code < 800H THEN
  300.     uchar[1] := CHR(ORD(BITS(code) * {0..5}) + 80H);
  301.     uchar[0] := CHR(ASR(code, 6) + 0C0H);
  302.     uchar[2] := 0X
  303.   ELSIF code < 10000H THEN
  304.     uchar[2] := CHR(ORD(BITS(code) * {0..5}) + 80H);
  305.     code := ASR(code, 6);
  306.     uchar[1] := CHR(ORD(BITS(code) * {0..5}) + 80H);
  307.     uchar[0] := CHR(ASR(code, 6) + 0E0H);
  308.     uchar[3] := 0X
  309. (*
  310.   ELSIF code < 200000H THEN
  311.   ELSIF code < 4000000H THEN
  312.   ELSE  *)
  313.   END
  314. END utf8;
  315.  
  316.  
  317. PROCEDURE EntOct*(VAR chars: CHARS): BOOLEAN;
  318. VAR
  319.   i     : INTEGER;
  320.   c     : CHAR;
  321.   amp   : BOOLEAN;
  322.   oct   : BOOLEAN;
  323.   val   : INTEGER;
  324.   exit  : BOOLEAN;
  325.   str   : STRING;
  326.   str2  : STRING;
  327.   uchar : UTF8;
  328.   res   : BOOLEAN;
  329.  
  330. BEGIN
  331.   i := 0;
  332.   amp := FALSE;
  333.   oct := FALSE;
  334.   res := FALSE;
  335.   WHILE i <= chars.last - chars.first DO
  336.     c := GetChar(chars, i);
  337.     CASE c OF
  338.     |"&":
  339.       amp := TRUE;
  340.       oct := FALSE
  341.     |"#":
  342.       oct := amp;
  343.       amp := FALSE
  344.     |"0".."9":
  345.       IF oct THEN
  346.         val := 0;
  347.         str := "&#";
  348.         str2[1] := 0X;
  349.         exit := FALSE;
  350.         REPEAT
  351.           val := val * 10 + ORD(c) - ORD("0");
  352.           str2[0] := c;
  353.           Append(str, str2);
  354.           INC(i);
  355.           IF i <= chars.last - chars.first THEN
  356.             c := GetChar(chars, i)
  357.           ELSE
  358.             exit := TRUE
  359.           END
  360.         UNTIL ~isdigit(c) OR exit;
  361.         IF c = ";" THEN
  362.           str2[0] := c;
  363.           Append(str, str2);
  364.           utf8(val, uchar);
  365.           Replace(chars, str, uchar);
  366.           res := TRUE;
  367.           i := chars.last - chars.first
  368.         ELSE
  369.           IF ~exit THEN
  370.             DEC(i);
  371.             amp := FALSE;
  372.             oct := FALSE
  373.           END
  374.         END
  375.       ELSE
  376.         amp := FALSE
  377.       END
  378.     ELSE
  379.       amp := FALSE;
  380.       oct := FALSE
  381.     END;
  382.     INC(i)
  383.   END
  384.   RETURN res
  385. END EntOct;
  386.  
  387.  
  388. PROCEDURE UCase*(VAR s: STRING);
  389. VAR i, n: INTEGER; c: CHAR;
  390. BEGIN
  391.   n := LENGTH(s) - 1;
  392.   FOR i := 0 TO n DO
  393.     c := s[i];
  394.     IF ("a" <= c) & (c <= "z") OR (0A0X <= c) & (c <= 0AFX) THEN
  395.       c := CHR(ORD(c) - 32)
  396.     ELSIF (0E0X <= c) & (c <= 0EFX) THEN
  397.       c := CHR(ORD(c) - 50H)
  398.     ELSIF (c = 0F1X) OR (c = 0F3X) OR (c = 0F5X) OR (c = 0F7X) THEN
  399.       c := CHR(ORD(c) - 1)
  400.     END;
  401.     s[i] := c
  402.   END
  403. END UCase;
  404.  
  405.  
  406. PROCEDURE Base64* (VAR chars: CHARS);
  407. BEGIN
  408.         chars.last := chars.first + base64_decode(chars.first, chars.first, chars.last - chars.first + 1) - 1
  409. END Base64;
  410.  
  411.  
  412. BEGIN
  413.   CS := TRUE
  414. END Strings.
  415.