1 (* DynamicStrings.mod provides a dynamic string type and procedures.
3 Copyright (C) 2001-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. *)
27 IMPLEMENTATION MODULE DynamicStrings ;
29 FROM libc IMPORT strlen, strncpy, write, exit, snprintf ;
30 FROM StrLib IMPORT StrLen ;
31 FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
32 FROM Assertion IMPORT Assert ;
33 FROM SYSTEM IMPORT ADR ;
34 FROM ASCII IMPORT nul, tab, lf ;
35 FROM M2RTS IMPORT Halt ;
39 PoisonOn = FALSE ; (* to enable debugging of this module, turn on PoisonOn and DebugOn. *)
41 CheckOn = FALSE ; (* to enable debugging of users of this module turn on *)
42 TraceOn = FALSE ; (* CheckOn and TraceOn. Enabling both of these is very expensive. *)
46 buf : ARRAY [0..MaxBuf-1] OF CHAR ;
51 Descriptor = POINTER TO descriptor ;
53 String = POINTER TO stringRecord ;
56 next: String ; (* a mechanism for tracking used/lost strings *)
68 desState = (inuse, marked, onlist, poisoned) ;
71 charStarUsed : BOOLEAN ; (* can we garbage collect this? *)
73 charStarSize : CARDINAL ;
74 charStarValid: BOOLEAN ;
76 garbage : String ; (* temporary strings to be destroyed
77 once this string is killed *)
80 frame = POINTER TO frameRec ;
82 alloc, dealloc: String ;
87 Initialized: BOOLEAN ;
89 captured : String ; (* debugging aid. *)
92 (* writeStringDesc write out debugging information about string, s. *)
94 PROCEDURE writeStringDesc (s: String) ;
96 writeCstring (s^.debug.file) ; writeString (':') ;
97 writeCard (s^.debug.line) ; writeString (':') ;
98 writeCstring (s^.debug.proc) ; writeString (' ') ;
101 CASE s^.head^.state OF
103 inuse : writeString ("still in use (") ; writeCard (s^.contents.len) ; writeString (") characters") |
104 marked : writeString ("marked") |
105 onlist : writeString ("on a (lost) garbage list") |
106 poisoned: writeString ("poisoned")
109 writeString ("unknown state")
111 END writeStringDesc ;
118 PROCEDURE writeNspace (n: CARDINAL) ;
131 PROCEDURE DumpStringInfo (s: String; i: CARDINAL) ;
135 writeNspace (i) ; writeStringDesc (s) ; writeLn ;
136 IF s^.head^.garbage # NIL
138 writeNspace (i) ; writeString ('garbage list:') ; writeLn ;
140 s := s^.head^.garbage ;
141 DumpStringInfo (s, i+1) ; writeLn
153 PopAllocationExemption - test to see that all strings are deallocated, except
154 string e since the last push.
155 Post-condition: it pops to the previous allocation/deallocation
158 If halt is true then the application terminates
159 with an exit code of 1.
162 PROCEDURE PopAllocationExemption (halt: BOOLEAN; e: String) : String ;
173 Halt ("mismatched number of PopAllocation's compared to PushAllocation's",
174 __FILE__, __FUNCTION__, __LINE__) ;
175 (* writeString ("mismatched number of PopAllocation's compared to PushAllocation's") *)
177 IF frameHead^.alloc # NIL
180 s := frameHead^.alloc ;
182 IF NOT ((e = s) OR IsOnGarbage (e, s) OR IsOnGarbage (s, e))
186 writeString ("the following strings have been lost") ; writeLn ;
189 DumpStringInfo (s, 0)
198 frameHead := frameHead^.next
202 END PopAllocationExemption ;
206 PopAllocation - test to see that all strings are deallocated since
207 the last push. Then it pops to the previous
208 allocation/deallocation lists.
210 If halt is true then the application terminates
211 with an exit code of 1.
214 PROCEDURE PopAllocation (halt: BOOLEAN) ;
218 IF PopAllocationExemption (halt, NIL) = NIL
226 PushAllocation - pushes the current allocation/deallocation lists.
229 PROCEDURE PushAllocation ;
251 PROCEDURE doDSdbEnter ;
264 PROCEDURE doDSdbExit (s: String) ;
268 s := PopAllocationExemption (TRUE, s)
277 PROCEDURE DSdbEnter ;
286 PROCEDURE DSdbExit (s: String) ;
292 * #undef GM2_DEBUG_DYNAMICSTINGS
293 * #if defined(GM2_DEBUG_DYNAMICSTINGS)
294 * # define DSdbEnter doDSdbEnter
295 * # define DSdbExit doDSdbExit
296 * # define CheckOn TRUE
297 * # define TraceOn TRUE
302 PROCEDURE Capture (s: String) : CARDINAL ;
313 PROCEDURE Min (a, b: CARDINAL) : CARDINAL ;
328 PROCEDURE Max (a, b: CARDINAL) : CARDINAL ;
340 writeString - writes a string to stdout.
343 PROCEDURE writeString (a: ARRAY OF CHAR) ;
347 i := write (1, ADR (a), StrLen (a))
352 writeCstring - writes a C string to stdout.
355 PROCEDURE writeCstring (a: ADDRESS) ;
361 writeString ('(null)')
363 i := write (1, a, strlen (a))
372 PROCEDURE writeCard (c: CARDINAL) ;
379 writeCard (c DIV 10) ;
382 ch := CHR (ORD ('0') + c) ;
383 i := write (1, ADR (ch), 1)
392 PROCEDURE writeLongcard (l: LONGCARD) ;
399 writeLongcard (l DIV 16) ;
400 writeLongcard (l MOD 16)
403 ch := CHR (ORD ('0') + VAL (CARDINAL, l)) ;
404 i := write(1, ADR(ch), 1)
407 ch := CHR (ORD ('a') + VAL(CARDINAL, l) - 10) ;
408 i := write (1, ADR (ch), 1)
414 writeAddress - writes out the address of a with a C style hex prefix.
417 PROCEDURE writeAddress (a: ADDRESS) ;
419 buffer: ARRAY [0..30] OF CHAR ;
421 snprintf (ADR (buffer), SIZE (buffer), "0x%", a) ;
422 writeString (buffer) ;
427 writeLn - writes a newline.
436 i := write (1, ADR (ch), 1)
441 AssignDebug - assigns, file, and, line, information to string, s.
444 PROCEDURE AssignDebug (s: String; file: ARRAY OF CHAR; line: CARDINAL; proc: ARRAY OF CHAR) : String ;
451 ALLOCATE (debug.file, StrLen (file) + 1) ;
452 IF strncpy(debug.file, f, StrLen(file)+1)=NIL
456 ALLOCATE (debug.proc, StrLen (proc) + 1) ;
457 IF strncpy (debug.proc, p, StrLen (proc) + 1) = NIL
466 CopyOut - copies string, s, to a.
469 PROCEDURE CopyOut (VAR a: ARRAY OF CHAR; s: String) ;
473 l := Min (HIGH (a) + 1, Length (s)) ;
476 a[i] := char (s, i) ;
487 IsOn - returns TRUE if, s, is on one of the debug lists.
490 PROCEDURE IsOn (list, s: String) : BOOLEAN ;
492 WHILE (list # s) AND (list # NIL) DO
493 list := list^.debug.next
500 AddTo - adds string, s, to, list.
503 PROCEDURE AddTo (VAR list: String; s: String) ;
510 s^.debug.next := list ;
517 SubFrom - removes string, s, from, list.
520 PROCEDURE SubFrom (VAR list: String; s: String) ;
526 list := s^.debug.next ;
529 WHILE (p^.debug.next # NIL) AND (p^.debug.next # s) DO
534 p^.debug.next := s^.debug.next
536 (* not found, quit *)
545 AddAllocated - adds string, s, to the head of the allocated list.
548 PROCEDURE AddAllocated (s: String) ;
551 AddTo (frameHead^.alloc, s)
556 AddDeallocated - adds string, s, to the head of the deallocated list.
559 PROCEDURE AddDeallocated (s: String) ;
562 AddTo (frameHead^.dealloc, s)
567 IsOnAllocated - returns TRUE if the string, s, has ever been allocated.
570 PROCEDURE IsOnAllocated (s: String) : BOOLEAN ;
577 IF IsOn (f^.alloc, s)
589 IsOnDeallocated - returns TRUE if the string, s, has ever been deallocated.
592 PROCEDURE IsOnDeallocated (s: String) : BOOLEAN ;
599 IF IsOn (f^.dealloc, s)
607 END IsOnDeallocated ;
611 SubAllocated - removes string, s, from the list of allocated strings.
614 PROCEDURE SubAllocated (s: String) ;
621 IF IsOn (f^.alloc, s)
623 SubFrom (f^.alloc, s) ;
633 SubDeallocated - removes string, s, from the list of deallocated strings.
636 PROCEDURE SubDeallocated (s: String) ;
643 IF IsOn (f^.dealloc, s)
645 SubFrom (f^.dealloc, s) ;
655 SubDebugInfo - removes string, s, from the list of allocated strings.
658 PROCEDURE SubDebugInfo (s: String) ;
660 IF IsOnDeallocated (s)
662 Assert (NOT DebugOn) ;
663 (* string has already been deallocated *)
672 (* string has not been allocated *)
678 AddDebugInfo - adds string, s, to the list of allocated strings.
681 PROCEDURE AddDebugInfo (s: String) ;
697 ConcatContents - add the contents of string, a, where, h, is the
698 total length of, a. The offset is in, o.
701 PROCEDURE ConcatContents (VAR c: Contents; a: ARRAY OF CHAR; h, o: CARDINAL) ;
706 WHILE (o < h) AND (i < MaxBuf) DO
718 contents.next := NIL ;
719 ConcatContents (contents, a, h, o)
721 AddDebugInfo (c.next) ;
722 c.next := AssignDebug (c.next, __FILE__, __LINE__, __FUNCTION__)
730 InitString - creates and returns a String type object.
731 Initial contents are, a.
734 PROCEDURE InitString (a: ARRAY OF CHAR) : String ;
744 ConcatContents (contents, a, StrLen (a), 0) ;
747 charStarUsed := FALSE ;
750 charStarValid := FALSE ;
758 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
765 DeallocateCharStar - deallocates any charStar.
768 PROCEDURE DeallocateCharStar (s: String) ;
770 IF (s # NIL) AND (s^.head # NIL)
773 IF charStarUsed AND (charStar # NIL)
775 DEALLOCATE (charStar, charStarSize)
777 charStarUsed := FALSE ;
780 charStarValid := FALSE
783 END DeallocateCharStar ;
787 CheckPoisoned - checks for a poisoned string, s.
790 PROCEDURE CheckPoisoned (s: String) : String ;
792 IF PoisonOn AND (s # NIL) AND (s^.head # NIL) AND (s^.head^.state = poisoned)
801 KillString - frees String, s, and its contents.
805 PROCEDURE KillString (s: String) : String ;
811 s := CheckPoisoned (s)
820 ELSIF IsOnDeallocated (s)
830 garbage := KillString (garbage) ;
833 DeallocateCharStar (s)
842 t := KillString (s^.contents.next) ;
854 Fin - finishes with a string, it calls KillString with, s.
855 The purpose of the procedure is to provide a short cut
856 to calling KillString and then testing the return result.
859 PROCEDURE Fin (s: String) ;
861 IF KillString (s) # NIL
869 MarkInvalid - marks the char * version of String, s, as invalid.
872 PROCEDURE MarkInvalid (s: String) ;
876 s := CheckPoisoned (s)
880 s^.head^.charStarValid := FALSE
886 ConcatContentsAddress - concatenate the string, a, where, h, is the
890 PROCEDURE ConcatContentsAddress (VAR c: Contents; a: ADDRESS; h: CARDINAL) ;
892 p : POINTER TO CHAR ;
898 WHILE (j < h) AND (i < MaxBuf) DO
911 contents.next := NIL ;
912 ConcatContentsAddress (contents, p, h - j)
914 AddDebugInfo (c.next) ;
917 c.next := AssignDebug (c.next, __FILE__, __LINE__, __FUNCTION__)
923 END ConcatContentsAddress ;
927 InitStringCharStar - initializes and returns a String to contain the C string.
930 PROCEDURE InitStringCharStar (a: ADDRESS) : String ;
942 ConcatContentsAddress (contents, a, strlen (a))
946 charStarUsed := FALSE ;
949 charStarValid := FALSE ;
957 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
960 END InitStringCharStar ;
964 InitStringChar - initializes and returns a String to contain the single character, ch.
967 PROCEDURE InitStringChar (ch: CHAR) : String ;
969 a: ARRAY [0..1] OF CHAR ;
974 s := InitString (a) ;
977 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
984 Mark - marks String, s, ready for garbage collection.
987 PROCEDURE Mark (s: String) : String ;
991 s := CheckPoisoned (s)
993 IF (s # NIL) AND (s^.head^.state = inuse)
995 s^.head^.state := marked
1002 AddToGarbage - adds String, b, onto the garbage list of, a. Providing
1003 the state of b is marked. The state is then altered to
1004 onlist. String, a, is returned.
1007 PROCEDURE AddToGarbage (a, b: String) : String ;
1013 a := CheckPoisoned (a) ;
1014 b := CheckPoisoned (b)
1017 IF (a#NIL) AND (a#b) AND (a^.head^.state=marked)
1019 writeString('warning trying to add to a marked string') ; writeLn
1022 IF (a # b) AND (a # NIL) AND (b # NIL) AND (b^.head^.state = marked) AND (a^.head^.state = inuse)
1025 WHILE c^.head^.garbage # NIL DO
1026 c := c^.head^.garbage
1028 c^.head^.garbage := b ;
1029 b^.head^.state := onlist ;
1040 IsOnGarbage - returns TRUE if, s, is on string, e, garbage list.
1043 PROCEDURE IsOnGarbage (e, s: String) : BOOLEAN ;
1045 IF (e # NIL) AND (s # NIL)
1047 WHILE e^.head^.garbage # NIL DO
1048 IF e^.head^.garbage = s
1052 e := e^.head^.garbage
1061 Length - returns the length of the String, s.
1064 PROCEDURE Length (s: String) : CARDINAL ;
1070 RETURN s^.contents.len + Length (s^.contents.next)
1076 ConCat - returns String, a, after the contents of, b, have been appended.
1079 PROCEDURE ConCat (a, b: String) : String ;
1085 a := CheckPoisoned (a) ;
1086 b := CheckPoisoned (b)
1090 RETURN ConCat (a, Mark (Dup (b)))
1093 a := AddToGarbage (a, b) ;
1097 WHILE (t^.contents.len = MaxBuf) AND (t^.contents.next # NIL) DO
1098 t := t^.contents.next
1100 ConcatContents (t^.contents, b^.contents.buf, b^.contents.len, 0) ;
1101 b := b^.contents.next
1104 IF (a = NIL) AND (b # NIL)
1113 ConCatChar - returns String, a, after character, ch, has been appended.
1116 PROCEDURE ConCatChar (a: String; ch: CHAR) : String ;
1118 b: ARRAY [0..1] OF CHAR ;
1123 a := CheckPoisoned (a)
1129 WHILE (t^.contents.len = MaxBuf) AND (t^.contents.next # NIL) DO
1130 t := t^.contents.next
1132 ConcatContents (t^.contents, b, 1, 0) ;
1138 ReplaceChar - returns string s after it has changed all occurances of from to to.
1141 PROCEDURE ReplaceChar (s: String; from, to: CHAR) : String ;
1149 WHILE i < t^.contents.len DO
1150 IF t^.contents.buf[i] = from
1152 t^.contents.buf[i] := to
1156 t := t^.contents.next
1163 Assign - assigns the contents of, b, into, a.
1164 String, a, is returned.
1167 PROCEDURE Assign (a, b: String) : String ;
1171 a := CheckPoisoned (a) ;
1172 b := CheckPoisoned (b)
1174 IF (a # NIL) AND (b # NIL)
1177 contents.next := KillString (contents.next) ;
1181 RETURN ConCat (a, b)
1186 Dup - duplicate a String, s, returning the copy of s.
1189 PROCEDURE Dup (s: String) : String ;
1193 s := CheckPoisoned (s)
1195 s := Assign (InitString (''), s) ;
1198 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
1205 Add - returns a new String which contains the contents of a and b.
1208 PROCEDURE Add (a, b: String) : String ;
1212 a := CheckPoisoned (a) ;
1213 b := CheckPoisoned (b)
1215 a := ConCat (ConCat (InitString (''), a), b) ;
1218 a := AssignDebug (a, __FILE__, __LINE__, __FUNCTION__)
1225 Equal - returns TRUE if String, a, and, b, are equal.
1228 PROCEDURE Equal (a, b: String) : BOOLEAN ;
1234 a := CheckPoisoned (a) ;
1235 b := CheckPoisoned (b)
1237 IF Length (a) = Length (b)
1239 WHILE (a # NIL) AND (b # NIL) DO
1241 Assert (a^.contents.len = b^.contents.len) ;
1242 WHILE i<a^.contents.len DO
1243 IF a^.contents.buf[i] # b^.contents.buf[i]
1249 a := a^.contents.next ;
1250 b := b^.contents.next
1260 EqualCharStar - returns TRUE if contents of String, s, is the same as the
1264 PROCEDURE EqualCharStar (s: String; a: ADDRESS) : BOOLEAN ;
1270 s := CheckPoisoned (s)
1272 t := InitStringCharStar (a) ;
1275 t := AssignDebug (t, __FILE__, __LINE__, __FUNCTION__)
1277 t := AddToGarbage (t, s) ;
1280 t := KillString (t) ;
1283 t := KillString (t) ;
1290 EqualArray - returns TRUE if contents of String, s, is the same as the
1294 PROCEDURE EqualArray (s: String; a: ARRAY OF CHAR) : BOOLEAN ;
1300 s := CheckPoisoned (s)
1302 t := InitString (a) ;
1305 t := AssignDebug (t, __FILE__, __LINE__, __FUNCTION__)
1307 t := AddToGarbage (t, s) ;
1310 t := KillString (t) ;
1313 t := KillString (t) ;
1320 Mult - returns a new string which is n concatenations of String, s.
1323 PROCEDURE Mult (s: String; n: CARDINAL) : String ;
1327 s := CheckPoisoned (s)
1331 s := AddToGarbage (InitString (''), s)
1333 s := ConCat (Mult (s, n-1), s)
1337 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
1344 Slice - returns a new string which contains the elements
1347 strings start at element 0
1348 Slice(s, 0, 2) will return elements 0, 1 but not 2
1349 Slice(s, 1, 3) will return elements 1, 2 but not 3
1350 Slice(s, 2, 0) will return elements 2..max
1351 Slice(s, 3, -1) will return elements 3..max-1
1352 Slice(s, 4, -2) will return elements 4..max-2
1355 PROCEDURE Slice (s: String; low, high: INTEGER) : String ;
1358 start, end, o: INTEGER ;
1362 s := CheckPoisoned (s)
1366 low := VAL (INTEGER, Length (s)) + low
1370 high := VAL (INTEGER, Length (s)) + high
1372 (* make sure high is <= Length (s) *)
1373 high := Min (Length (s), high)
1375 d := InitString ('') ;
1376 d := AddToGarbage (d, s) ;
1380 IF low < o + VAL (INTEGER, s^.contents.len)
1386 (* found sliceable unit *)
1393 end := Max (Min (MaxBuf, high - o), 0) ;
1394 WHILE t^.contents.len = MaxBuf DO
1395 IF t^.contents.next = NIL
1397 NEW (t^.contents.next) ;
1398 WITH t^.contents.next^ DO
1402 AddDebugInfo (t^.contents.next) ;
1405 t^.contents.next := AssignDebug (t^.contents.next, __FILE__, __LINE__, __FUNCTION__)
1408 t := t^.contents.next
1410 ConcatContentsAddress (t^.contents,
1411 ADR (s^.contents.buf[start]), end - start) ;
1412 INC (o, s^.contents.len) ;
1413 s := s^.contents.next
1416 INC (o, s^.contents.len) ;
1417 s := s^.contents.next
1422 d := AssignDebug (d, __FILE__, __LINE__, __FUNCTION__)
1429 Index - returns the indice of the first occurance of, ch, in
1430 String, s. -1 is returned if, ch, does not exist.
1431 The search starts at position, o.
1434 PROCEDURE Index (s: String; ch: CHAR; o: CARDINAL) : INTEGER ;
1440 s := CheckPoisoned (s)
1445 IF k + contents.len < o
1447 INC (k, contents.len)
1450 WHILE i < contents.len DO
1451 IF contents.buf[i] = ch
1461 s := s^.contents.next
1468 RIndex - returns the indice of the last occurance of, ch,
1469 in String, s. The search starts at position, o.
1470 -1 is returned if, ch, is not found.
1473 PROCEDURE RIndex (s: String; ch: CHAR; o: CARDINAL) : INTEGER ;
1480 s := CheckPoisoned (s)
1486 IF k + contents.len < o
1488 INC (k, contents.len)
1496 WHILE i < contents.len DO
1497 IF contents.buf[i] = ch
1506 s := s^.contents.next
1513 RemoveComment - assuming that, comment, is a comment delimiter
1514 which indicates anything to its right is a comment
1515 then strip off the comment and also any white space
1516 on the remaining right hand side.
1517 It leaves any white space on the left hand side alone.
1520 PROCEDURE RemoveComment (s: String; comment: CHAR) : String ;
1524 i := Index (s, comment, 0) ;
1527 s := InitString ('')
1530 s := RemoveWhitePostfix (Slice (Mark (s), 0, i))
1534 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
1541 char - returns the character, ch, at position, i, in String, s.
1544 PROCEDURE char (s: String; i: INTEGER) : CHAR ;
1550 s := CheckPoisoned (s)
1554 c := VAL (CARDINAL, VAL (INTEGER, Length (s)) + i)
1558 WHILE (s # NIL) AND (c >= s^.contents.len) DO
1559 DEC (c, s^.contents.len) ;
1560 s := s^.contents.next
1562 IF (s = NIL) OR (c >= s^.contents.len)
1566 RETURN s^.contents.buf[c]
1572 string - returns the C style char * of String, s.
1575 PROCEDURE string (s: String) : ADDRESS ;
1579 p : POINTER TO CHAR ;
1583 s := CheckPoisoned (s)
1589 IF NOT s^.head^.charStarValid
1593 IF NOT (charStarUsed AND (charStarSize > l))
1595 DeallocateCharStar (s) ;
1596 ALLOCATE (charStar, l+1) ;
1597 charStarSize := l+1 ;
1598 charStarUsed := TRUE
1605 WHILE i < a^.contents.len DO
1606 p^ := a^.contents.buf[i] ;
1610 a := a^.contents.next
1613 s^.head^.charStarValid := TRUE
1615 RETURN s^.head^.charStar
1621 IsWhite - returns TRUE if, ch, is a space or a tab.
1624 PROCEDURE IsWhite (ch: CHAR) : BOOLEAN ;
1626 RETURN (ch = ' ') OR (ch = tab)
1631 RemoveWhitePrefix - removes any leading white space from String, s.
1632 A new string is returned.
1635 PROCEDURE RemoveWhitePrefix (s: String) : String ;
1640 WHILE IsWhite (char (s, i)) DO
1643 s := Slice (s, INTEGER (i), 0) ;
1646 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
1649 END RemoveWhitePrefix ;
1653 RemoveWhitePostfix - removes any leading white space from String, s.
1654 A new string is returned.
1657 PROCEDURE RemoveWhitePostfix (s: String) : String ;
1661 i := VAL(INTEGER, Length (s)) - 1 ;
1662 WHILE (i >= 0) AND IsWhite (char (s, i)) DO
1665 s := Slice (s, 0, i+1) ;
1668 s := AssignDebug (s, __FILE__, __LINE__, __FUNCTION__)
1671 END RemoveWhitePostfix ;
1675 ToUpper - returns string, s, after it has had its lower case characters
1676 replaced by upper case characters.
1677 The string, s, is not duplicated.
1680 PROCEDURE ToUpper (s: String) : String ;
1693 WHILE i < contents.len DO
1694 ch := contents.buf[i] ;
1695 IF (ch >= 'a') AND (ch <= 'z')
1697 contents.buf[i] := CHR (ORD (ch) - ORD ('a') + ORD ('A'))
1702 t := t^.contents.next
1710 ToLower - returns string, s, after it has had its upper case characters
1711 replaced by lower case characters.
1712 The string, s, is not duplicated.
1715 PROCEDURE ToLower (s: String) : String ;
1728 WHILE i < contents.len DO
1729 ch := contents.buf[i] ;
1730 IF (ch >= 'A') AND (ch <= 'Z')
1732 contents.buf[i] := CHR (ORD (ch) - ORD ('A') + ORD ('a'))
1737 t := t^.contents.next
1745 InitStringDB - the debug version of InitString.
1748 PROCEDURE InitStringDB (a: ARRAY OF CHAR; file: ARRAY OF CHAR; line: CARDINAL) : String ;
1750 RETURN AssignDebug (InitString (a), file, line, 'InitString')
1755 InitStringCharStarDB - the debug version of InitStringCharStar.
1758 PROCEDURE InitStringCharStarDB (a: ADDRESS; file: ARRAY OF CHAR; line: CARDINAL) : String ;
1760 RETURN AssignDebug (InitStringCharStar (a), file, line, 'InitStringCharStar')
1761 END InitStringCharStarDB ;
1765 InitStringCharDB - the debug version of InitStringChar.
1768 PROCEDURE InitStringCharDB (ch: CHAR; file: ARRAY OF CHAR; line: CARDINAL) : String ;
1770 RETURN AssignDebug (InitStringChar (ch), file, line, 'InitStringChar')
1771 END InitStringCharDB ;
1775 MultDB - the debug version of MultDB.
1778 PROCEDURE MultDB (s: String; n: CARDINAL; file: ARRAY OF CHAR; line: CARDINAL) : String ;
1780 RETURN AssignDebug (Mult (s, n), file, line, 'Mult')
1785 DupDB - the debug version of Dup.
1788 PROCEDURE DupDB (s: String; file: ARRAY OF CHAR; line: CARDINAL) : String ;
1790 RETURN AssignDebug (Dup (s), file, line, 'Dup')
1795 SliceDB - debug version of Slice.
1798 PROCEDURE SliceDB (s: String; low, high: INTEGER;
1799 file: ARRAY OF CHAR; line: CARDINAL) : String ;
1802 s := AssignDebug (Slice (s, low, high), file, line, 'Slice') ;
1812 PROCEDURE DumpState (s: String) ;
1814 CASE s^.head^.state OF
1816 inuse : writeString ("still in use (") ; writeCard (s^.contents.len) ; writeString (") characters") |
1817 marked : writeString ("marked") |
1818 onlist : writeString ("on a garbage list") |
1819 poisoned: writeString ("poisoned")
1822 writeString ("unknown state")
1828 DumpStringSynopsis -
1831 PROCEDURE DumpStringSynopsis (s: String) ;
1833 writeCstring (s^.debug.file) ; writeString (':') ;
1834 writeCard (s^.debug.line) ; writeString (':') ;
1835 writeCstring (s^.debug.proc) ;
1836 writeString (' string ') ;
1840 IF IsOnAllocated (s)
1842 writeString (' globally allocated')
1843 ELSIF IsOnDeallocated (s)
1845 writeString (' globally deallocated')
1847 writeString (' globally unknown')
1850 END DumpStringSynopsis ;
1854 DumpString - displays the contents of string, s.
1857 PROCEDURE DumpString (s: String) ;
1863 DumpStringSynopsis (s) ;
1864 IF (s^.head # NIL) AND (s^.head^.garbage # NIL)
1866 writeString ('display chained strings on the garbage list') ; writeLn ;
1867 t := s^.head^.garbage ;
1869 DumpStringSynopsis (t) ;
1870 t := t^.head^.garbage
1878 Init - initialize the module.
1885 Initialized := TRUE ;
1893 Initialized := FALSE ;