Update year range in copyright notice of binutils files
[binutils-gdb.git] / bfd / doc / chew.c
blob28c8072c27259492fbe726d6a05dbf37628b0c20
1 /* chew
2 Copyright (C) 1990-2024 Free Software Foundation, Inc.
3 Contributed by steve chamberlain @cygnus
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
22 /* Yet another way of extracting documentation from source.
23 No, I haven't finished it yet, but I hope you people like it better
24 than the old way
26 sac
28 Basically, this is a sort of string forth, maybe we should call it
29 struth?
31 You define new words thus:
32 : <newword> <oldwords> ;
34 Variables are defined using:
35 variable NAME
39 /* Primitives provided by the program:
41 Two stacks are provided, a string stack and an integer stack.
43 Internal state variables:
44 internal_wanted - indicates whether `-i' was passed
45 internal_mode - user-settable
47 Commands:
48 push_text
49 ! - pop top of integer stack for address, pop next for value; store
50 @ - treat value on integer stack as the address of an integer; push
51 that integer on the integer stack after popping the "address"
52 hello - print "hello\n" to stdout
53 stdout - put stdout marker on TOS
54 stderr - put stderr marker on TOS
55 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
56 skip_past_newline
57 catstr - fn icatstr
58 copy_past_newline - append input, up to and including newline into TOS
59 dup - fn other_dup
60 drop - discard TOS
61 idrop - ditto
62 remchar - delete last character from TOS
63 get_stuff_in_command
64 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
65 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
66 and @item to each "o" line; append @end itemize
67 courierize - put @example around . and | lines, translate {* *} { }
68 exit - fn chew_exit
69 swap
70 outputdots - strip out lines without leading dots
71 maybecatstr - do catstr if internal_mode == internal_wanted, discard
72 value in any case
73 catstrif - do catstr if top of integer stack is nonzero
74 translatecomments - turn {* and *} into comment delimiters
75 kill_bogus_lines - get rid of extra newlines
76 indent
77 print_stack_level - print current stack depth to stderr
78 strip_trailing_newlines - go ahead, guess...
79 [quoted string] - push string onto string stack
80 [word starting with digit] - push atol(str) onto integer stack
82 internalmode - the internalmode variable (evaluates to address)
84 A command must be all upper-case, and alone on a line.
86 Foo. */
88 #include <assert.h>
89 #include <stdio.h>
90 #include <ctype.h>
91 #include <stdlib.h>
92 #include <string.h>
93 #include <stdint.h>
94 #include <inttypes.h>
96 #define DEF_SIZE 5000
97 #define STACK 50
99 /* Here is a string type ... */
101 typedef struct buffer
103 char *ptr;
104 unsigned long write_idx;
105 unsigned long size;
106 } string_type;
108 /* Compiled programs consist of arrays of these. */
110 typedef union
112 void (*f) (void);
113 struct dict_struct *e;
114 char *s;
115 intptr_t l;
116 } pcu;
118 typedef struct dict_struct
120 char *word;
121 struct dict_struct *next;
122 pcu *code;
123 int code_length;
124 int code_end;
125 } dict_type;
127 int internal_wanted;
128 intptr_t *internal_mode;
130 int warning;
132 string_type stack[STACK];
133 string_type *tos;
135 unsigned int idx = 0; /* Pos in input buffer */
136 string_type *ptr; /* and the buffer */
138 intptr_t istack[STACK];
139 intptr_t *isp = &istack[0];
141 dict_type *root;
143 pcu *pc;
145 static void
146 die (char *msg)
148 fprintf (stderr, "%s\n", msg);
149 exit (1);
152 void *
153 xmalloc (size_t size)
155 void *newmem;
157 if (size == 0)
158 size = 1;
159 newmem = malloc (size);
160 if (!newmem)
161 die ("out of memory");
163 return newmem;
166 void *
167 xrealloc (void *oldmem, size_t size)
169 void *newmem;
171 if (size == 0)
172 size = 1;
173 if (!oldmem)
174 newmem = malloc (size);
175 else
176 newmem = realloc (oldmem, size);
177 if (!newmem)
178 die ("out of memory");
180 return newmem;
183 char *
184 xstrdup (const char *s)
186 size_t len = strlen (s) + 1;
187 char *ret = xmalloc (len);
188 return memcpy (ret, s, len);
191 static void
192 init_string_with_size (string_type *buffer, unsigned int size)
194 buffer->write_idx = 0;
195 buffer->size = size;
196 buffer->ptr = xmalloc (size);
199 static void
200 init_string (string_type *buffer)
202 init_string_with_size (buffer, DEF_SIZE);
205 static int
206 find (string_type *str, char *what)
208 unsigned int i;
209 char *p;
210 p = what;
211 for (i = 0; i < str->write_idx && *p; i++)
213 if (*p == str->ptr[i])
214 p++;
215 else
216 p = what;
218 return (*p == 0);
221 static void
222 write_buffer (string_type *buffer, FILE *f)
224 if (buffer->write_idx != 0
225 && fwrite (buffer->ptr, buffer->write_idx, 1, f) != 1)
226 die ("cannot write output");
229 static void
230 delete_string (string_type *buffer)
232 free (buffer->ptr);
233 buffer->ptr = NULL;
236 static char *
237 addr (string_type *buffer, unsigned int idx)
239 return buffer->ptr + idx;
242 static char
243 at (string_type *buffer, unsigned int pos)
245 if (pos >= buffer->write_idx)
246 return 0;
247 return buffer->ptr[pos];
250 static void
251 catchar (string_type *buffer, int ch)
253 if (buffer->write_idx == buffer->size)
255 buffer->size *= 2;
256 buffer->ptr = xrealloc (buffer->ptr, buffer->size);
259 buffer->ptr[buffer->write_idx++] = ch;
262 static void
263 overwrite_string (string_type *dst, string_type *src)
265 free (dst->ptr);
266 dst->size = src->size;
267 dst->write_idx = src->write_idx;
268 dst->ptr = src->ptr;
271 static void
272 catbuf (string_type *buffer, char *buf, unsigned int len)
274 if (buffer->write_idx + len >= buffer->size)
276 while (buffer->write_idx + len >= buffer->size)
277 buffer->size *= 2;
278 buffer->ptr = xrealloc (buffer->ptr, buffer->size);
280 memcpy (buffer->ptr + buffer->write_idx, buf, len);
281 buffer->write_idx += len;
284 static void
285 cattext (string_type *buffer, char *string)
287 catbuf (buffer, string, (unsigned int) strlen (string));
290 static void
291 catstr (string_type *dst, string_type *src)
293 catbuf (dst, src->ptr, src->write_idx);
296 static unsigned int
297 skip_white_and_stars (string_type *src, unsigned int idx)
299 char c;
300 while ((c = at (src, idx)),
301 isspace ((unsigned char) c)
302 || (c == '*'
303 /* Don't skip past end-of-comment or star as first
304 character on its line. */
305 && at (src, idx +1) != '/'
306 && at (src, idx -1) != '\n'))
307 idx++;
308 return idx;
311 static unsigned int
312 skip_past_newline_1 (string_type *ptr, unsigned int idx)
314 while (at (ptr, idx)
315 && at (ptr, idx) != '\n')
316 idx++;
317 if (at (ptr, idx) == '\n')
318 return idx + 1;
319 return idx;
322 static void
323 check_range (void)
325 if (tos < stack)
326 die ("underflow in string stack");
327 if (tos >= stack + STACK)
328 die ("overflow in string stack");
331 static void
332 icheck_range (void)
334 if (isp < istack)
335 die ("underflow in integer stack");
336 if (isp >= istack + STACK)
337 die ("overflow in integer stack");
340 static void
341 drop (void)
343 tos--;
344 check_range ();
345 delete_string (tos + 1);
346 pc++;
349 static void
350 idrop (void)
352 isp--;
353 icheck_range ();
354 pc++;
357 static void
358 exec (dict_type *word)
360 pc = word->code;
361 while (pc->f)
362 pc->f ();
365 static void
366 call (void)
368 pcu *oldpc = pc;
369 dict_type *e = pc[1].e;
370 exec (e);
371 pc = oldpc + 2;
374 static void
375 remchar (void)
377 if (tos->write_idx)
378 tos->write_idx--;
379 pc++;
382 static void
383 strip_trailing_newlines (void)
385 while (tos->write_idx > 0
386 && (isspace ((unsigned char) at (tos, tos->write_idx - 1))
387 || at (tos, tos->write_idx - 1) == '\n'))
388 tos->write_idx--;
389 pc++;
392 static void
393 push_number (void)
395 isp++;
396 icheck_range ();
397 pc++;
398 *isp = pc->l;
399 pc++;
402 /* This is a wrapper for push_number just so we can correctly free the
403 variable at the end. */
404 static void
405 push_variable (void)
407 push_number ();
410 static void
411 push_text (void)
413 tos++;
414 check_range ();
415 init_string (tos);
416 pc++;
417 cattext (tos, pc->s);
418 pc++;
421 /* This function removes everything not inside comments starting on
422 the first char of the line from the string, also when copying
423 comments, removes blank space and leading *'s.
424 Blank lines are turned into one blank line. */
426 static void
427 remove_noncomments (string_type *src, string_type *dst)
429 unsigned int idx = 0;
431 while (at (src, idx))
433 /* Now see if we have a comment at the start of the line. */
434 if (at (src, idx) == '\n'
435 && at (src, idx + 1) == '/'
436 && at (src, idx + 2) == '*')
438 idx += 3;
440 idx = skip_white_and_stars (src, idx);
442 /* Remove leading dot */
443 if (at (src, idx) == '.')
444 idx++;
446 /* Copy to the end of the line, or till the end of the
447 comment. */
448 while (at (src, idx))
450 if (at (src, idx) == '\n')
452 /* end of line, echo and scrape of leading blanks */
453 if (at (src, idx + 1) == '\n')
454 catchar (dst, '\n');
455 catchar (dst, '\n');
456 idx++;
457 idx = skip_white_and_stars (src, idx);
459 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
461 idx += 2;
462 cattext (dst, "\nENDDD\n");
463 break;
465 else
467 catchar (dst, at (src, idx));
468 idx++;
472 else
473 idx++;
477 static void
478 print_stack_level (void)
480 fprintf (stderr, "current string stack depth = %ld, ",
481 (long) (tos - stack));
482 fprintf (stderr, "current integer stack depth = %ld\n",
483 (long) (isp - istack));
484 pc++;
487 /* turn {*
488 and *} into comments */
490 static void
491 translatecomments (void)
493 unsigned int idx = 0;
494 string_type out;
495 init_string (&out);
497 while (at (tos, idx))
499 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
501 cattext (&out, "/*");
502 idx += 2;
504 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
506 cattext (&out, "*/");
507 idx += 2;
509 else
511 catchar (&out, at (tos, idx));
512 idx++;
516 overwrite_string (tos, &out);
518 pc++;
521 /* Wrap tos-1 as a C comment, indenting by tos. */
523 static void
524 wrap_comment (void)
526 string_type out;
527 init_string (&out);
529 catstr (&out, tos);
530 cattext (&out, "/* ");
531 for (unsigned int idx = 0; at (tos - 1, idx); idx++)
533 catchar (&out, at (tos - 1, idx));
534 if (at (tos - 1, idx) == '\n' && at (tos - 1, idx + 1) != '\n')
536 catstr (&out, tos);
537 cattext (&out, " ");
540 cattext (&out, " */");
542 overwrite_string (tos - 1, &out);
543 drop ();
545 pc++;
548 /* Mod tos so that only lines with leading dots remain */
549 static void
550 outputdots (void)
552 unsigned int idx = 0;
553 string_type out;
554 init_string (&out);
556 while (at (tos, idx))
558 /* Every iteration begins at the start of a line. */
559 if (at (tos, idx) == '.')
561 char c;
562 int spaces;
564 idx++;
565 spaces = 0;
566 while ((c = at (tos, idx)) && c != '\n')
568 if (spaces >= 0)
570 if (c == ' ')
572 spaces++;
573 idx++;
574 continue;
576 else
578 while (spaces >= 8)
580 catchar (&out, '\t');
581 spaces -= 8;
583 while (spaces-- > 0)
584 catchar (&out, ' ');
587 if (c == '{' && at (tos, idx + 1) == '*')
589 cattext (&out, "/*");
590 idx += 2;
592 else if (c == '*' && at (tos, idx + 1) == '}')
594 cattext (&out, "*/");
595 idx += 2;
597 else
599 catchar (&out, c);
600 idx++;
603 if (c == '\n')
604 idx++;
605 catchar (&out, '\n');
607 else
609 idx = skip_past_newline_1 (tos, idx);
613 overwrite_string (tos, &out);
614 pc++;
617 /* Find lines starting with . and | and put example around them on tos */
618 static void
619 courierize (void)
621 string_type out;
622 unsigned int idx = 0;
623 int command = 0;
625 init_string (&out);
627 while (at (tos, idx))
629 if (at (tos, idx) == '\n'
630 && (at (tos, idx +1 ) == '.'
631 || at (tos, idx + 1) == '|'))
633 cattext (&out, "\n@example\n");
636 idx += 2;
638 while (at (tos, idx) && at (tos, idx) != '\n')
640 if (command > 1)
642 /* We are inside {} parameters of some command;
643 Just pass through until matching brace. */
644 if (at (tos, idx) == '{')
645 ++command;
646 else if (at (tos, idx) == '}')
647 --command;
649 else if (command != 0)
651 if (at (tos, idx) == '{')
652 ++command;
653 else if (!islower ((unsigned char) at (tos, idx)))
654 --command;
656 else if (at (tos, idx) == '@'
657 && islower ((unsigned char) at (tos, idx + 1)))
659 ++command;
661 else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
663 cattext (&out, "/*");
664 idx += 2;
665 continue;
667 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
669 cattext (&out, "*/");
670 idx += 2;
671 continue;
673 else if (at (tos, idx) == '{'
674 || at (tos, idx) == '}')
676 catchar (&out, '@');
679 catchar (&out, at (tos, idx));
680 idx++;
682 catchar (&out, '\n');
684 while (at (tos, idx) == '\n'
685 && ((at (tos, idx + 1) == '.')
686 || (at (tos, idx + 1) == '|')))
688 cattext (&out, "@end example");
690 else
692 catchar (&out, at (tos, idx));
693 idx++;
697 overwrite_string (tos, &out);
698 pc++;
701 /* Finds any lines starting with "o ", if there are any, then turns
702 on @itemize @bullet, and @items each of them. Then ends with @end
703 itemize, inplace at TOS*/
705 static void
706 bulletize (void)
708 unsigned int idx = 0;
709 int on = 0;
710 string_type out;
711 init_string (&out);
713 while (at (tos, idx))
715 if (at (tos, idx) == '@'
716 && at (tos, idx + 1) == '*')
718 cattext (&out, "*");
719 idx += 2;
721 else if (at (tos, idx) == '\n'
722 && at (tos, idx + 1) == 'o'
723 && isspace ((unsigned char) at (tos, idx + 2)))
725 if (!on)
727 cattext (&out, "\n@itemize @bullet\n");
728 on = 1;
731 cattext (&out, "\n@item\n");
732 idx += 3;
734 else
736 catchar (&out, at (tos, idx));
737 if (on && at (tos, idx) == '\n'
738 && at (tos, idx + 1) == '\n'
739 && at (tos, idx + 2) != 'o')
741 cattext (&out, "@end itemize");
742 on = 0;
744 idx++;
748 if (on)
750 cattext (&out, "@end itemize\n");
753 delete_string (tos);
754 *tos = out;
755 pc++;
758 /* Turn <<foo>> into @code{foo} in place at TOS*/
760 static void
761 do_fancy_stuff (void)
763 unsigned int idx = 0;
764 string_type out;
765 init_string (&out);
766 while (at (tos, idx))
768 if (at (tos, idx) == '<'
769 && at (tos, idx + 1) == '<'
770 && !isspace ((unsigned char) at (tos, idx + 2)))
772 /* This qualifies as a << startup. */
773 idx += 2;
774 cattext (&out, "@code{");
775 while (at (tos, idx)
776 && at (tos, idx) != '>' )
778 catchar (&out, at (tos, idx));
779 idx++;
782 cattext (&out, "}");
783 idx += 2;
785 else
787 catchar (&out, at (tos, idx));
788 idx++;
791 delete_string (tos);
792 *tos = out;
793 pc++;
797 /* A command is all upper case,and alone on a line. */
799 static int
800 iscommand (string_type *ptr, unsigned int idx)
802 unsigned int len = 0;
803 while (at (ptr, idx))
805 if (isupper ((unsigned char) at (ptr, idx))
806 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
808 len++;
809 idx++;
811 else if (at (ptr, idx) == '\n')
813 if (len > 3)
814 return 1;
815 return 0;
817 else
818 return 0;
820 return 0;
823 static int
824 copy_past_newline (string_type *ptr, unsigned int idx, string_type *dst)
826 int column = 0;
828 while (at (ptr, idx) && at (ptr, idx) != '\n')
830 if (at (ptr, idx) == '\t')
832 /* Expand tabs. Neither makeinfo nor TeX can cope well with
833 them. */
835 catchar (dst, ' ');
836 while (++column & 7);
838 else
840 catchar (dst, at (ptr, idx));
841 column++;
843 idx++;
846 catchar (dst, at (ptr, idx));
847 idx++;
848 return idx;
852 static void
853 icopy_past_newline (void)
855 tos++;
856 check_range ();
857 init_string (tos);
858 idx = copy_past_newline (ptr, idx, tos);
859 pc++;
862 static void
863 kill_bogus_lines (void)
865 int sl;
867 int idx = 0;
868 int c;
869 int dot = 0;
871 string_type out;
872 init_string (&out);
873 /* Drop leading nl. */
874 while (at (tos, idx) == '\n')
876 idx++;
878 c = idx;
880 /* If the first char is a '.' prepend a newline so that it is
881 recognized properly later. */
882 if (at (tos, idx) == '.')
883 catchar (&out, '\n');
885 /* Find the last char. */
886 while (at (tos, idx))
888 idx++;
891 /* Find the last non white before the nl. */
892 idx--;
894 while (idx && isspace ((unsigned char) at (tos, idx)))
895 idx--;
896 idx++;
898 /* Copy buffer upto last char, but blank lines before and after
899 dots don't count. */
900 sl = 1;
902 while (c < idx)
904 if (at (tos, c) == '\n'
905 && at (tos, c + 1) == '\n'
906 && at (tos, c + 2) == '.')
908 /* Ignore two newlines before a dot. */
909 c++;
911 else if (at (tos, c) == '.' && sl)
913 /* remember that this line started with a dot. */
914 dot = 2;
916 else if (at (tos, c) == '\n'
917 && at (tos, c + 1) == '\n'
918 && dot)
920 c++;
921 /* Ignore two newlines when last line was dot. */
924 catchar (&out, at (tos, c));
925 if (at (tos, c) == '\n')
927 sl = 1;
929 if (dot == 2)
930 dot = 1;
931 else
932 dot = 0;
934 else
935 sl = 0;
937 c++;
941 /* Append nl. */
942 catchar (&out, '\n');
943 pc++;
944 delete_string (tos);
945 *tos = out;
949 static void
950 collapse_whitespace (void)
952 int last_was_ws = 0;
953 int idx;
955 string_type out;
956 init_string (&out);
958 for (idx = 0; at (tos, idx) != 0; ++idx)
960 char c = at (tos, idx);
961 if (isspace (c))
963 if (!last_was_ws)
965 catchar (&out, ' ');
966 last_was_ws = 1;
969 else
971 catchar (&out, c);
972 last_was_ws = 0;
976 pc++;
977 delete_string (tos);
978 *tos = out;
981 /* indent
982 Take the string at the top of the stack, do some prettying. */
984 static void
985 indent (void)
987 string_type out;
988 int tab = 0;
989 int idx = 0;
990 int ol = 0;
991 init_string (&out);
992 while (at (tos, idx))
994 switch (at (tos, idx))
996 case '\n':
997 catchar (&out, '\n');
998 idx++;
999 if (tab && at (tos, idx))
1001 int i;
1002 for (i = 0; i < tab - 1; i += 2)
1003 catchar (&out, '\t');
1004 if (i < tab)
1005 cattext (&out, " ");
1007 ol = 0;
1008 break;
1009 case '(':
1010 if (ol == 0)
1012 int i;
1013 for (i = 1; i < tab - 1; i += 2)
1014 catchar (&out, '\t');
1015 if (i < tab)
1016 cattext (&out, " ");
1017 cattext (&out, " ");
1019 tab++;
1020 idx++;
1021 catchar (&out, '(');
1022 ol = 1;
1023 break;
1024 case ')':
1025 tab--;
1026 catchar (&out, ')');
1027 idx++;
1028 ol = 1;
1029 break;
1030 default:
1031 catchar (&out, at (tos, idx));
1032 ol = 1;
1033 idx++;
1034 break;
1038 pc++;
1039 delete_string (tos);
1040 *tos = out;
1044 static void
1045 get_stuff_in_command (void)
1047 tos++;
1048 check_range ();
1049 init_string (tos);
1051 while (at (ptr, idx))
1053 if (iscommand (ptr, idx))
1054 break;
1055 idx = copy_past_newline (ptr, idx, tos);
1057 pc++;
1060 static void
1061 swap (void)
1063 string_type t;
1065 t = tos[0];
1066 tos[0] = tos[-1];
1067 tos[-1] = t;
1068 pc++;
1071 static void
1072 other_dup (void)
1074 tos++;
1075 check_range ();
1076 init_string (tos);
1077 catstr (tos, tos - 1);
1078 pc++;
1081 static void
1082 icatstr (void)
1084 tos--;
1085 check_range ();
1086 catstr (tos, tos + 1);
1087 delete_string (tos + 1);
1088 pc++;
1091 static void
1092 skip_past_newline (void)
1094 idx = skip_past_newline_1 (ptr, idx);
1095 pc++;
1098 static void
1099 maybecatstr (void)
1101 if (internal_wanted == *internal_mode)
1103 catstr (tos - 1, tos);
1105 delete_string (tos);
1106 tos--;
1107 check_range ();
1108 pc++;
1111 static void
1112 catstrif (void)
1114 int cond = isp[0];
1115 isp--;
1116 icheck_range ();
1117 if (cond)
1118 catstr (tos - 1, tos);
1119 delete_string (tos);
1120 tos--;
1121 check_range ();
1122 pc++;
1125 char *
1126 nextword (char *string, char **word)
1128 char *word_start;
1129 int idx;
1130 char *dst;
1131 char *src;
1133 int length = 0;
1135 while (isspace ((unsigned char) *string) || *string == '-')
1137 if (*string == '-')
1139 while (*string && *string != '\n')
1140 string++;
1143 else
1145 string++;
1148 if (!*string)
1150 *word = NULL;
1151 return NULL;
1154 word_start = string;
1155 if (*string == '"')
1159 string++;
1160 length++;
1161 if (*string == '\\')
1163 string += 2;
1164 length += 2;
1167 while (*string != '"');
1169 else
1171 while (!isspace ((unsigned char) *string))
1173 string++;
1174 length++;
1179 *word = xmalloc (length + 1);
1181 dst = *word;
1182 src = word_start;
1184 for (idx = 0; idx < length; idx++)
1186 if (src[idx] == '\\')
1187 switch (src[idx + 1])
1189 case 'n':
1190 *dst++ = '\n';
1191 idx++;
1192 break;
1193 case '"':
1194 case '\\':
1195 *dst++ = src[idx + 1];
1196 idx++;
1197 break;
1198 default:
1199 *dst++ = '\\';
1200 break;
1202 else
1203 *dst++ = src[idx];
1205 *dst++ = 0;
1207 if (*string)
1208 return string + 1;
1209 else
1210 return NULL;
1213 dict_type *
1214 lookup_word (char *word)
1216 dict_type *ptr = root;
1217 while (ptr)
1219 if (strcmp (ptr->word, word) == 0)
1220 return ptr;
1221 ptr = ptr->next;
1223 if (warning)
1224 fprintf (stderr, "Can't find %s\n", word);
1225 return NULL;
1228 static void
1229 free_words (void)
1231 dict_type *ptr = root;
1233 while (ptr)
1235 dict_type *next;
1237 free (ptr->word);
1238 if (ptr->code)
1240 int i;
1241 for (i = 0; i < ptr->code_end - 1; i ++)
1242 if (ptr->code[i].f == push_text
1243 && ptr->code[i + 1].s)
1245 free (ptr->code[i + 1].s - 1);
1246 ++i;
1248 else if (ptr->code[i].f == push_variable)
1250 free ((void *) ptr->code[i + 1].l);
1251 ++i;
1253 free (ptr->code);
1255 next = ptr->next;
1256 free (ptr);
1257 ptr = next;
1261 static void
1262 perform (void)
1264 tos = stack;
1266 while (at (ptr, idx))
1268 /* It's worth looking through the command list. */
1269 if (iscommand (ptr, idx))
1271 char *next;
1272 dict_type *word;
1274 (void) nextword (addr (ptr, idx), &next);
1276 word = lookup_word (next);
1278 if (word)
1280 exec (word);
1282 else
1284 if (warning)
1285 fprintf (stderr, "warning, %s is not recognised\n", next);
1286 idx = skip_past_newline_1 (ptr, idx);
1288 free (next);
1290 else
1291 idx = skip_past_newline_1 (ptr, idx);
1295 dict_type *
1296 newentry (char *word)
1298 dict_type *new_d = xmalloc (sizeof (*new_d));
1299 new_d->word = word;
1300 new_d->next = root;
1301 root = new_d;
1302 new_d->code = xmalloc (sizeof (*new_d->code));
1303 new_d->code_length = 1;
1304 new_d->code_end = 0;
1305 return new_d;
1308 unsigned int
1309 add_to_definition (dict_type *entry, pcu word)
1311 if (entry->code_end == entry->code_length)
1313 entry->code_length += 2;
1314 entry->code = xrealloc (entry->code,
1315 entry->code_length * sizeof (*entry->code));
1317 entry->code[entry->code_end] = word;
1319 return entry->code_end++;
1322 void
1323 add_intrinsic (char *name, void (*func) (void))
1325 dict_type *new_d = newentry (xstrdup (name));
1326 pcu p = { func };
1327 add_to_definition (new_d, p);
1328 p.f = 0;
1329 add_to_definition (new_d, p);
1332 static void
1333 add_variable (char *name, intptr_t *loc)
1335 dict_type *new_d = newentry (name);
1336 pcu p = { push_variable };
1337 add_to_definition (new_d, p);
1338 p.l = (intptr_t) loc;
1339 add_to_definition (new_d, p);
1340 p.f = 0;
1341 add_to_definition (new_d, p);
1344 static void
1345 add_intrinsic_variable (const char *name, intptr_t *loc)
1347 add_variable (xstrdup (name), loc);
1350 void
1351 compile (char *string)
1353 /* Add words to the dictionary. */
1354 char *word;
1356 string = nextword (string, &word);
1357 while (string && *string && word[0])
1359 if (word[0] == ':')
1361 dict_type *ptr;
1362 pcu p;
1364 /* Compile a word and add to dictionary. */
1365 free (word);
1366 string = nextword (string, &word);
1367 if (!string)
1368 continue;
1369 ptr = newentry (word);
1370 string = nextword (string, &word);
1371 if (!string)
1373 free (ptr->code);
1374 free (ptr);
1375 continue;
1378 while (word[0] != ';')
1380 switch (word[0])
1382 case '"':
1383 /* got a string, embed magic push string
1384 function */
1385 p.f = push_text;
1386 add_to_definition (ptr, p);
1387 p.s = word + 1;
1388 add_to_definition (ptr, p);
1389 break;
1390 case '0':
1391 case '1':
1392 case '2':
1393 case '3':
1394 case '4':
1395 case '5':
1396 case '6':
1397 case '7':
1398 case '8':
1399 case '9':
1400 /* Got a number, embedd the magic push number
1401 function */
1402 p.f = push_number;
1403 add_to_definition (ptr, p);
1404 p.l = atol (word);
1405 add_to_definition (ptr, p);
1406 free (word);
1407 break;
1408 default:
1409 p.f = call;
1410 add_to_definition (ptr, p);
1411 p.e = lookup_word (word);
1412 add_to_definition (ptr, p);
1413 free (word);
1416 string = nextword (string, &word);
1418 p.f = 0;
1419 add_to_definition (ptr, p);
1420 free (word);
1421 string = nextword (string, &word);
1423 else if (strcmp (word, "variable") == 0)
1425 free (word);
1426 string = nextword (string, &word);
1427 if (!string)
1428 continue;
1429 intptr_t *loc = xmalloc (sizeof (intptr_t));
1430 *loc = 0;
1431 add_variable (word, loc);
1432 string = nextword (string, &word);
1434 else
1436 fprintf (stderr, "syntax error at %s\n", string - 1);
1439 free (word);
1442 static void
1443 bang (void)
1445 *(intptr_t *) ((isp[0])) = isp[-1];
1446 isp -= 2;
1447 icheck_range ();
1448 pc++;
1451 static void
1452 atsign (void)
1454 isp[0] = *(intptr_t *) (isp[0]);
1455 pc++;
1458 static void
1459 hello (void)
1461 printf ("hello\n");
1462 pc++;
1465 static void
1466 stdout_ (void)
1468 isp++;
1469 icheck_range ();
1470 *isp = 1;
1471 pc++;
1474 static void
1475 stderr_ (void)
1477 isp++;
1478 icheck_range ();
1479 *isp = 2;
1480 pc++;
1483 static void
1484 print (void)
1486 if (*isp == 1)
1487 write_buffer (tos, stdout);
1488 else if (*isp == 2)
1489 write_buffer (tos, stderr);
1490 else
1491 fprintf (stderr, "print: illegal print destination `%" PRIdPTR "'\n", *isp);
1492 isp--;
1493 tos--;
1494 icheck_range ();
1495 check_range ();
1496 pc++;
1499 static void
1500 read_in (string_type *str, FILE *file)
1502 char buff[10000];
1503 unsigned int r;
1506 r = fread (buff, 1, sizeof (buff), file);
1507 catbuf (str, buff, r);
1509 while (r);
1510 buff[0] = 0;
1512 catbuf (str, buff, 1);
1515 static void
1516 usage (void)
1518 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1519 exit (33);
1522 /* There is no reliable way to declare exit. Sometimes it returns
1523 int, and sometimes it returns void. Sometimes it changes between
1524 OS releases. Trying to get it declared correctly in the hosts file
1525 is a pointless waste of time. */
1527 static void
1528 chew_exit (void)
1530 exit (0);
1534 main (int ac, char *av[])
1536 unsigned int i;
1537 string_type buffer;
1538 string_type pptr;
1540 init_string (&buffer);
1541 init_string (&pptr);
1542 init_string (stack + 0);
1543 tos = stack + 1;
1544 ptr = &pptr;
1546 add_intrinsic ("push_text", push_text);
1547 add_intrinsic ("!", bang);
1548 add_intrinsic ("@", atsign);
1549 add_intrinsic ("hello", hello);
1550 add_intrinsic ("stdout", stdout_);
1551 add_intrinsic ("stderr", stderr_);
1552 add_intrinsic ("print", print);
1553 add_intrinsic ("skip_past_newline", skip_past_newline);
1554 add_intrinsic ("catstr", icatstr);
1555 add_intrinsic ("copy_past_newline", icopy_past_newline);
1556 add_intrinsic ("dup", other_dup);
1557 add_intrinsic ("drop", drop);
1558 add_intrinsic ("idrop", idrop);
1559 add_intrinsic ("remchar", remchar);
1560 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1561 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1562 add_intrinsic ("bulletize", bulletize);
1563 add_intrinsic ("courierize", courierize);
1564 /* If the following line gives an error, exit() is not declared in the
1565 ../hosts/foo.h file for this host. Fix it there, not here! */
1566 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1567 add_intrinsic ("exit", chew_exit);
1568 add_intrinsic ("swap", swap);
1569 add_intrinsic ("outputdots", outputdots);
1570 add_intrinsic ("maybecatstr", maybecatstr);
1571 add_intrinsic ("catstrif", catstrif);
1572 add_intrinsic ("translatecomments", translatecomments);
1573 add_intrinsic ("wrap_comment", wrap_comment);
1574 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1575 add_intrinsic ("indent", indent);
1576 add_intrinsic ("print_stack_level", print_stack_level);
1577 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1578 add_intrinsic ("collapse_whitespace", collapse_whitespace);
1580 internal_mode = xmalloc (sizeof (intptr_t));
1581 *internal_mode = 0;
1582 add_intrinsic_variable ("internalmode", internal_mode);
1584 /* Put a nl at the start. */
1585 catchar (&buffer, '\n');
1587 read_in (&buffer, stdin);
1588 remove_noncomments (&buffer, ptr);
1589 for (i = 1; i < (unsigned int) ac; i++)
1591 if (av[i][0] == '-')
1593 if (av[i][1] == 'f')
1595 string_type b;
1596 FILE *f;
1597 init_string (&b);
1599 f = fopen (av[i + 1], "r");
1600 if (!f)
1602 fprintf (stderr, "Can't open the input file %s\n",
1603 av[i + 1]);
1604 return 33;
1607 read_in (&b, f);
1608 compile (b.ptr);
1609 perform ();
1610 delete_string (&b);
1612 else if (av[i][1] == 'i')
1614 internal_wanted = 1;
1616 else if (av[i][1] == 'w')
1618 warning = 1;
1620 else
1621 usage ();
1624 write_buffer (stack + 0, stdout);
1625 free_words ();
1626 delete_string (&pptr);
1627 delete_string (&buffer);
1628 if (tos != stack)
1630 fprintf (stderr, "finishing with current stack level %ld\n",
1631 (long) (tos - stack));
1632 return 1;
1634 return 0;