[gdb/testsuite] Add PR gdb/26967 KFAIL in two more test-cases
[binutils-gdb.git] / bfd / doc / chew.c
blob842d4153005ec4d26c78ba49a562db163fb73efb
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 ();
546 /* Mod tos so that only lines with leading dots remain */
547 static void
548 outputdots (void)
550 unsigned int idx = 0;
551 string_type out;
552 init_string (&out);
554 while (at (tos, idx))
556 /* Every iteration begins at the start of a line. */
557 if (at (tos, idx) == '.')
559 char c;
560 int spaces;
562 idx++;
563 spaces = 0;
564 while ((c = at (tos, idx)) && c != '\n')
566 if (spaces >= 0)
568 if (c == ' ')
570 spaces++;
571 idx++;
572 continue;
574 else
576 while (spaces >= 8)
578 catchar (&out, '\t');
579 spaces -= 8;
581 while (spaces-- > 0)
582 catchar (&out, ' ');
585 if (c == '{' && at (tos, idx + 1) == '*')
587 cattext (&out, "/*");
588 idx += 2;
590 else if (c == '*' && at (tos, idx + 1) == '}')
592 cattext (&out, "*/");
593 idx += 2;
595 else
597 catchar (&out, c);
598 idx++;
601 if (c == '\n')
602 idx++;
603 catchar (&out, '\n');
605 else
607 idx = skip_past_newline_1 (tos, idx);
611 overwrite_string (tos, &out);
612 pc++;
615 /* Find lines starting with . and | and put example around them on tos */
616 static void
617 courierize (void)
619 string_type out;
620 unsigned int idx = 0;
621 int command = 0;
623 init_string (&out);
625 while (at (tos, idx))
627 if (at (tos, idx) == '\n'
628 && (at (tos, idx +1 ) == '.'
629 || at (tos, idx + 1) == '|'))
631 cattext (&out, "\n@example\n");
634 idx += 2;
636 while (at (tos, idx) && at (tos, idx) != '\n')
638 if (command > 1)
640 /* We are inside {} parameters of some command;
641 Just pass through until matching brace. */
642 if (at (tos, idx) == '{')
643 ++command;
644 else if (at (tos, idx) == '}')
645 --command;
647 else if (command != 0)
649 if (at (tos, idx) == '{')
650 ++command;
651 else if (!islower ((unsigned char) at (tos, idx)))
652 --command;
654 else if (at (tos, idx) == '@'
655 && islower ((unsigned char) at (tos, idx + 1)))
657 ++command;
659 else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
661 cattext (&out, "/*");
662 idx += 2;
663 continue;
665 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
667 cattext (&out, "*/");
668 idx += 2;
669 continue;
671 else if (at (tos, idx) == '{'
672 || at (tos, idx) == '}')
674 catchar (&out, '@');
677 catchar (&out, at (tos, idx));
678 idx++;
680 catchar (&out, '\n');
682 while (at (tos, idx) == '\n'
683 && ((at (tos, idx + 1) == '.')
684 || (at (tos, idx + 1) == '|')))
686 cattext (&out, "@end example");
688 else
690 catchar (&out, at (tos, idx));
691 idx++;
695 overwrite_string (tos, &out);
696 pc++;
699 /* Finds any lines starting with "o ", if there are any, then turns
700 on @itemize @bullet, and @items each of them. Then ends with @end
701 itemize, inplace at TOS*/
703 static void
704 bulletize (void)
706 unsigned int idx = 0;
707 int on = 0;
708 string_type out;
709 init_string (&out);
711 while (at (tos, idx))
713 if (at (tos, idx) == '@'
714 && at (tos, idx + 1) == '*')
716 cattext (&out, "*");
717 idx += 2;
719 else if (at (tos, idx) == '\n'
720 && at (tos, idx + 1) == 'o'
721 && isspace ((unsigned char) at (tos, idx + 2)))
723 if (!on)
725 cattext (&out, "\n@itemize @bullet\n");
726 on = 1;
729 cattext (&out, "\n@item\n");
730 idx += 3;
732 else
734 catchar (&out, at (tos, idx));
735 if (on && at (tos, idx) == '\n'
736 && at (tos, idx + 1) == '\n'
737 && at (tos, idx + 2) != 'o')
739 cattext (&out, "@end itemize");
740 on = 0;
742 idx++;
746 if (on)
748 cattext (&out, "@end itemize\n");
751 delete_string (tos);
752 *tos = out;
753 pc++;
756 /* Turn <<foo>> into @code{foo} in place at TOS*/
758 static void
759 do_fancy_stuff (void)
761 unsigned int idx = 0;
762 string_type out;
763 init_string (&out);
764 while (at (tos, idx))
766 if (at (tos, idx) == '<'
767 && at (tos, idx + 1) == '<'
768 && !isspace ((unsigned char) at (tos, idx + 2)))
770 /* This qualifies as a << startup. */
771 idx += 2;
772 cattext (&out, "@code{");
773 while (at (tos, idx)
774 && at (tos, idx) != '>' )
776 catchar (&out, at (tos, idx));
777 idx++;
780 cattext (&out, "}");
781 idx += 2;
783 else
785 catchar (&out, at (tos, idx));
786 idx++;
789 delete_string (tos);
790 *tos = out;
791 pc++;
795 /* A command is all upper case,and alone on a line. */
797 static int
798 iscommand (string_type *ptr, unsigned int idx)
800 unsigned int len = 0;
801 while (at (ptr, idx))
803 if (isupper ((unsigned char) at (ptr, idx))
804 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
806 len++;
807 idx++;
809 else if (at (ptr, idx) == '\n')
811 if (len > 3)
812 return 1;
813 return 0;
815 else
816 return 0;
818 return 0;
821 static int
822 copy_past_newline (string_type *ptr, unsigned int idx, string_type *dst)
824 int column = 0;
826 while (at (ptr, idx) && at (ptr, idx) != '\n')
828 if (at (ptr, idx) == '\t')
830 /* Expand tabs. Neither makeinfo nor TeX can cope well with
831 them. */
833 catchar (dst, ' ');
834 while (++column & 7);
836 else
838 catchar (dst, at (ptr, idx));
839 column++;
841 idx++;
844 catchar (dst, at (ptr, idx));
845 idx++;
846 return idx;
850 static void
851 icopy_past_newline (void)
853 tos++;
854 check_range ();
855 init_string (tos);
856 idx = copy_past_newline (ptr, idx, tos);
857 pc++;
860 static void
861 kill_bogus_lines (void)
863 int sl;
865 int idx = 0;
866 int c;
867 int dot = 0;
869 string_type out;
870 init_string (&out);
871 /* Drop leading nl. */
872 while (at (tos, idx) == '\n')
874 idx++;
876 c = idx;
878 /* If the first char is a '.' prepend a newline so that it is
879 recognized properly later. */
880 if (at (tos, idx) == '.')
881 catchar (&out, '\n');
883 /* Find the last char. */
884 while (at (tos, idx))
886 idx++;
889 /* Find the last non white before the nl. */
890 idx--;
892 while (idx && isspace ((unsigned char) at (tos, idx)))
893 idx--;
894 idx++;
896 /* Copy buffer upto last char, but blank lines before and after
897 dots don't count. */
898 sl = 1;
900 while (c < idx)
902 if (at (tos, c) == '\n'
903 && at (tos, c + 1) == '\n'
904 && at (tos, c + 2) == '.')
906 /* Ignore two newlines before a dot. */
907 c++;
909 else if (at (tos, c) == '.' && sl)
911 /* remember that this line started with a dot. */
912 dot = 2;
914 else if (at (tos, c) == '\n'
915 && at (tos, c + 1) == '\n'
916 && dot)
918 c++;
919 /* Ignore two newlines when last line was dot. */
922 catchar (&out, at (tos, c));
923 if (at (tos, c) == '\n')
925 sl = 1;
927 if (dot == 2)
928 dot = 1;
929 else
930 dot = 0;
932 else
933 sl = 0;
935 c++;
939 /* Append nl. */
940 catchar (&out, '\n');
941 pc++;
942 delete_string (tos);
943 *tos = out;
947 static void
948 collapse_whitespace (void)
950 int last_was_ws = 0;
951 int idx;
953 string_type out;
954 init_string (&out);
956 for (idx = 0; at (tos, idx) != 0; ++idx)
958 char c = at (tos, idx);
959 if (isspace (c))
961 if (!last_was_ws)
963 catchar (&out, ' ');
964 last_was_ws = 1;
967 else
969 catchar (&out, c);
970 last_was_ws = 0;
974 pc++;
975 delete_string (tos);
976 *tos = out;
979 /* indent
980 Take the string at the top of the stack, do some prettying. */
982 static void
983 indent (void)
985 string_type out;
986 int tab = 0;
987 int idx = 0;
988 int ol = 0;
989 init_string (&out);
990 while (at (tos, idx))
992 switch (at (tos, idx))
994 case '\n':
995 catchar (&out, '\n');
996 idx++;
997 if (tab && at (tos, idx))
999 int i;
1000 for (i = 0; i < tab - 1; i += 2)
1001 catchar (&out, '\t');
1002 if (i < tab)
1003 cattext (&out, " ");
1005 ol = 0;
1006 break;
1007 case '(':
1008 if (ol == 0)
1010 int i;
1011 for (i = 1; i < tab - 1; i += 2)
1012 catchar (&out, '\t');
1013 if (i < tab)
1014 cattext (&out, " ");
1015 cattext (&out, " ");
1017 tab++;
1018 idx++;
1019 catchar (&out, '(');
1020 ol = 1;
1021 break;
1022 case ')':
1023 tab--;
1024 catchar (&out, ')');
1025 idx++;
1026 ol = 1;
1027 break;
1028 default:
1029 catchar (&out, at (tos, idx));
1030 ol = 1;
1031 idx++;
1032 break;
1036 pc++;
1037 delete_string (tos);
1038 *tos = out;
1042 static void
1043 get_stuff_in_command (void)
1045 tos++;
1046 check_range ();
1047 init_string (tos);
1049 while (at (ptr, idx))
1051 if (iscommand (ptr, idx))
1052 break;
1053 idx = copy_past_newline (ptr, idx, tos);
1055 pc++;
1058 static void
1059 swap (void)
1061 string_type t;
1063 t = tos[0];
1064 tos[0] = tos[-1];
1065 tos[-1] = t;
1066 pc++;
1069 static void
1070 other_dup (void)
1072 tos++;
1073 check_range ();
1074 init_string (tos);
1075 catstr (tos, tos - 1);
1076 pc++;
1079 static void
1080 icatstr (void)
1082 tos--;
1083 check_range ();
1084 catstr (tos, tos + 1);
1085 delete_string (tos + 1);
1086 pc++;
1089 static void
1090 skip_past_newline (void)
1092 idx = skip_past_newline_1 (ptr, idx);
1093 pc++;
1096 static void
1097 maybecatstr (void)
1099 if (internal_wanted == *internal_mode)
1101 catstr (tos - 1, tos);
1103 delete_string (tos);
1104 tos--;
1105 check_range ();
1106 pc++;
1109 static void
1110 catstrif (void)
1112 int cond = isp[0];
1113 isp--;
1114 icheck_range ();
1115 if (cond)
1116 catstr (tos - 1, tos);
1117 delete_string (tos);
1118 tos--;
1119 check_range ();
1120 pc++;
1123 char *
1124 nextword (char *string, char **word)
1126 char *word_start;
1127 int idx;
1128 char *dst;
1129 char *src;
1131 int length = 0;
1133 while (isspace ((unsigned char) *string) || *string == '-')
1135 if (*string == '-')
1137 while (*string && *string != '\n')
1138 string++;
1141 else
1143 string++;
1146 if (!*string)
1148 *word = NULL;
1149 return NULL;
1152 word_start = string;
1153 if (*string == '"')
1157 string++;
1158 length++;
1159 if (*string == '\\')
1161 string += 2;
1162 length += 2;
1165 while (*string != '"');
1167 else
1169 while (!isspace ((unsigned char) *string))
1171 string++;
1172 length++;
1177 *word = xmalloc (length + 1);
1179 dst = *word;
1180 src = word_start;
1182 for (idx = 0; idx < length; idx++)
1184 if (src[idx] == '\\')
1185 switch (src[idx + 1])
1187 case 'n':
1188 *dst++ = '\n';
1189 idx++;
1190 break;
1191 case '"':
1192 case '\\':
1193 *dst++ = src[idx + 1];
1194 idx++;
1195 break;
1196 default:
1197 *dst++ = '\\';
1198 break;
1200 else
1201 *dst++ = src[idx];
1203 *dst++ = 0;
1205 if (*string)
1206 return string + 1;
1207 else
1208 return NULL;
1211 dict_type *
1212 lookup_word (char *word)
1214 dict_type *ptr = root;
1215 while (ptr)
1217 if (strcmp (ptr->word, word) == 0)
1218 return ptr;
1219 ptr = ptr->next;
1221 if (warning)
1222 fprintf (stderr, "Can't find %s\n", word);
1223 return NULL;
1226 static void
1227 free_words (void)
1229 dict_type *ptr = root;
1231 while (ptr)
1233 dict_type *next;
1235 free (ptr->word);
1236 if (ptr->code)
1238 int i;
1239 for (i = 0; i < ptr->code_end - 1; i ++)
1240 if (ptr->code[i].f == push_text
1241 && ptr->code[i + 1].s)
1243 free (ptr->code[i + 1].s - 1);
1244 ++i;
1246 else if (ptr->code[i].f == push_variable)
1248 free ((void *) ptr->code[i + 1].l);
1249 ++i;
1251 free (ptr->code);
1253 next = ptr->next;
1254 free (ptr);
1255 ptr = next;
1259 static void
1260 perform (void)
1262 tos = stack;
1264 while (at (ptr, idx))
1266 /* It's worth looking through the command list. */
1267 if (iscommand (ptr, idx))
1269 char *next;
1270 dict_type *word;
1272 (void) nextword (addr (ptr, idx), &next);
1274 word = lookup_word (next);
1276 if (word)
1278 exec (word);
1280 else
1282 if (warning)
1283 fprintf (stderr, "warning, %s is not recognised\n", next);
1284 idx = skip_past_newline_1 (ptr, idx);
1286 free (next);
1288 else
1289 idx = skip_past_newline_1 (ptr, idx);
1293 dict_type *
1294 newentry (char *word)
1296 dict_type *new_d = xmalloc (sizeof (*new_d));
1297 new_d->word = word;
1298 new_d->next = root;
1299 root = new_d;
1300 new_d->code = xmalloc (sizeof (*new_d->code));
1301 new_d->code_length = 1;
1302 new_d->code_end = 0;
1303 return new_d;
1306 unsigned int
1307 add_to_definition (dict_type *entry, pcu word)
1309 if (entry->code_end == entry->code_length)
1311 entry->code_length += 2;
1312 entry->code = xrealloc (entry->code,
1313 entry->code_length * sizeof (*entry->code));
1315 entry->code[entry->code_end] = word;
1317 return entry->code_end++;
1320 void
1321 add_intrinsic (char *name, void (*func) (void))
1323 dict_type *new_d = newentry (xstrdup (name));
1324 pcu p = { func };
1325 add_to_definition (new_d, p);
1326 p.f = 0;
1327 add_to_definition (new_d, p);
1330 static void
1331 add_variable (char *name, intptr_t *loc)
1333 dict_type *new_d = newentry (name);
1334 pcu p = { push_variable };
1335 add_to_definition (new_d, p);
1336 p.l = (intptr_t) loc;
1337 add_to_definition (new_d, p);
1338 p.f = 0;
1339 add_to_definition (new_d, p);
1342 static void
1343 add_intrinsic_variable (const char *name, intptr_t *loc)
1345 add_variable (xstrdup (name), loc);
1348 void
1349 compile (char *string)
1351 /* Add words to the dictionary. */
1352 char *word;
1354 string = nextword (string, &word);
1355 while (string && *string && word[0])
1357 if (word[0] == ':')
1359 dict_type *ptr;
1360 pcu p;
1362 /* Compile a word and add to dictionary. */
1363 free (word);
1364 string = nextword (string, &word);
1365 if (!string)
1366 continue;
1367 ptr = newentry (word);
1368 string = nextword (string, &word);
1369 if (!string)
1371 free (ptr->code);
1372 free (ptr);
1373 continue;
1376 while (word[0] != ';')
1378 switch (word[0])
1380 case '"':
1381 /* got a string, embed magic push string
1382 function */
1383 p.f = push_text;
1384 add_to_definition (ptr, p);
1385 p.s = word + 1;
1386 add_to_definition (ptr, p);
1387 break;
1388 case '0':
1389 case '1':
1390 case '2':
1391 case '3':
1392 case '4':
1393 case '5':
1394 case '6':
1395 case '7':
1396 case '8':
1397 case '9':
1398 /* Got a number, embedd the magic push number
1399 function */
1400 p.f = push_number;
1401 add_to_definition (ptr, p);
1402 p.l = atol (word);
1403 add_to_definition (ptr, p);
1404 free (word);
1405 break;
1406 default:
1407 p.f = call;
1408 add_to_definition (ptr, p);
1409 p.e = lookup_word (word);
1410 add_to_definition (ptr, p);
1411 free (word);
1414 string = nextword (string, &word);
1416 p.f = 0;
1417 add_to_definition (ptr, p);
1418 free (word);
1419 string = nextword (string, &word);
1421 else if (strcmp (word, "variable") == 0)
1423 free (word);
1424 string = nextword (string, &word);
1425 if (!string)
1426 continue;
1427 intptr_t *loc = xmalloc (sizeof (intptr_t));
1428 *loc = 0;
1429 add_variable (word, loc);
1430 string = nextword (string, &word);
1432 else
1434 fprintf (stderr, "syntax error at %s\n", string - 1);
1437 free (word);
1440 static void
1441 bang (void)
1443 *(intptr_t *) ((isp[0])) = isp[-1];
1444 isp -= 2;
1445 icheck_range ();
1446 pc++;
1449 static void
1450 atsign (void)
1452 isp[0] = *(intptr_t *) (isp[0]);
1453 pc++;
1456 static void
1457 hello (void)
1459 printf ("hello\n");
1460 pc++;
1463 static void
1464 stdout_ (void)
1466 isp++;
1467 icheck_range ();
1468 *isp = 1;
1469 pc++;
1472 static void
1473 stderr_ (void)
1475 isp++;
1476 icheck_range ();
1477 *isp = 2;
1478 pc++;
1481 static void
1482 print (void)
1484 if (*isp == 1)
1485 write_buffer (tos, stdout);
1486 else if (*isp == 2)
1487 write_buffer (tos, stderr);
1488 else
1489 fprintf (stderr, "print: illegal print destination `%" PRIdPTR "'\n", *isp);
1490 isp--;
1491 tos--;
1492 icheck_range ();
1493 check_range ();
1494 pc++;
1497 static void
1498 read_in (string_type *str, FILE *file)
1500 char buff[10000];
1501 unsigned int r;
1504 r = fread (buff, 1, sizeof (buff), file);
1505 catbuf (str, buff, r);
1507 while (r);
1508 buff[0] = 0;
1510 catbuf (str, buff, 1);
1513 static void
1514 usage (void)
1516 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1517 exit (33);
1520 /* There is no reliable way to declare exit. Sometimes it returns
1521 int, and sometimes it returns void. Sometimes it changes between
1522 OS releases. Trying to get it declared correctly in the hosts file
1523 is a pointless waste of time. */
1525 static void
1526 chew_exit (void)
1528 exit (0);
1532 main (int ac, char *av[])
1534 unsigned int i;
1535 string_type buffer;
1536 string_type pptr;
1538 init_string (&buffer);
1539 init_string (&pptr);
1540 init_string (stack + 0);
1541 tos = stack + 1;
1542 ptr = &pptr;
1544 add_intrinsic ("push_text", push_text);
1545 add_intrinsic ("!", bang);
1546 add_intrinsic ("@", atsign);
1547 add_intrinsic ("hello", hello);
1548 add_intrinsic ("stdout", stdout_);
1549 add_intrinsic ("stderr", stderr_);
1550 add_intrinsic ("print", print);
1551 add_intrinsic ("skip_past_newline", skip_past_newline);
1552 add_intrinsic ("catstr", icatstr);
1553 add_intrinsic ("copy_past_newline", icopy_past_newline);
1554 add_intrinsic ("dup", other_dup);
1555 add_intrinsic ("drop", drop);
1556 add_intrinsic ("idrop", idrop);
1557 add_intrinsic ("remchar", remchar);
1558 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1559 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1560 add_intrinsic ("bulletize", bulletize);
1561 add_intrinsic ("courierize", courierize);
1562 /* If the following line gives an error, exit() is not declared in the
1563 ../hosts/foo.h file for this host. Fix it there, not here! */
1564 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1565 add_intrinsic ("exit", chew_exit);
1566 add_intrinsic ("swap", swap);
1567 add_intrinsic ("outputdots", outputdots);
1568 add_intrinsic ("maybecatstr", maybecatstr);
1569 add_intrinsic ("catstrif", catstrif);
1570 add_intrinsic ("translatecomments", translatecomments);
1571 add_intrinsic ("wrap_comment", wrap_comment);
1572 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1573 add_intrinsic ("indent", indent);
1574 add_intrinsic ("print_stack_level", print_stack_level);
1575 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1576 add_intrinsic ("collapse_whitespace", collapse_whitespace);
1578 internal_mode = xmalloc (sizeof (intptr_t));
1579 *internal_mode = 0;
1580 add_intrinsic_variable ("internalmode", internal_mode);
1582 /* Put a nl at the start. */
1583 catchar (&buffer, '\n');
1585 read_in (&buffer, stdin);
1586 remove_noncomments (&buffer, ptr);
1587 for (i = 1; i < (unsigned int) ac; i++)
1589 if (av[i][0] == '-')
1591 if (av[i][1] == 'f')
1593 string_type b;
1594 FILE *f;
1595 init_string (&b);
1597 f = fopen (av[i + 1], "r");
1598 if (!f)
1600 fprintf (stderr, "Can't open the input file %s\n",
1601 av[i + 1]);
1602 return 33;
1605 read_in (&b, f);
1606 compile (b.ptr);
1607 perform ();
1608 delete_string (&b);
1610 else if (av[i][1] == 'i')
1612 internal_wanted = 1;
1614 else if (av[i][1] == 'w')
1616 warning = 1;
1618 else
1619 usage ();
1622 write_buffer (stack + 0, stdout);
1623 free_words ();
1624 delete_string (&pptr);
1625 delete_string (&buffer);
1626 if (tos != stack)
1628 fprintf (stderr, "finishing with current stack level %ld\n",
1629 (long) (tos - stack));
1630 return 1;
1632 return 0;