Subversion Repositories Kolibri OS

Rev

Rev 9896 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     Copyright 2016, 2019, 2022, 2023 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, Encoding;
  23.  
  24.  
  25. TYPE
  26.  
  27.   STRING* = ARRAY 1024 OF CHAR;
  28.  
  29.   CHARS*  = RECORD first*, last* : INTEGER END;
  30.  
  31.  
  32. VAR
  33.  
  34.   CS: BOOLEAN;
  35.  
  36.  
  37. PROCEDURE [ccall,   "base64.obj",      ""] base64_decode (inp, outp: INTEGER; Len: INTEGER): INTEGER; END;
  38. PROCEDURE [stdcall, "rasterworks.obj", ""] countUTF8Z (string, byteQuantity: INTEGER): INTEGER; END;
  39.  
  40. PROCEDURE DelLeft(VAR s: STRING; count: INTEGER);
  41. VAR i, max: INTEGER;
  42. BEGIN
  43.   max := LENGTH(s) - count - 1;
  44.   IF max >= 0 THEN
  45.     FOR i := 0 TO max DO
  46.       s[i] := s[i + count]
  47.     END
  48.   END
  49. END DelLeft;
  50.  
  51.  
  52. PROCEDURE Trim*(VAR s: STRING; ch: CHAR);
  53. VAR i, n: INTEGER;
  54. BEGIN
  55.   i := 0;
  56.   WHILE s[i] = ch DO
  57.     INC(i)
  58.   END;
  59.   DelLeft(s, i);
  60.   n := LENGTH(s) - 1;
  61.   IF n >= 0 THEN
  62.     i := n;
  63.     WHILE s[i] = ch DO
  64.       DEC(i)
  65.     END;
  66.     IF n # i THEN
  67.       s[i + 1] := 0X
  68.     END
  69.   END
  70. END Trim;
  71.  
  72.  
  73. PROCEDURE GetChar*(chars: CHARS; i: INTEGER): CHAR;
  74. VAR c: CHAR;
  75. BEGIN
  76.   ASSERT(chars.first + i <= chars.last);
  77.   sys.GET(chars.first + i, c)
  78.   RETURN c
  79. END GetChar;
  80.  
  81.  
  82. PROCEDURE Reverse*(VAR s: ARRAY OF CHAR);
  83. VAR i, j: INTEGER; c: CHAR;
  84. BEGIN
  85.   i := 0;
  86.   j := LENGTH(s) - 1;
  87.   WHILE i < j DO
  88.     c := s[i];
  89.     s[i] := s[j];
  90.     s[j] := c;
  91.     INC(i);
  92.     DEC(j)
  93.   END
  94. END Reverse;
  95.  
  96.  
  97. PROCEDURE IntToString*(x: INTEGER; VAR s: STRING);
  98. VAR n, i: INTEGER;
  99. BEGIN
  100.   i := 0;
  101.   REPEAT
  102.     n := x MOD 10;
  103.     x := x DIV 10;
  104.     s[i] := CHR(ORD("0") + n);
  105.     INC(i)
  106.   UNTIL x = 0;
  107.   s[i] := 0X;
  108.   Reverse(s)
  109. END IntToString;
  110.  
  111.  
  112. PROCEDURE isdigit(c: CHAR): BOOLEAN;
  113.   RETURN ("0" <= c) & (c <= "9")
  114. END isdigit;
  115.  
  116.  
  117. PROCEDURE CharsToInt*(s: CHARS; VAR err: BOOLEAN): INTEGER;
  118. VAR n, i, res, len: INTEGER; c: CHAR;
  119. BEGIN
  120.   res := 0;
  121.   len := s.last - s.first + 1;
  122.   err := len <= 0;
  123.   FOR i := 0 TO s.last - s.first DO
  124.     c := GetChar(s, i);
  125.     IF isdigit(c) THEN
  126.       n := ORD(c) - ORD("0");
  127.       res := res * 10 + n
  128.     ELSE
  129.       err := TRUE
  130.     END
  131.   END
  132.   RETURN res
  133. END CharsToInt;
  134.  
  135.  
  136. PROCEDURE Append*(VAR str1: STRING; str2: STRING);
  137. VAR
  138.   len1, len2 : INTEGER;
  139.   i, j       : INTEGER;
  140. BEGIN
  141.   len1 := LENGTH(str1);
  142.   len2 := LENGTH(str2);
  143.   ASSERT(len1 + len2 < LEN(str1));
  144.   j := len1;
  145.   FOR i := 0 TO len2 - 1 DO
  146.     str1[j] := str2[i];
  147.     INC(j)
  148.   END;
  149.   str1[j] := 0X
  150. END Append;
  151.  
  152.  
  153. PROCEDURE GetPath*(VAR S: STRING);
  154. VAR i, j: INTEGER;
  155. BEGIN
  156.   j := 0;
  157.   i := LENGTH(S) - 1;
  158.   WHILE i >= 0 DO
  159.     IF S[i] = "/" THEN
  160.       j := i;
  161.       i := 0
  162.     END;
  163.     DEC(i)
  164.   END;
  165.   S[j] := 0X
  166. END GetPath;
  167.  
  168.  
  169. PROCEDURE PutChar*(chars: CHARS; i: INTEGER; c: CHAR);
  170. BEGIN
  171.   ASSERT(chars.first + i <= chars.last);
  172.   sys.PUT(chars.first + i, c)
  173. END PutChar;
  174.  
  175.  
  176. PROCEDURE StrToChars*(str: ARRAY OF CHAR; VAR chars: CHARS);
  177. BEGIN
  178.   ASSERT(str # "");
  179.   chars.first := sys.ADR(str[0]);
  180.   chars.last  := sys.ADR(str[LENGTH(str) - 1])
  181. END StrToChars;
  182.  
  183.  
  184. PROCEDURE PtrToString*(ptr: INTEGER; VAR S: STRING);
  185. VAR i: INTEGER; c: CHAR;
  186. BEGIN
  187.   i := 0;
  188.   REPEAT
  189.     sys.GET(ptr, c);
  190.     S[i] := c;
  191.     INC(i);
  192.     INC(ptr)
  193.   UNTIL (c = 0X) OR (i = LEN(S));
  194.   S[i - 1] := 0X
  195. END PtrToString;
  196.  
  197.  
  198. PROCEDURE CharsEq*(chars1, chars2: CHARS): BOOLEAN;
  199. VAR
  200.   pos, len2  : INTEGER;
  201.   c1, c2     : CHAR;
  202.   Result     : BOOLEAN;
  203.  
  204.   PROCEDURE CAP(VAR c: CHAR);
  205.   BEGIN
  206.     IF ~CS & ("a" <= c) & (c <= "z") THEN
  207.       c := CHR(ORD(c) - 32)
  208.     END
  209.   END CAP;
  210.  
  211. BEGIN
  212.   pos  := chars1.last - chars1.first;
  213.   len2 := chars2.last - chars2.first;
  214.   IF pos = len2 THEN
  215.     REPEAT
  216.       c1 := GetChar(chars1, pos);
  217.       c2 := GetChar(chars2, pos);
  218.       CAP(c1);
  219.       CAP(c2);
  220.       DEC(pos)
  221.     UNTIL (c1 # c2) OR (pos = -1);
  222.     Result := c1 = c2
  223.   ELSE
  224.     Result := FALSE
  225.   END
  226.   RETURN Result
  227. END CharsEq;
  228.  
  229.  
  230. PROCEDURE CharsEqStr*(chars: CHARS; str: STRING): BOOLEAN;
  231. VAR
  232.   chars2: CHARS;
  233. BEGIN
  234.   StrToChars(str, chars2)
  235.   RETURN CharsEq(chars, chars2)
  236. END CharsEqStr;
  237.  
  238.  
  239. PROCEDURE SetCS*(value: BOOLEAN);
  240. BEGIN
  241.   CS := value
  242. END SetCS;
  243.  
  244.  
  245. PROCEDURE Utf8Length*(chars: CHARS): INTEGER;
  246.   RETURN countUTF8Z(chars.first, chars.last - chars.first + 1)
  247. END Utf8Length;
  248.  
  249.  
  250. PROCEDURE Replace*(VAR chars: CHARS; str1, str2: ARRAY OF CHAR);
  251. VAR
  252.   temp: CHARS;
  253.   s   : CHARS;
  254.   len1: INTEGER;
  255.   len2: INTEGER;
  256.   diff: INTEGER;
  257.  
  258.   PROCEDURE Put(first, last, len1, len2, diff: INTEGER; str2: ARRAY OF CHAR);
  259.   VAR i: INTEGER; c: CHAR;
  260.   BEGIN
  261.     sys.MOVE(sys.ADR(str2[0]), first, len2);
  262.     FOR i := first + len1 TO last DO
  263.       sys.GET(i, c);
  264.       sys.PUT(i - diff, c);
  265.     END
  266.   END Put;
  267.  
  268. BEGIN
  269.   len1 := LENGTH(str1);
  270.   len2 := LENGTH(str2);
  271.   diff := len1 - len2;
  272.   ASSERT(diff >= 0);
  273.   ASSERT(len1 > 0);
  274.   StrToChars(str1, s);
  275.   temp := chars;
  276.   temp.last := temp.first + len1 - 1;
  277.   WHILE temp.last <= chars.last DO
  278.     IF CharsEq(temp, s) THEN
  279.       Put(temp.first, chars.last, len1, len2, diff, str2);
  280.       chars.last := chars.last - diff;
  281.       temp.first := temp.first + len2;
  282.       temp.last  := temp.first + len1 - 1
  283.     ELSE
  284.       INC(temp.first);
  285.       INC(temp.last)
  286.     END
  287.   END
  288. END Replace;
  289.  
  290.  
  291. PROCEDURE EntOct*(VAR chars: CHARS): BOOLEAN;
  292. VAR
  293.   i     : INTEGER;
  294.   c     : CHAR;
  295.   amp   : BOOLEAN;
  296.   oct   : BOOLEAN;
  297.   val   : INTEGER;
  298.   exit  : BOOLEAN;
  299.   str   : STRING;
  300.   str2  : STRING;
  301.   uchar : Encoding.tUtf8;
  302.   res   : BOOLEAN;
  303.  
  304. BEGIN
  305.   i := 0;
  306.   amp := FALSE;
  307.   oct := FALSE;
  308.   res := FALSE;
  309.   WHILE i <= chars.last - chars.first DO
  310.     c := GetChar(chars, i);
  311.     CASE c OF
  312.     |"&":
  313.       amp := TRUE;
  314.       oct := FALSE
  315.     |"#":
  316.       oct := amp;
  317.       amp := FALSE
  318.     |"0".."9":
  319.       IF oct THEN
  320.         val := 0;
  321.         str := "&#";
  322.         str2[1] := 0X;
  323.         exit := FALSE;
  324.         REPEAT
  325.           val := val * 10 + ORD(c) - ORD("0");
  326.           str2[0] := c;
  327.           Append(str, str2);
  328.           INC(i);
  329.           IF i <= chars.last - chars.first THEN
  330.             c := GetChar(chars, i)
  331.           ELSE
  332.             exit := TRUE
  333.           END
  334.         UNTIL ~isdigit(c) OR exit;
  335.         IF c = ";" THEN
  336.           str2[0] := c;
  337.           Append(str, str2);
  338.           Encoding.utf8(val, uchar);
  339.           Replace(chars, str, uchar);
  340.           res := TRUE;
  341.           i := chars.last - chars.first
  342.         ELSE
  343.           IF ~exit THEN
  344.             DEC(i);
  345.             amp := FALSE;
  346.             oct := FALSE
  347.           END
  348.         END
  349.       ELSE
  350.         amp := FALSE
  351.       END
  352.     ELSE
  353.       amp := FALSE;
  354.       oct := FALSE
  355.     END;
  356.     INC(i)
  357.   END
  358.   RETURN res
  359. END EntOct;
  360.  
  361.  
  362. PROCEDURE UCase*(VAR s: STRING);
  363. VAR i, n: INTEGER; c: CHAR;
  364. BEGIN
  365.   n := LENGTH(s) - 1;
  366.   FOR i := 0 TO n DO
  367.     c := s[i];
  368.     IF ("a" <= c) & (c <= "z") OR (0A0X <= c) & (c <= 0AFX) THEN
  369.       c := CHR(ORD(c) - 32)
  370.     ELSIF (0E0X <= c) & (c <= 0EFX) THEN
  371.       c := CHR(ORD(c) - 50H)
  372.     ELSIF (c = 0F1X) OR (c = 0F3X) OR (c = 0F5X) OR (c = 0F7X) THEN
  373.       c := CHR(ORD(c) - 1)
  374.     END;
  375.     s[i] := c
  376.   END
  377. END UCase;
  378.  
  379.  
  380. PROCEDURE Base64* (VAR chars: CHARS);
  381. BEGIN
  382.         chars.last := chars.first + base64_decode(chars.first, chars.first, chars.last - chars.first + 1) - 1
  383. END Base64;
  384.  
  385.  
  386. BEGIN
  387.   CS := TRUE
  388. END Strings.
  389.