! ---------------------------------------------------------------------------- !
!   StringMaker.h by Roger Firth ([email protected])
!
!       1.0 Jul 2002
!           Original version.
!
! ---------------------------------------------------------------------------- !
!   Installation: add the line:
!
!       Include "StringMaker";
!
!   near the start of your game file.
!
! ---------------------------------------------------------------------------- !
!
!   The routine StringToChars(s,a) unpacks a string S into an array of
!   characters A, in which the first word (A-->0) holds the length of the
!   string, and the remaining bytes (A->2, A->3, ...) hold the characters.
!   You can also create such an array using output stream 3 (see section 42
!   of the DM4):
!
!       @output_stream 3 A;
!       print ... ;
!       @output_stream -3;
!
!   The routine CharsToString(a,s) reverses the process. Here A is an array
!   of characters in the format created by StringToChars(), and S is an
!   array of words into which the packed string is written. Note that this
!   array will be in the Z-machine's low memory (only the compiler can write
!   into the high memory region) and so therefore you cannot use
!   print (string) S to output the string that you have made; instead, use
!   print (address) S to print it.
!
!   For example:
!
!       Array AAA --> 100;  ! reserve 100 words for a character array
!       Array SSS --> 100;  ! and the same for the string.
!
!       StringToChars("This is^a short string", AAA);
!       AAA->13 = 'm';      ! overwrite "short" with "small"
!       AAA->14 = 'a';
!       AAA->15 = AAA->16 = 'l';
!       AAA->24 = '.';      ! add a full stop on the end
!       AAA-->0 = AAA-->0 + 1;
!       CharsToString(AAA, SSS);
!       print (address) SSS, "^";
!
!   produces:
!
!       This is
!       a small string.

System_file;

Array alphaTable ->
   'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z'
   'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z'
   ' ' '^' '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' '.' ',' '!' '?' '_' '#' 039 '"' '/' '\' '-' ':' '(' ')';

Global sCount = 0;                              ! current word in string
Global zCount = 0;                              ! current Z-char within word

[ StringToChars s a;        ! unpack a string into an array of ZSCII characters
   (s).print_to_array(a);
   return a-->0;
];

[ CharsToString a s         ! pack ZSCII characters into a Z-character string
   t i;
   t = $0034-->0; if (t == 0) t = alphaTable;  ! address of alphabet table
   sCount = zCount = 0;
   for (i=0 : i<(a-->0) : i++)
       ZSCIItoZchar(a->(i+2), s, t);           ! convert all ZSCII to Z-chars
   switch (zCount) {                           ! fix up last word of string
       1:  s-->sCount = s-->sCount | $80A5;    ! - two pad characters
       2:  s-->sCount = s-->sCount | $8005;    ! - one pad character
       0:  sCount--;
           s-->sCount = s-->sCount | $8000;    ! - no pad characters
       default: "StringMaker BUG1";
   }
   return sCount;
];

[ ZSCIItoZchar c s t        ! convert 10-bit ZSCII char to 5-bit Z-character(s)
   i;
   if (c == 32) {                              ! space
       Zchar(0, s); return;
   }
   if (c == 13) {                              ! newline
       Zchar(5, s); Zchar(7, s); return;
   }
   for (i=0 : i<78 : i++) if (c == t->i)
       switch (i/26) {                         ! found in alpha table
           0:  Zchar(6+i, s);                  ! - A0 (lower case)
               return;
           1:  Zchar(4, s); Zchar(6+i%26, s);  ! - A1 (upper case)
               return;
           2:  Zchar(5, s); Zchar(6+i%26, s);  ! - A2 (punctuation)
               return;
           default: "StringMaker BUG2";
       }
   Zchar(5, s); Zchar(6, s);                   ! not found in alpha table
   Zchar(c/$20, s); Zchar(c&$1F, s);
];

[ Zchar c s;                ! pack a Z-character into the string being built
   switch (zCount++) {
       0:  s-->sCount = c * $400;
       1:  s-->sCount = s-->sCount + c * $20;
       2:  s-->sCount = s-->sCount + c; sCount++; zCount = 0;
       default: "StringMaker BUG3";
   }
];

! ---------------------------------------------------------------------------- !