1 /*
2   Message
3 */
4 
5 #include "message.h"
6 
7 #include "config.h"
8 #include "head.h"
9 #include "mem.h"
10 #include "os.h"
11 #include "print.h"
12 
13 /*
14 **      Coded Message Routine Global Variables
15 */
16 
17 #if EARLY
18 /* Bind at runtime */
19 static char *table;
20 static void (*letter) (char);
21 static word(*find_mode) (char);
22 #else
23 /* Only one option, so do it at link time */
24 #define table          table_2
25 #define letter         (letter_v3)
26 #define find_mode      (find_mode_v3)
27 #endif
28 
29 static int print_mode;
30 static int single_mode;
31 static word word_bank;
32 
33 /*
34 **      Character Table
35 */
36 
37 #if EARLY
38 static char table_1[] = {
39   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
40   'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
41   'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
42   'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
43   'W', 'X', 'Y', 'Z', ' ', '0', '1', '2', '3', '4', '5', '6',
44   '7', '8', '9', '.', ',', '!', '?', '_', '#', '\'', '\"',
45   '/', '\\', '<', '-', ':', '(', ')', '\0', '\0'
46 };
47 #endif
48 
49 static char table_2[] = {
50   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
51   'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
52   'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
53   'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
54   'W', 'X', 'Y', 'Z', ' ', ' ', '0', '1', '2', '3', '4', '5',
55   '6', '7', '8', '9', '.', ',', '!', '?', '_', '#', '\'',
56   '\"', '/', '\\', '-', ':', '(', ')', '\0', '\0'
57 };
58 
59 #if EARLY
letter_v1(char ch)60 static void letter_v1(char ch)
61 {
62   extern void (*PrintChar) (word);
63 
64   switch(ch)
65   {
66     case 0:
67       (*PrintChar) ((word) ' ');
68       single_mode = print_mode;
69       break;
70     case 1:
71       new_line();
72       single_mode = print_mode;
73       break;
74     case 2:
75       single_mode = (single_mode + 1) % 3;
76       break;
77     case 3:
78       single_mode = (single_mode + 2) % 3;
79       break;
80     case 4:
81       print_mode  = (single_mode + 1) % 3;
82       single_mode = print_mode;
83       break;
84     case 5:
85       print_mode  = (single_mode + 2) % 3;
86       single_mode = print_mode;
87       break;
88     case 6:
89       if(single_mode == 2)
90       {
91         single_mode = 3;
92         break;
93       }
94       /* else fall through */
95     default:
96       (*PrintChar) ((word) table[(single_mode * 26) + ch - 6]);
97       single_mode = print_mode;
98       break;
99   }
100 }
101 #endif
102 
103 #if EARLY
letter_v2(char ch)104 static void letter_v2(char ch)
105 {
106   extern void (*PrintChar) (word);
107 
108   switch(ch)
109   {
110     case 0:
111       (*PrintChar) ((word) ' ');
112       single_mode = print_mode;
113       break;
114     case 1:
115       single_mode |= 0x80;
116       word_bank = (ch - 1) << 6;
117       break;
118     case 2:
119       single_mode = (single_mode + 1) % 3;
120       break;
121     case 3:
122       single_mode = (single_mode + 2) % 3;
123       break;
124     case 4:
125       print_mode  = (single_mode + 1) % 3;
126       single_mode = print_mode;
127       break;
128     case 5:
129       print_mode  = (single_mode + 2) % 3;
130       single_mode = print_mode;
131       break;
132     case 6:
133     case 7:
134       if(single_mode == 2)
135       {
136         if(ch == 6)
137         {
138           single_mode = 3;
139         }
140         else
141         {
142           new_line();
143           single_mode = print_mode;
144         }
145         break;
146       }
147       /* else fall through */
148     default:
149       (*PrintChar) ((word) table[(single_mode * 26) + ch - 6]);
150       single_mode = print_mode;
151       break;
152   }
153 }
154 #endif
155 
letter_v3(char ch)156 static void letter_v3(char ch)
157 {
158   extern void (*PrintChar) (word);
159 
160   switch(ch)
161   {
162     case 0:
163       (*PrintChar) ((word) ' ');
164       single_mode = print_mode;
165       break;
166     case 1:
167     case 2:
168     case 3:
169       single_mode |= 0x80;
170       word_bank = (ch - 1) << 6;
171       break;
172     case 4:
173     case 5:
174       if(single_mode == 0)
175       {
176         single_mode = ch - 3;
177       }
178       else
179       {
180         if(single_mode != ch - 3)
181           single_mode = 0;
182         print_mode = single_mode;
183       }
184       break;
185     case 6:
186     case 7:
187       if(single_mode == 2)
188       {
189         if(ch == 6)
190         {
191           single_mode = 3;
192         }
193         else
194         {
195           new_line();
196           single_mode = print_mode;
197         }
198         break;
199       }
200       /* else fall through */
201     default:
202       (*PrintChar) ((word) table[(single_mode * 26) + ch - 6]);
203       single_mode = print_mode;
204       break;
205   }
206 }
207 
208 #if EARLY
find_mode_v1(char ch)209 static word find_mode_v1(char ch)
210 {
211   if(ch == 0)
212   {
213     return 3 + 3;
214   }
215   if('a' <= ch && ch <= 'z')
216   {
217     return 0;
218   }
219   if('A' <= ch && ch <= 'Z')
220   {
221     return 1 + 1;
222   }
223   return 2 + 1;
224 }
225 #endif
226 
find_mode_v3(char ch)227 static word find_mode_v3(char ch)
228 {
229   if(ch == 0)
230   {
231     return 3 + 3;
232   }
233   if('a' <= ch && ch <= 'z')
234   {
235     return 0;
236   }
237   if('A' <= ch && ch <= 'Z')
238   {
239     return 1 + 3;
240   }
241   return 2 + 3;
242 }
243 
convert(char ch)244 static word convert(char ch)
245 {
246   int i = os_strpos(table, ch);
247 
248   if(i >= 0)
249   {
250     word code = i + 6;
251     while(code >= 0x20)
252       code -= 0x1A;
253     return code;
254   }
255   else
256   {
257     return 0;
258   }
259 }
260 
decode_char(char ch)261 static void decode_char(char ch)
262 {
263   extern void (*PrintChar) (word);
264   if(single_mode & 0x80)
265   {
266     int save_mode = print_mode;
267     long_word a   = hd_common() + (word_bank + 2L * ch);
268     word page     = rd_byte_addr(a);
269     word offset   = rd_byte_addr(a+1) << 1;
270     print_coded(&page, &offset);
271     single_mode = print_mode = save_mode;
272   }
273   else if(single_mode & 0x40)
274   {
275     (*PrintChar) (ch + ((single_mode & 0x03) << 5));
276     single_mode = print_mode;
277   }
278   else if(single_mode < 3)
279   {
280     (*letter) (ch);
281   }
282   else if(single_mode == 3)
283   {
284     single_mode = 0x40 + ch;
285   }
286 }
287 
decode(word data)288 static void decode(word data)
289 {
290   decode_char((data >> (5*2)) & 0x1F);
291   decode_char((data >> (5*1)) & 0x1F);
292   decode_char((data >> (5*0)) & 0x1F);
293 }
294 
295 /*
296 **      Decode Routines
297 */
298 
init_message(void)299 void init_message(void)
300 {
301 #if EARLY
302   switch(hd_version())
303   {
304     case VERSION_1:
305       table     = table_1;
306       letter    = letter_v1;
307       find_mode = find_mode_v1;
308       break;
309     case VERSION_2:
310       table     = table_2;
311       letter    = letter_v2;
312       find_mode = find_mode_v1;
313       break;
314     default:
315       table     = table_2;
316       letter    = letter_v3;
317       find_mode = find_mode_v3;
318       break;
319   }
320 #endif
321 }
322 
print_coded(word * page,word * offset)323 void print_coded(word *page, word *offset)
324 {
325   word data;
326   word p = *page;
327   word o = *offset;
328 
329   /*
330     Print mode
331     0    : Lower Case Letter
332     1    : Upper Case Letter
333     2    : Number or Symbol
334     3    : ASCII Letter - first byte
335     0x40 : ASCII Letter - second byte
336     0x80 : Common Word
337   */
338 
339   print_mode  = 0;
340   single_mode = 0;
341 
342   do
343   {
344     data = rd_word_seg(p, o);
345     o += 2;
346     if(o >= BLOCK_SIZE)
347     {
348       o -= BLOCK_SIZE;
349       p += 1;
350     }
351     decode(data);
352   } while((data & 0x8000) == 0);
353   *page   = p;
354   *offset = o;
355 }
356 
357 /*
358 **      Encode Routines
359 */
360 
encode(byte * the_word,word coded[])361 void encode(byte *the_word, word coded[])
362 {
363   int plus = hd_plus();
364   int cpw = plus ? PLUS_CHARS_PER_WORD : STD_CHARS_PER_WORD;
365   int esz = plus ? PLUS_ENCODED_SIZE : STD_ENCODED_SIZE;
366   word data[max(STD_CHARS_PER_WORD, PLUS_CHARS_PER_WORD)];
367   int count = 0;
368   while(count < cpw)
369   {
370     byte ch = *the_word++;
371     if(ch == 0)
372     {
373       /* Finished, so fill with blanks */
374       while(count < cpw)
375         data[count++] = 5;
376     }
377     else
378     {
379       /* Get Character Print-Mode */
380       word mode = (*find_mode) ((char) ch);
381       if(mode != 0) data[count++] = mode;
382       /* Get offset of character in Table[] */
383       if(count < cpw)
384       {
385         word offset = convert((char) ch);
386         if(offset == 0)
387         {
388           /* Character not in Table[], so use ASCII */
389           data[count++] = 6;
390           if(count < cpw) data[count++] = ch >> 5;
391           if(count < cpw) data[count++] = ch & 0x1F;
392         }
393         else
394         {
395           data[count++] = offset;
396         }
397       }
398     }
399   }
400   /* Encrypt */
401   for(count = 0; count < esz; count++)
402     coded[count] = (data[count * 3 + 0] << 10)
403                  | (data[count * 3 + 1] << 5)
404                  | (data[count * 3 + 2] << 0);
405   coded[esz - 1] |= 0x8000;
406 }
407