1 /*
2 * text.c
3 *
4 * Text manipulation routines
5 *
6 */
7
8 #include "ztypes.h"
9
10 static int saved_formatting = ON;
11 /* static int line_pos = 0; */
12 /* static int char_count = 0; no longer used --zarf */
13 static int story_buffer = 0;
14 static int story_pos = 0;
15 static int story_count = 0;
16
17 /*
18 * decode_text
19 *
20 * Convert encoded text to ASCII. Text is encoded by squeezing each character
21 * into 5 bits. 3 x 5 bit encoded characters can fit in one word with a spare
22 * bit left over. The spare bit is used to signal to end of a string. The 5 bit
23 * encoded characters can either be actual character codes or prefix codes that
24 * modifier the following code.
25 *
26 */
27
28 #ifdef __STDC__
decode_text(unsigned long * address)29 void decode_text (unsigned long *address)
30 #else
31 void decode_text (address)
32 unsigned long *address;
33 #endif
34 {
35 int i, synonym_flag, synonym = 0, ascii_flag, ascii = 0;
36 int data, code, shift_state, shift_lock;
37 unsigned long addr;
38
39 /* Set state variables */
40
41 shift_state = 0;
42 shift_lock = 0;
43 ascii_flag = 0;
44 synonym_flag = 0;
45
46 do {
47
48 /*
49 * Read one 16 bit word. Each word contains three 5 bit codes. If the
50 * high bit is set then this is the last word in the string.
51 */
52
53 data = read_data_word (address);
54
55 for (i = 10; i >= 0; i -= 5) {
56
57 /* Get code, high bits first */
58
59 code = (data >> i) & 0x1f;
60
61 /* Synonym codes */
62
63 if (synonym_flag) {
64
65 synonym_flag = 0;
66 synonym = (synonym - 1) * 64;
67 addr = (unsigned long) get_word (h_synonyms_offset + synonym + (code * 2)) * 2;
68 decode_text (&addr);
69 shift_state = shift_lock;
70
71 /* ASCII codes */
72
73 } else if (ascii_flag) {
74
75 /*
76 * If this is the first part ASCII code then remember it.
77 * Because the codes are only 5 bits you need two codes to make
78 * one eight bit ASCII character. The first code contains the
79 * top 3 bits. The second code contains the bottom 5 bits.
80 */
81
82 if (ascii_flag++ == 1)
83
84 ascii = code << 5;
85
86 /*
87 * If this is the second part ASCII code then assemble the
88 * character from the two codes and output it.
89 */
90
91 else {
92
93 ascii_flag = 0;
94 write_zchar ((char) (ascii | code));
95
96 }
97
98 /* Character codes */
99
100 } else if (code > 5) {
101
102 code -= 6;
103
104 /*
105 * If this is character 0 in the punctuation set then the next two
106 * codes make an ASCII character.
107 */
108
109 if (shift_state == 2 && code == 0)
110
111 ascii_flag = 1;
112
113 /*
114 * If this is character 1 in the punctuation set then this
115 * is a new line.
116 */
117
118 else if (shift_state == 2 && code == 1 && h_type > V1)
119
120 new_line ();
121
122 /*
123 * This is a normal character so select it from the character
124 * table appropriate for the current shift state.
125 */
126
127 else
128
129 write_zchar (lookup_table[shift_state][code]);
130
131 shift_state = shift_lock;
132
133 /* Special codes 0 to 5 */
134
135 } else {
136
137 /*
138 * Space: 0
139 *
140 * Output a space character.
141 *
142 */
143
144 if (code == 0) {
145
146 write_zchar (' ');
147
148 } else {
149
150 /*
151 * The use of the synonym and shift codes is the only difference between
152 * the different versions.
153 */
154
155 if (h_type < V3) {
156
157 /*
158 * Newline or synonym: 1
159 *
160 * Output a newline character or set synonym flag.
161 *
162 */
163
164 if (code == 1) {
165
166 if (h_type == V1)
167
168 new_line ();
169
170 else {
171
172 synonym_flag = 1;
173 synonym = code;
174
175 }
176
177 /*
178 * Shift keys: 2, 3, 4 or 5
179 *
180 * Shift keys 2 & 3 only shift the next character and can be used regardless of
181 * the state of the shift lock. Shift keys 4 & 5 lock the shift until reset.
182 *
183 * The following code implements the the shift code state transitions:
184 *
185 * +-------------+-------------+-------------+-------------+
186 * | Shift State | Lock State |
187 * +-------------+-------------+-------------+-------------+-------------+
188 * | Code | 2 | 3 | 4 | 5 |
189 * +-------------+-------------+-------------+-------------+-------------+
190 * | lowercase | uppercase | punctuation | uppercase | punctuation |
191 * | uppercase | punctuation | lowercase | punctuation | lowercase |
192 * | punctuation | lowercase | uppercase | lowercase | uppercase |
193 * +-------------+-------------+-------------+-------------+-------------+
194 *
195 */
196
197 } else {
198 if (code < 4)
199 shift_state = (shift_lock + code + 2) % 3;
200 else
201 shift_lock = shift_state = (shift_lock + code) % 3;
202 }
203
204 } else {
205
206 /*
207 * Synonym table: 1, 2 or 3
208 *
209 * Selects which of three synonym tables the synonym
210 * code following in the next code is to use.
211 *
212 */
213
214 if (code < 4) {
215
216 synonym_flag = 1;
217 synonym = code;
218
219 /*
220 * Shift key: 4 or 5
221 *
222 * Selects the shift state for the next character,
223 * either uppercase (4) or punctuation (5). The shift
224 * state automatically gets reset back to lowercase for
225 * V3+ games after the next character is output.
226 *
227 */
228
229 } else {
230
231 shift_state = code - 3;
232 shift_lock = 0;
233
234 }
235 }
236 }
237 }
238 }
239 } while ((data & 0x8000) == 0);
240
241 }/* decode_text */
242
243 /*
244 * encode_text
245 *
246 * Pack a string into up to 9 codes or 3 words.
247 *
248 */
249
250 #ifdef __STDC__
encode_text(int len,const char * s,short * buffer)251 void encode_text (int len, const char *s, short *buffer)
252 #else
253 void encode_text (len, s, buffer)
254 int len;
255 const char *s;
256 short *buffer;
257 #endif
258 {
259 int i, j, prev_table, table, next_table, shift_state, code, codes_count;
260 char codes[9];
261
262 /* Initialise codes count and prev_table number */
263
264 codes_count = 0;
265 prev_table = 0;
266
267 /* Scan do the string one character at a time */
268
269 while (len--) {
270
271 /*
272 * Set the table and code to be the ASCII character inducer, then
273 * look for the character in the three lookup tables. If the
274 * character isn't found then it will be an ASCII character.
275 */
276
277 table = 2;
278 code = 0;
279 for (i = 0; i < 3; i++) {
280 for (j = 0; j < 26; j++) {
281 if (lookup_table[i][j] == *s) {
282 table = i;
283 code = j;
284 }
285 }
286 }
287
288 /*
289 * Type 1 and 2 games differ on how the shift keys are used. Switch
290 * now depending on the game version.
291 */
292
293 if (h_type < V3) {
294
295 /*
296 * If the current table is the same as the previous table then
297 * just store the character code, otherwise switch tables.
298 */
299
300 if (table != prev_table) {
301
302 /* Find the table for the next character */
303
304 next_table = 0;
305 if (len) {
306 next_table = 2;
307 for (i = 0; i < 3; i++) {
308 for (j = 0; j < 26; j++) {
309 if (lookup_table[i][j] == s[1])
310 next_table = i;
311 }
312 }
313 }
314
315 /*
316 * Calculate the shift key. This magic. See the description in
317 * decode_text for more information on version 1 and 2 shift
318 * key changes.
319 */
320
321 shift_state = (table + (prev_table * 2)) % 3;
322
323 /* Only store the shift key if there is a change in table */
324
325 if (shift_state) {
326
327 /*
328 * If the next character as the uses the same table as
329 * this character then change the shift from a single
330 * shift to a shift lock. Also remember the current
331 * table for the next iteration.
332 */
333
334 if (next_table == table) {
335 shift_state += 2;
336 prev_table = table;
337 } else
338 prev_table = 0;
339
340 /* Store the code in the codes buffer */
341
342 if (codes_count < 9)
343 codes[codes_count++] = (char) (shift_state + 1);
344 }
345 }
346 } else {
347
348 /*
349 * For V3 games each uppercase or punctuation table is preceded
350 * by a separate shift key. If this is such a shift key then
351 * put it in the codes buffer.
352 */
353
354 if (table && codes_count < 9)
355 codes[codes_count++] = (char) (table + 3);
356 }
357
358 /* Put the character code in the code buffer */
359
360 if (codes_count < 9)
361 codes[codes_count++] = (char) (code + 6);
362
363 /*
364 * Cannot find character in table so treat it as a literal ASCII
365 * code. The ASCII code inducer (code 0 in table 2) is followed by
366 * the high 3 bits of the ASCII character followed by the low 5
367 * bits to make 8 bits in total.
368 */
369
370 if (table == 2 && code == 0) {
371 if (codes_count < 9)
372 codes[codes_count++] = (char) ((*s >> 5) & 0x07);
373 if (codes_count < 9)
374 codes[codes_count++] = (char) (*s & 0x1f);
375 }
376
377 /* Advance to next character */
378
379 s++;
380
381 }
382
383 /* Pad out codes with shift 5's */
384
385 while (codes_count < 9)
386 codes[codes_count++] = 5;
387
388 /* Pack codes into buffer */
389
390 buffer[0] = ((short) codes[0] << 10) | ((short) codes[1] << 5) | (short) codes[2];
391 buffer[1] = ((short) codes[3] << 10) | ((short) codes[4] << 5) | (short) codes[5];
392 buffer[2] = ((short) codes[6] << 10) | ((short) codes[7] << 5) | (short) codes[8];
393
394 /* Terminate buffer at 6 or 9 codes depending on the version */
395
396 if (h_type < V4)
397 buffer[1] |= 0x8000;
398 else
399 buffer[2] |= 0x8000;
400
401 }/* encode_text */
402
403 /*
404 * write_zchar
405 *
406 * High level Z-code character output routine. Translates Z-code characters to
407 * machine specific character(s) before output. If it cannot translate it then
408 * use the default translation. If the character is still unknown then display
409 * a '?'.
410 *
411 */
412
413 #ifdef __STDC__
write_zchar(int c)414 void write_zchar (int c)
415 #else
416 void write_zchar (c)
417 int c;
418 #endif
419 {
420 char xlat_buffer[MAX_TEXT_SIZE + 1];
421 int i;
422
423 c = (unsigned int) (c & 0xff);
424
425 /* If character is not special character then just write it */
426
427 if (c >= ' ' && c <= '~') {
428
429 write_char (c);
430
431 }
432 else if (c == 13) {
433
434 /* write_char ('\r'); */
435 new_line ();
436
437 }
438 else {
439
440 /* Put default character in translation buffer */
441
442 xlat_buffer[0] = '?';
443 xlat_buffer[1] = '\0';
444
445 /* If translation fails then supply a default */
446
447 if (codes_to_text (c, xlat_buffer)) {
448
449 if (c > 23 && c < 28) {
450 /* Arrow keys - these must the keyboard keys used for input */
451 static char xlat[4] = { '\\', '/', '+', '-' };
452
453 xlat_buffer[0] = xlat[c - 24];
454 xlat_buffer[1] = '\0';
455 }
456 else if (c == 0) {
457 /* Null - print nothing */
458 xlat_buffer[0] = '\0';
459 }
460 else if (c < 32) {
461 /* Some other control character: print an octal escape. */
462 xlat_buffer[0] = '\\';
463 xlat_buffer[1] = '0' + ((c >> 6) & 7);
464 xlat_buffer[2] = '0' + ((c >> 3) & 7);
465 xlat_buffer[3] = '0' + (c & 7);
466 xlat_buffer[4] = '\0';
467 }
468 else if (c > 178 && c < 219) {
469 /* IBM line drawing characters to ASCII characters */
470 if (c == 179)
471 xlat_buffer[0] = '|';
472 else if (c == 186)
473 xlat_buffer[0] = '#';
474 else if (c == 196)
475 xlat_buffer[0] = '-';
476 else if (c == 205)
477 xlat_buffer[0] = '=';
478 else
479 xlat_buffer[0] = '+';
480 xlat_buffer[1] = '\0';
481 }
482 else if (c > 154 && c < 164) {
483 /* German character replacements */
484
485 static char xlat[] = "aeoeueAeOeUess>><<";
486
487 xlat_buffer[0] = xlat[((c - 155) * 2) + 0];
488 xlat_buffer[1] = xlat[((c - 155) * 2) + 1];
489 xlat_buffer[2] = '\0';
490 }
491 }
492
493 /* Substitute translated characters */
494
495 for (i = 0; xlat_buffer[i] != '\0'; i++)
496 write_char ((unsigned char) xlat_buffer[i]);
497
498 }
499
500 }/* write_zchar */
501
502 /*
503 * write_char
504 *
505 * High level character output routine. The write_char routine is slightly
506 * complicated by the fact that the output can be limited by a fixed character
507 * count, as well as, filling up the buffer.
508 *
509 */
510
511 #ifdef __STDC__
write_char(int c)512 void write_char (int c)
513 #else
514 void write_char (c)
515 int c;
516 #endif
517 {
518 char *cp;
519 int right_len;
520
521 /* Only do if text formatting is turned on */
522
523 if (redirect_depth) {
524
525 /* If redirect is on then write the character to the status line for V1 to V3
526 games or into the writeable data area for V4+ games */
527
528 if (h_type < V4)
529 status_line[status_pos++] = (char) c;
530 else {
531 set_byte (story_pos++, c);
532 story_count++;
533 }
534 } else {
535
536 /* No formatting or output redirection, so just output the character */
537
538 if (c == 13)
539 c = '\n';
540
541 script_char (c);
542
543 output_char (c);
544
545 }
546
547 }/* write_char */
548
549 /*
550 * set_video_attribute
551 *
552 * Set a video attribute. Write the video mode, from 0 to 8, incremented.
553 * This is so the output routines don't confuse video attribute 0 as the
554 * end of the string.
555 *
556 */
557
558 #ifdef __STDC__
set_video_attribute(zword_t mode)559 void set_video_attribute (zword_t mode)
560 #else
561 void set_video_attribute (mode)
562 zword_t mode;
563 #endif
564 {
565
566 if ((int) mode <= MAX_ATTRIBUTE)
567 write_char ((char) ++mode);
568
569 }/* set_video_attribute */
570
571 /*
572 * write_string
573 *
574 * Output a string
575 *
576 */
577
578 #ifdef __STDC__
write_string(const char * s)579 void write_string (const char *s)
580 #else
581 void write_string (s)
582 const char *s;
583 #endif
584 {
585
586 while (*s)
587 write_zchar (*s++);
588
589 }/* write_string */
590
591 /*
592 * flush_buffer
593 *
594 * Send output buffer to the screen.
595 *
596 */
597
598 #ifdef __STDC__
flush_buffer(int flag)599 void flush_buffer (int flag)
600 #else
601 void flush_buffer (flag)
602 int flag;
603 #endif
604 {
605
606 /* Terminate the line */
607 /* ain't no bufferin' no more --zarf */
608
609 #if 0
610 line[line_pos] = '\0';
611
612 /* Send the line buffer to the printer */
613
614 script_string (line);
615
616 /* Send the line buffer to the screen */
617
618 output_string (line);
619
620 /* Reset the buffer pointer */
621
622 line_pos = 0;
623 #endif
624
625 }/* flush_buffer */
626
627 /*
628 * set_format_mode
629 *
630 * Set the format mode flag. Formatting disables writing into the output buffer.
631 *
632 */
633
634 #ifdef __STDC__
set_format_mode(zword_t flag)635 void set_format_mode (zword_t flag)
636 #else
637 void set_format_mode (flag)
638 zword_t flag;
639 #endif
640 {
641
642 /* Flush any current output */
643
644 flush_buffer (FALSE);
645
646 /* Set formatting depending on the flag */
647
648 if (flag)
649 formatting = ON;
650 else
651 formatting = OFF;
652
653 }/* set_format_mode */
654
655 /*
656 * set_print_modes
657 *
658 * Set various printing modes. These can be: disabling output, scripting and
659 * redirecting output. Redirection is peculiar. I use it to format the status
660 * line for V1 to V3 games, otherwise it wasn't used. V4 games format the status line
661 * themselves in an internal buffer in the writeable data area. To use the normal
662 * text decoding routines they have to redirect output to the writeable data
663 * area. This is done by passing in a buffer pointer. The first word of the
664 * buffer will receive the number of characters written since the output was
665 * redirected. The remainder of the buffer will contain the redirected text.
666 *
667 */
668
669 typedef struct redirect_stash_struct {
670 zword_t count;
671 zword_t buffer;
672 zword_t pos;
673 } redirect_stash_t;
674
675 #ifdef __STDC__
set_print_modes(zword_t type,zword_t option)676 void set_print_modes (zword_t type, zword_t option)
677 #else
678 void set_print_modes (type, option)
679 zword_t type;
680 zword_t option;
681 #endif
682 {
683 static int redirect_size = 0;
684 static redirect_stash_t *stash = NULL;
685
686 if ((short) type == 1) {
687
688 /* Turn on text output */
689
690 outputting = ON;
691
692 } else if ((short) type == 2) {
693
694 /* Turn on scripting */
695
696 open_script ();
697
698 } else if ((short) type == 3) {
699
700 /* Turn on output redirection */
701
702 if (redirect_depth == 0) {
703 /* Disable text formatting during redirection */
704
705 saved_formatting = formatting;
706 formatting = OFF;
707
708 /* Enable text redirection */
709
710 redirect_depth = 1;
711 }
712 else {
713 if (redirect_size == 0) {
714 redirect_size = 4;
715 stash = (redirect_stash_t *)malloc(
716 redirect_size * sizeof(redirect_stash_t));
717 }
718 if (redirect_depth > redirect_size) {
719 redirect_size *= 2;
720 stash = (redirect_stash_t *)realloc(stash,
721 redirect_size * sizeof(redirect_stash_t));
722 }
723
724 if (h_type < V4) {
725 stash[redirect_depth-1].pos = status_pos;
726 }
727 else {
728 stash[redirect_depth-1].pos = story_pos;
729 stash[redirect_depth-1].buffer = story_buffer;
730 stash[redirect_depth-1].count = story_count;
731 }
732
733 redirect_depth++;
734 }
735
736 /* Set up the redirection pointers */
737
738 if (h_type < V4)
739 status_pos = 0;
740 else {
741 story_count = 0;
742 story_buffer = option;
743 story_pos = option + 2;
744 }
745
746 } else if ((short) type == 4) {
747
748 /* Turn on input recording */
749
750 open_record ();
751
752 } else if ((short) type == -1) {
753
754 /* Turn off text output */
755
756 outputting = OFF;
757
758 } else if ((short) type == -2) {
759
760 /* Turn off scripting */
761
762 close_script ();
763
764 } else if ((short) type == -3) {
765
766 /* Turn off output redirection */
767
768 if (redirect_depth) {
769
770 if (redirect_depth == 1) {
771 /* Restore the format mode and turn off redirection */
772
773 formatting = saved_formatting;
774 redirect_depth = 0;
775
776 /* Terminate the redirection buffer and store the count of
777 character in the buffer into the first word of the buffer */
778
779 if (h_type > V3)
780 set_word (story_buffer, story_count);
781 }
782 else {
783 if (h_type > V3)
784 set_word (story_buffer, story_count);
785
786 redirect_depth--;
787
788 if (h_type < V4) {
789 status_pos = stash[redirect_depth-1].pos;
790 }
791 else {
792 story_pos = stash[redirect_depth-1].pos;
793 story_buffer = stash[redirect_depth-1].buffer;
794 story_count = stash[redirect_depth-1].count;
795 }
796
797 }
798 }
799
800 } else if ((short) type == -4) {
801
802 /* Turn off input recording */
803
804 close_record ();
805
806 }
807
808 }/* set_print_modes */
809
810 /*
811 * print_character
812 *
813 * Write a character.
814 *
815 */
816
817 #ifdef __STDC__
print_character(zword_t c)818 void print_character (zword_t c)
819 #else
820 void print_character (c)
821 zword_t c;
822 #endif
823 {
824
825 write_zchar ((char) c);
826
827 }/* print_character */
828
829 /*
830 * print_number
831 *
832 * Write a signed number.
833 *
834 */
835
836 #ifdef __STDC__
print_number(zword_t num)837 void print_number (zword_t num)
838 #else
839 void print_number (num)
840 zword_t num;
841 #endif
842 {
843 int i, count;
844 char buffer[10];
845
846 i = (short) num;
847 sprintf (buffer, "%d", i);
848 count = strlen (buffer);
849 for (i = 0; i < count; i++)
850 write_char (buffer[i]);
851
852 }/* print_number */
853
854 /*
855 * print_address
856 *
857 * Print using a packed address. Packed addresses are used to save space and
858 * reference addresses outside of the data region.
859 *
860 */
861
862 #ifdef __STDC__
print_address(zword_t packed_address)863 void print_address (zword_t packed_address)
864 #else
865 void print_address (packed_address)
866 zword_t packed_address;
867 #endif
868 {
869 unsigned long address;
870
871 /* Convert packed address to real address */
872
873 address = (unsigned long) packed_address * story_scaler;
874
875 /* Decode and output text at address */
876
877 decode_text (&address);
878
879 }/* print_address */
880
881 /*
882 * print_offset
883 *
884 * Print using a real address. Real addresses are just offsets into the
885 * data region.
886 *
887 */
888
889 #ifdef __STDC__
print_offset(zword_t offset)890 void print_offset (zword_t offset)
891 #else
892 void print_offset (offset)
893 zword_t offset;
894 #endif
895 {
896 unsigned long address;
897
898 address = offset;
899
900 /* Decode and output text at address */
901
902 decode_text (&address);
903
904 }/* print_offset */
905
906 /*
907 * print_object
908 *
909 * Print an object description. Object descriptions are stored as ASCIC
910 * strings at the front of the property list for the object.
911 *
912 */
913
914 #ifdef __STDC__
print_object(zword_t obj)915 void print_object (zword_t obj)
916 #else
917 void print_object (obj)
918 zword_t obj;
919 #endif
920 {
921 zword_t offset;
922 unsigned long address;
923
924 /* Check for NULL object */
925
926 if (obj == 0)
927 return;
928
929 /* Calculate address of property list */
930
931 offset = get_object_address (obj);
932 offset += (h_type < V4) ? O3_PROPERTY_OFFSET : O4_PROPERTY_OFFSET;
933
934 /* Read the property list address and skip the count byte */
935
936 address = (unsigned long) get_word (offset) + 1;
937
938 /* Decode and output text at address */
939
940 decode_text (&address);
941
942 }/* print_object */
943
944 /*
945 * print_literal
946 *
947 * Print the string embedded in the instruction stream at this point. All
948 * strings that do not need to be referenced by address are embedded in the
949 * instruction stream. All strings that can be refered to by address are placed
950 * at the end of the code region and referenced by packed address.
951 *
952 */
953
954 #ifdef __STDC__
print_literal(void)955 void print_literal (void)
956 #else
957 void print_literal ()
958 #endif
959 {
960
961 /* Decode and output text at PC */
962
963 decode_text (&pc);
964
965 }/* print_literal */
966
967 /*
968 * println_return
969 *
970 * Print a string embedded in the instruction stream as with print_literal,
971 * except flush the output buffer and write a new line. After this return from
972 * the current subroutine with a status of true.
973 *
974 */
975
976 #ifdef __STDC__
println_return(void)977 void println_return (void)
978 #else
979 void println_return ()
980 #endif
981 {
982
983 print_literal ();
984 new_line ();
985 ret (TRUE);
986
987 }/* println_return */
988
989 /*
990 * new_line
991 *
992 * Simply flush the current contents of the output buffer followed by a new
993 * line.
994 *
995 */
996
997 #ifdef __STDC__
new_line(void)998 void new_line (void)
999 #else
1000 void new_line ()
1001 #endif
1002 {
1003
1004 /* Only flush buffer if story redirect is off */
1005
1006 if (redirect_depth == 0) {
1007 flush_buffer (TRUE);
1008 script_new_line ();
1009 output_new_line ();
1010 } else
1011 write_char ('\r');
1012
1013 }/* new_line */
1014
1015 /*
1016 * print_time
1017 *
1018 * Print the time as HH:MM [am|pm]. This is a bit language dependent and can
1019 * quite easily be changed. If you change the size of the time string output
1020 * then adjust the status line position in display_status_line.
1021 *
1022 */
1023
1024 #ifdef __STDC__
print_time(int hours,int minutes)1025 void print_time (int hours, int minutes)
1026 #else
1027 void print_time (hours, minutes)
1028 int hours;
1029 int minutes;
1030 #endif
1031 {
1032 int pm_indicator;
1033
1034 /* Remember if time is pm */
1035
1036 pm_indicator = (hours < 12) ? OFF : ON;
1037
1038 /* Convert 24 hour clock to 12 hour clock */
1039
1040 hours %= 12;
1041 if (hours == 0)
1042 hours = 12;
1043
1044 /* Write hour right justified */
1045
1046 if (hours < 10)
1047 write_char (' ');
1048 print_number (hours);
1049
1050 /* Write hours/minutes separator */
1051
1052 write_char (':');
1053
1054 /* Write minutes zero filled */
1055
1056 if (minutes < 10)
1057 write_char ('0');
1058 print_number (minutes);
1059
1060 /* Write the am or pm string */
1061
1062 if (pm_indicator == ON)
1063 write_string (" pm");
1064 else
1065 write_string (" am");
1066
1067 }/* print_time */
1068
1069 /*
1070 * encode
1071 *
1072 * Convert text to packed text.
1073 *
1074 */
1075
1076 #ifdef __STDC__
encode(zword_t word_addr,zword_t word_length,zword_t word_offset,zword_t dest_addr)1077 void encode (zword_t word_addr, zword_t word_length, zword_t word_offset, zword_t dest_addr)
1078 #else
1079 void encode (word_addr, word_length, word_offset, dest_addr)
1080 zword_t word_addr;
1081 zword_t word_length;
1082 zword_t word_offset;
1083 zword_t dest_addr;
1084 #endif
1085 {
1086 short word[3];
1087 int i;
1088
1089 /* Encode the word */
1090
1091 encode_text (word_length, (const char *) &datap[word_addr + word_offset], word);
1092
1093 /* Move the encoded word, byte swapped, into the destination buffer */
1094
1095 for (i = 0; i < 3; i++, dest_addr += 2)
1096 set_word (dest_addr, word[i]);
1097
1098 }/* encode */
1099