]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/doc/chew.c
Remove the paramstuff word
[thirdparty/binutils-gdb.git] / bfd / doc / chew.c
1 /* chew
2 Copyright (C) 1990-2023 Free Software Foundation, Inc.
3 Contributed by steve chamberlain @cygnus
4
5 This file is part of BFD, the Binary File Descriptor library.
6
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.
11
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.
16
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. */
21
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
25
26 sac
27
28 Basically, this is a sort of string forth, maybe we should call it
29 struth?
30
31 You define new words thus:
32 : <newword> <oldwords> ;
33
34 */
35
36 /* Primitives provided by the program:
37
38 Two stacks are provided, a string stack and an integer stack.
39
40 Internal state variables:
41 internal_wanted - indicates whether `-i' was passed
42 internal_mode - user-settable
43
44 Commands:
45 push_text
46 ! - pop top of integer stack for address, pop next for value; store
47 @ - treat value on integer stack as the address of an integer; push
48 that integer on the integer stack after popping the "address"
49 hello - print "hello\n" to stdout
50 stdout - put stdout marker on TOS
51 stderr - put stderr marker on TOS
52 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
53 skip_past_newline
54 catstr - fn icatstr
55 copy_past_newline - append input, up to and including newline into TOS
56 dup - fn other_dup
57 drop - discard TOS
58 idrop - ditto
59 remchar - delete last character from TOS
60 get_stuff_in_command
61 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
62 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
63 and @item to each "o" line; append @end itemize
64 courierize - put @example around . and | lines, translate {* *} { }
65 exit - fn chew_exit
66 swap
67 outputdots - strip out lines without leading dots
68 maybecatstr - do catstr if internal_mode == internal_wanted, discard
69 value in any case
70 translatecomments - turn {* and *} into comment delimiters
71 kill_bogus_lines - get rid of extra newlines
72 indent
73 internalmode - pop from integer stack, set `internalmode' to that value
74 print_stack_level - print current stack depth to stderr
75 strip_trailing_newlines - go ahead, guess...
76 [quoted string] - push string onto string stack
77 [word starting with digit] - push atol(str) onto integer stack
78
79 A command must be all upper-case, and alone on a line.
80
81 Foo. */
82
83 #include <assert.h>
84 #include <stdio.h>
85 #include <ctype.h>
86 #include <stdlib.h>
87 #include <string.h>
88
89 #define DEF_SIZE 5000
90 #define STACK 50
91
92 /* Here is a string type ... */
93
94 typedef struct buffer
95 {
96 char *ptr;
97 unsigned long write_idx;
98 unsigned long size;
99 } string_type;
100
101 /* Compiled programs consist of arrays of these. */
102
103 typedef union
104 {
105 void (*f) (void);
106 struct dict_struct *e;
107 char *s;
108 long l;
109 } pcu;
110
111 typedef struct dict_struct
112 {
113 char *word;
114 struct dict_struct *next;
115 pcu *code;
116 int code_length;
117 int code_end;
118 } dict_type;
119
120 int internal_wanted;
121 int internal_mode;
122
123 int warning;
124
125 string_type stack[STACK];
126 string_type *tos;
127
128 unsigned int idx = 0; /* Pos in input buffer */
129 string_type *ptr; /* and the buffer */
130
131 long istack[STACK];
132 long *isp = &istack[0];
133
134 dict_type *root;
135
136 pcu *pc;
137
138 static void
139 die (char *msg)
140 {
141 fprintf (stderr, "%s\n", msg);
142 exit (1);
143 }
144
145 void *
146 xmalloc (size_t size)
147 {
148 void *newmem;
149
150 if (size == 0)
151 size = 1;
152 newmem = malloc (size);
153 if (!newmem)
154 die ("out of memory");
155
156 return newmem;
157 }
158
159 void *
160 xrealloc (void *oldmem, size_t size)
161 {
162 void *newmem;
163
164 if (size == 0)
165 size = 1;
166 if (!oldmem)
167 newmem = malloc (size);
168 else
169 newmem = realloc (oldmem, size);
170 if (!newmem)
171 die ("out of memory");
172
173 return newmem;
174 }
175
176 char *
177 xstrdup (const char *s)
178 {
179 size_t len = strlen (s) + 1;
180 char *ret = xmalloc (len);
181 return memcpy (ret, s, len);
182 }
183
184 static void
185 init_string_with_size (string_type *buffer, unsigned int size)
186 {
187 buffer->write_idx = 0;
188 buffer->size = size;
189 buffer->ptr = xmalloc (size);
190 }
191
192 static void
193 init_string (string_type *buffer)
194 {
195 init_string_with_size (buffer, DEF_SIZE);
196 }
197
198 static int
199 find (string_type *str, char *what)
200 {
201 unsigned int i;
202 char *p;
203 p = what;
204 for (i = 0; i < str->write_idx && *p; i++)
205 {
206 if (*p == str->ptr[i])
207 p++;
208 else
209 p = what;
210 }
211 return (*p == 0);
212 }
213
214 static void
215 write_buffer (string_type *buffer, FILE *f)
216 {
217 if (buffer->write_idx != 0
218 && fwrite (buffer->ptr, buffer->write_idx, 1, f) != 1)
219 die ("cannot write output");
220 }
221
222 static void
223 delete_string (string_type *buffer)
224 {
225 free (buffer->ptr);
226 buffer->ptr = NULL;
227 }
228
229 static char *
230 addr (string_type *buffer, unsigned int idx)
231 {
232 return buffer->ptr + idx;
233 }
234
235 static char
236 at (string_type *buffer, unsigned int pos)
237 {
238 if (pos >= buffer->write_idx)
239 return 0;
240 return buffer->ptr[pos];
241 }
242
243 static void
244 catchar (string_type *buffer, int ch)
245 {
246 if (buffer->write_idx == buffer->size)
247 {
248 buffer->size *= 2;
249 buffer->ptr = xrealloc (buffer->ptr, buffer->size);
250 }
251
252 buffer->ptr[buffer->write_idx++] = ch;
253 }
254
255 static void
256 overwrite_string (string_type *dst, string_type *src)
257 {
258 free (dst->ptr);
259 dst->size = src->size;
260 dst->write_idx = src->write_idx;
261 dst->ptr = src->ptr;
262 }
263
264 static void
265 catbuf (string_type *buffer, char *buf, unsigned int len)
266 {
267 if (buffer->write_idx + len >= buffer->size)
268 {
269 while (buffer->write_idx + len >= buffer->size)
270 buffer->size *= 2;
271 buffer->ptr = xrealloc (buffer->ptr, buffer->size);
272 }
273 memcpy (buffer->ptr + buffer->write_idx, buf, len);
274 buffer->write_idx += len;
275 }
276
277 static void
278 cattext (string_type *buffer, char *string)
279 {
280 catbuf (buffer, string, (unsigned int) strlen (string));
281 }
282
283 static void
284 catstr (string_type *dst, string_type *src)
285 {
286 catbuf (dst, src->ptr, src->write_idx);
287 }
288
289 static unsigned int
290 skip_white_and_stars (string_type *src, unsigned int idx)
291 {
292 char c;
293 while ((c = at (src, idx)),
294 isspace ((unsigned char) c)
295 || (c == '*'
296 /* Don't skip past end-of-comment or star as first
297 character on its line. */
298 && at (src, idx +1) != '/'
299 && at (src, idx -1) != '\n'))
300 idx++;
301 return idx;
302 }
303
304 static unsigned int
305 skip_past_newline_1 (string_type *ptr, unsigned int idx)
306 {
307 while (at (ptr, idx)
308 && at (ptr, idx) != '\n')
309 idx++;
310 if (at (ptr, idx) == '\n')
311 return idx + 1;
312 return idx;
313 }
314
315 static void
316 check_range (void)
317 {
318 if (tos < stack)
319 die ("underflow in string stack");
320 if (tos >= stack + STACK)
321 die ("overflow in string stack");
322 }
323
324 static void
325 icheck_range (void)
326 {
327 if (isp < istack)
328 die ("underflow in integer stack");
329 if (isp >= istack + STACK)
330 die ("overflow in integer stack");
331 }
332
333 static void
334 exec (dict_type *word)
335 {
336 pc = word->code;
337 while (pc->f)
338 pc->f ();
339 }
340
341 static void
342 call (void)
343 {
344 pcu *oldpc = pc;
345 dict_type *e = pc[1].e;
346 exec (e);
347 pc = oldpc + 2;
348 }
349
350 static void
351 remchar (void)
352 {
353 if (tos->write_idx)
354 tos->write_idx--;
355 pc++;
356 }
357
358 static void
359 strip_trailing_newlines (void)
360 {
361 while ((isspace ((unsigned char) at (tos, tos->write_idx - 1))
362 || at (tos, tos->write_idx - 1) == '\n')
363 && tos->write_idx > 0)
364 tos->write_idx--;
365 pc++;
366 }
367
368 static void
369 push_number (void)
370 {
371 isp++;
372 icheck_range ();
373 pc++;
374 *isp = pc->l;
375 pc++;
376 }
377
378 static void
379 push_text (void)
380 {
381 tos++;
382 check_range ();
383 init_string (tos);
384 pc++;
385 cattext (tos, pc->s);
386 pc++;
387 }
388
389 /* This function removes everything not inside comments starting on
390 the first char of the line from the string, also when copying
391 comments, removes blank space and leading *'s.
392 Blank lines are turned into one blank line. */
393
394 static void
395 remove_noncomments (string_type *src, string_type *dst)
396 {
397 unsigned int idx = 0;
398
399 while (at (src, idx))
400 {
401 /* Now see if we have a comment at the start of the line. */
402 if (at (src, idx) == '\n'
403 && at (src, idx + 1) == '/'
404 && at (src, idx + 2) == '*')
405 {
406 idx += 3;
407
408 idx = skip_white_and_stars (src, idx);
409
410 /* Remove leading dot */
411 if (at (src, idx) == '.')
412 idx++;
413
414 /* Copy to the end of the line, or till the end of the
415 comment. */
416 while (at (src, idx))
417 {
418 if (at (src, idx) == '\n')
419 {
420 /* end of line, echo and scrape of leading blanks */
421 if (at (src, idx + 1) == '\n')
422 catchar (dst, '\n');
423 catchar (dst, '\n');
424 idx++;
425 idx = skip_white_and_stars (src, idx);
426 }
427 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
428 {
429 idx += 2;
430 cattext (dst, "\nENDDD\n");
431 break;
432 }
433 else
434 {
435 catchar (dst, at (src, idx));
436 idx++;
437 }
438 }
439 }
440 else
441 idx++;
442 }
443 }
444
445 static void
446 print_stack_level (void)
447 {
448 fprintf (stderr, "current string stack depth = %ld, ",
449 (long) (tos - stack));
450 fprintf (stderr, "current integer stack depth = %ld\n",
451 (long) (isp - istack));
452 pc++;
453 }
454
455 /* turn {*
456 and *} into comments */
457
458 static void
459 translatecomments (void)
460 {
461 unsigned int idx = 0;
462 string_type out;
463 init_string (&out);
464
465 while (at (tos, idx))
466 {
467 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
468 {
469 cattext (&out, "/*");
470 idx += 2;
471 }
472 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
473 {
474 cattext (&out, "*/");
475 idx += 2;
476 }
477 else
478 {
479 catchar (&out, at (tos, idx));
480 idx++;
481 }
482 }
483
484 overwrite_string (tos, &out);
485
486 pc++;
487 }
488
489 /* Mod tos so that only lines with leading dots remain */
490 static void
491 outputdots (void)
492 {
493 unsigned int idx = 0;
494 string_type out;
495 init_string (&out);
496
497 while (at (tos, idx))
498 {
499 /* Every iteration begins at the start of a line. */
500 if (at (tos, idx) == '.')
501 {
502 char c;
503
504 idx++;
505
506 while ((c = at (tos, idx)) && c != '\n')
507 {
508 if (c == '{' && at (tos, idx + 1) == '*')
509 {
510 cattext (&out, "/*");
511 idx += 2;
512 }
513 else if (c == '*' && at (tos, idx + 1) == '}')
514 {
515 cattext (&out, "*/");
516 idx += 2;
517 }
518 else
519 {
520 catchar (&out, c);
521 idx++;
522 }
523 }
524 if (c == '\n')
525 idx++;
526 catchar (&out, '\n');
527 }
528 else
529 {
530 idx = skip_past_newline_1 (tos, idx);
531 }
532 }
533
534 overwrite_string (tos, &out);
535 pc++;
536 }
537
538 /* Find lines starting with . and | and put example around them on tos */
539 static void
540 courierize (void)
541 {
542 string_type out;
543 unsigned int idx = 0;
544 int command = 0;
545
546 init_string (&out);
547
548 while (at (tos, idx))
549 {
550 if (at (tos, idx) == '\n'
551 && (at (tos, idx +1 ) == '.'
552 || at (tos, idx + 1) == '|'))
553 {
554 cattext (&out, "\n@example\n");
555 do
556 {
557 idx += 2;
558
559 while (at (tos, idx) && at (tos, idx) != '\n')
560 {
561 if (command > 1)
562 {
563 /* We are inside {} parameters of some command;
564 Just pass through until matching brace. */
565 if (at (tos, idx) == '{')
566 ++command;
567 else if (at (tos, idx) == '}')
568 --command;
569 }
570 else if (command != 0)
571 {
572 if (at (tos, idx) == '{')
573 ++command;
574 else if (!islower ((unsigned char) at (tos, idx)))
575 --command;
576 }
577 else if (at (tos, idx) == '@'
578 && islower ((unsigned char) at (tos, idx + 1)))
579 {
580 ++command;
581 }
582 else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
583 {
584 cattext (&out, "/*");
585 idx += 2;
586 continue;
587 }
588 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
589 {
590 cattext (&out, "*/");
591 idx += 2;
592 continue;
593 }
594 else if (at (tos, idx) == '{'
595 || at (tos, idx) == '}')
596 {
597 catchar (&out, '@');
598 }
599
600 catchar (&out, at (tos, idx));
601 idx++;
602 }
603 catchar (&out, '\n');
604 }
605 while (at (tos, idx) == '\n'
606 && ((at (tos, idx + 1) == '.')
607 || (at (tos, idx + 1) == '|')))
608 ;
609 cattext (&out, "@end example");
610 }
611 else
612 {
613 catchar (&out, at (tos, idx));
614 idx++;
615 }
616 }
617
618 overwrite_string (tos, &out);
619 pc++;
620 }
621
622 /* Finds any lines starting with "o ", if there are any, then turns
623 on @itemize @bullet, and @items each of them. Then ends with @end
624 itemize, inplace at TOS*/
625
626 static void
627 bulletize (void)
628 {
629 unsigned int idx = 0;
630 int on = 0;
631 string_type out;
632 init_string (&out);
633
634 while (at (tos, idx))
635 {
636 if (at (tos, idx) == '@'
637 && at (tos, idx + 1) == '*')
638 {
639 cattext (&out, "*");
640 idx += 2;
641 }
642 else if (at (tos, idx) == '\n'
643 && at (tos, idx + 1) == 'o'
644 && isspace ((unsigned char) at (tos, idx + 2)))
645 {
646 if (!on)
647 {
648 cattext (&out, "\n@itemize @bullet\n");
649 on = 1;
650
651 }
652 cattext (&out, "\n@item\n");
653 idx += 3;
654 }
655 else
656 {
657 catchar (&out, at (tos, idx));
658 if (on && at (tos, idx) == '\n'
659 && at (tos, idx + 1) == '\n'
660 && at (tos, idx + 2) != 'o')
661 {
662 cattext (&out, "@end itemize");
663 on = 0;
664 }
665 idx++;
666
667 }
668 }
669 if (on)
670 {
671 cattext (&out, "@end itemize\n");
672 }
673
674 delete_string (tos);
675 *tos = out;
676 pc++;
677 }
678
679 /* Turn <<foo>> into @code{foo} in place at TOS*/
680
681 static void
682 do_fancy_stuff (void)
683 {
684 unsigned int idx = 0;
685 string_type out;
686 init_string (&out);
687 while (at (tos, idx))
688 {
689 if (at (tos, idx) == '<'
690 && at (tos, idx + 1) == '<'
691 && !isspace ((unsigned char) at (tos, idx + 2)))
692 {
693 /* This qualifies as a << startup. */
694 idx += 2;
695 cattext (&out, "@code{");
696 while (at (tos, idx)
697 && at (tos, idx) != '>' )
698 {
699 catchar (&out, at (tos, idx));
700 idx++;
701
702 }
703 cattext (&out, "}");
704 idx += 2;
705 }
706 else
707 {
708 catchar (&out, at (tos, idx));
709 idx++;
710 }
711 }
712 delete_string (tos);
713 *tos = out;
714 pc++;
715
716 }
717
718 /* A command is all upper case,and alone on a line. */
719
720 static int
721 iscommand (string_type *ptr, unsigned int idx)
722 {
723 unsigned int len = 0;
724 while (at (ptr, idx))
725 {
726 if (isupper ((unsigned char) at (ptr, idx))
727 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
728 {
729 len++;
730 idx++;
731 }
732 else if (at (ptr, idx) == '\n')
733 {
734 if (len > 3)
735 return 1;
736 return 0;
737 }
738 else
739 return 0;
740 }
741 return 0;
742 }
743
744 static int
745 copy_past_newline (string_type *ptr, unsigned int idx, string_type *dst)
746 {
747 int column = 0;
748
749 while (at (ptr, idx) && at (ptr, idx) != '\n')
750 {
751 if (at (ptr, idx) == '\t')
752 {
753 /* Expand tabs. Neither makeinfo nor TeX can cope well with
754 them. */
755 do
756 catchar (dst, ' ');
757 while (++column & 7);
758 }
759 else
760 {
761 catchar (dst, at (ptr, idx));
762 column++;
763 }
764 idx++;
765
766 }
767 catchar (dst, at (ptr, idx));
768 idx++;
769 return idx;
770
771 }
772
773 static void
774 icopy_past_newline (void)
775 {
776 tos++;
777 check_range ();
778 init_string (tos);
779 idx = copy_past_newline (ptr, idx, tos);
780 pc++;
781 }
782
783 /* indent
784 Take the string at the top of the stack, do some prettying. */
785
786 static void
787 kill_bogus_lines (void)
788 {
789 int sl;
790
791 int idx = 0;
792 int c;
793 int dot = 0;
794
795 string_type out;
796 init_string (&out);
797 /* Drop leading nl. */
798 while (at (tos, idx) == '\n')
799 {
800 idx++;
801 }
802 c = idx;
803
804 /* If the first char is a '.' prepend a newline so that it is
805 recognized properly later. */
806 if (at (tos, idx) == '.')
807 catchar (&out, '\n');
808
809 /* Find the last char. */
810 while (at (tos, idx))
811 {
812 idx++;
813 }
814
815 /* Find the last non white before the nl. */
816 idx--;
817
818 while (idx && isspace ((unsigned char) at (tos, idx)))
819 idx--;
820 idx++;
821
822 /* Copy buffer upto last char, but blank lines before and after
823 dots don't count. */
824 sl = 1;
825
826 while (c < idx)
827 {
828 if (at (tos, c) == '\n'
829 && at (tos, c + 1) == '\n'
830 && at (tos, c + 2) == '.')
831 {
832 /* Ignore two newlines before a dot. */
833 c++;
834 }
835 else if (at (tos, c) == '.' && sl)
836 {
837 /* remember that this line started with a dot. */
838 dot = 2;
839 }
840 else if (at (tos, c) == '\n'
841 && at (tos, c + 1) == '\n'
842 && dot)
843 {
844 c++;
845 /* Ignore two newlines when last line was dot. */
846 }
847
848 catchar (&out, at (tos, c));
849 if (at (tos, c) == '\n')
850 {
851 sl = 1;
852
853 if (dot == 2)
854 dot = 1;
855 else
856 dot = 0;
857 }
858 else
859 sl = 0;
860
861 c++;
862
863 }
864
865 /* Append nl. */
866 catchar (&out, '\n');
867 pc++;
868 delete_string (tos);
869 *tos = out;
870
871 }
872
873 static void
874 indent (void)
875 {
876 string_type out;
877 int tab = 0;
878 int idx = 0;
879 int ol = 0;
880 init_string (&out);
881 while (at (tos, idx))
882 {
883 switch (at (tos, idx))
884 {
885 case '\n':
886 cattext (&out, "\n");
887 idx++;
888 if (tab && at (tos, idx))
889 {
890 cattext (&out, " ");
891 }
892 ol = 0;
893 break;
894 case '(':
895 tab++;
896 if (ol == 0)
897 cattext (&out, " ");
898 idx++;
899 cattext (&out, "(");
900 ol = 1;
901 break;
902 case ')':
903 tab--;
904 cattext (&out, ")");
905 idx++;
906 ol = 1;
907
908 break;
909 default:
910 catchar (&out, at (tos, idx));
911 ol = 1;
912
913 idx++;
914 break;
915 }
916 }
917
918 pc++;
919 delete_string (tos);
920 *tos = out;
921
922 }
923
924 static void
925 get_stuff_in_command (void)
926 {
927 tos++;
928 check_range ();
929 init_string (tos);
930
931 while (at (ptr, idx))
932 {
933 if (iscommand (ptr, idx))
934 break;
935 idx = copy_past_newline (ptr, idx, tos);
936 }
937 pc++;
938 }
939
940 static void
941 swap (void)
942 {
943 string_type t;
944
945 t = tos[0];
946 tos[0] = tos[-1];
947 tos[-1] = t;
948 pc++;
949 }
950
951 static void
952 other_dup (void)
953 {
954 tos++;
955 check_range ();
956 init_string (tos);
957 catstr (tos, tos - 1);
958 pc++;
959 }
960
961 static void
962 drop (void)
963 {
964 tos--;
965 check_range ();
966 delete_string (tos + 1);
967 pc++;
968 }
969
970 static void
971 idrop (void)
972 {
973 isp--;
974 icheck_range ();
975 pc++;
976 }
977
978 static void
979 icatstr (void)
980 {
981 tos--;
982 check_range ();
983 catstr (tos, tos + 1);
984 delete_string (tos + 1);
985 pc++;
986 }
987
988 static void
989 skip_past_newline (void)
990 {
991 idx = skip_past_newline_1 (ptr, idx);
992 pc++;
993 }
994
995 static void
996 internalmode (void)
997 {
998 internal_mode = *(isp);
999 isp--;
1000 icheck_range ();
1001 pc++;
1002 }
1003
1004 static void
1005 maybecatstr (void)
1006 {
1007 if (internal_wanted == internal_mode)
1008 {
1009 catstr (tos - 1, tos);
1010 }
1011 delete_string (tos);
1012 tos--;
1013 check_range ();
1014 pc++;
1015 }
1016
1017 char *
1018 nextword (char *string, char **word)
1019 {
1020 char *word_start;
1021 int idx;
1022 char *dst;
1023 char *src;
1024
1025 int length = 0;
1026
1027 while (isspace ((unsigned char) *string) || *string == '-')
1028 {
1029 if (*string == '-')
1030 {
1031 while (*string && *string != '\n')
1032 string++;
1033
1034 }
1035 else
1036 {
1037 string++;
1038 }
1039 }
1040 if (!*string)
1041 {
1042 *word = NULL;
1043 return NULL;
1044 }
1045
1046 word_start = string;
1047 if (*string == '"')
1048 {
1049 do
1050 {
1051 string++;
1052 length++;
1053 if (*string == '\\')
1054 {
1055 string += 2;
1056 length += 2;
1057 }
1058 }
1059 while (*string != '"');
1060 }
1061 else
1062 {
1063 while (!isspace ((unsigned char) *string))
1064 {
1065 string++;
1066 length++;
1067
1068 }
1069 }
1070
1071 *word = xmalloc (length + 1);
1072
1073 dst = *word;
1074 src = word_start;
1075
1076 for (idx = 0; idx < length; idx++)
1077 {
1078 if (src[idx] == '\\')
1079 switch (src[idx + 1])
1080 {
1081 case 'n':
1082 *dst++ = '\n';
1083 idx++;
1084 break;
1085 case '"':
1086 case '\\':
1087 *dst++ = src[idx + 1];
1088 idx++;
1089 break;
1090 default:
1091 *dst++ = '\\';
1092 break;
1093 }
1094 else
1095 *dst++ = src[idx];
1096 }
1097 *dst++ = 0;
1098
1099 if (*string)
1100 return string + 1;
1101 else
1102 return NULL;
1103 }
1104
1105 dict_type *
1106 lookup_word (char *word)
1107 {
1108 dict_type *ptr = root;
1109 while (ptr)
1110 {
1111 if (strcmp (ptr->word, word) == 0)
1112 return ptr;
1113 ptr = ptr->next;
1114 }
1115 if (warning)
1116 fprintf (stderr, "Can't find %s\n", word);
1117 return NULL;
1118 }
1119
1120 static void
1121 free_words (void)
1122 {
1123 dict_type *ptr = root;
1124
1125 while (ptr)
1126 {
1127 dict_type *next;
1128
1129 free (ptr->word);
1130 if (ptr->code)
1131 {
1132 int i;
1133 for (i = 0; i < ptr->code_end - 1; i ++)
1134 if (ptr->code[i].f == push_text
1135 && ptr->code[i + 1].s)
1136 {
1137 free (ptr->code[i + 1].s - 1);
1138 ++i;
1139 }
1140 free (ptr->code);
1141 }
1142 next = ptr->next;
1143 free (ptr);
1144 ptr = next;
1145 }
1146 }
1147
1148 static void
1149 perform (void)
1150 {
1151 tos = stack;
1152
1153 while (at (ptr, idx))
1154 {
1155 /* It's worth looking through the command list. */
1156 if (iscommand (ptr, idx))
1157 {
1158 char *next;
1159 dict_type *word;
1160
1161 (void) nextword (addr (ptr, idx), &next);
1162
1163 word = lookup_word (next);
1164
1165 if (word)
1166 {
1167 exec (word);
1168 }
1169 else
1170 {
1171 if (warning)
1172 fprintf (stderr, "warning, %s is not recognised\n", next);
1173 idx = skip_past_newline_1 (ptr, idx);
1174 }
1175 free (next);
1176 }
1177 else
1178 idx = skip_past_newline_1 (ptr, idx);
1179 }
1180 }
1181
1182 dict_type *
1183 newentry (char *word)
1184 {
1185 dict_type *new_d = xmalloc (sizeof (*new_d));
1186 new_d->word = word;
1187 new_d->next = root;
1188 root = new_d;
1189 new_d->code = xmalloc (sizeof (*new_d->code));
1190 new_d->code_length = 1;
1191 new_d->code_end = 0;
1192 return new_d;
1193 }
1194
1195 unsigned int
1196 add_to_definition (dict_type *entry, pcu word)
1197 {
1198 if (entry->code_end == entry->code_length)
1199 {
1200 entry->code_length += 2;
1201 entry->code = xrealloc (entry->code,
1202 entry->code_length * sizeof (*entry->code));
1203 }
1204 entry->code[entry->code_end] = word;
1205
1206 return entry->code_end++;
1207 }
1208
1209 void
1210 add_intrinsic (char *name, void (*func) (void))
1211 {
1212 dict_type *new_d = newentry (xstrdup (name));
1213 pcu p = { func };
1214 add_to_definition (new_d, p);
1215 p.f = 0;
1216 add_to_definition (new_d, p);
1217 }
1218
1219 void
1220 compile (char *string)
1221 {
1222 /* Add words to the dictionary. */
1223 char *word;
1224
1225 string = nextword (string, &word);
1226 while (string && *string && word[0])
1227 {
1228 if (word[0] == ':')
1229 {
1230 dict_type *ptr;
1231 pcu p;
1232
1233 /* Compile a word and add to dictionary. */
1234 free (word);
1235 string = nextword (string, &word);
1236 if (!string)
1237 continue;
1238 ptr = newentry (word);
1239 string = nextword (string, &word);
1240 if (!string)
1241 {
1242 free (ptr->code);
1243 free (ptr);
1244 continue;
1245 }
1246
1247 while (word[0] != ';')
1248 {
1249 switch (word[0])
1250 {
1251 case '"':
1252 /* got a string, embed magic push string
1253 function */
1254 p.f = push_text;
1255 add_to_definition (ptr, p);
1256 p.s = word + 1;
1257 add_to_definition (ptr, p);
1258 break;
1259 case '0':
1260 case '1':
1261 case '2':
1262 case '3':
1263 case '4':
1264 case '5':
1265 case '6':
1266 case '7':
1267 case '8':
1268 case '9':
1269 /* Got a number, embedd the magic push number
1270 function */
1271 p.f = push_number;
1272 add_to_definition (ptr, p);
1273 p.l = atol (word);
1274 add_to_definition (ptr, p);
1275 free (word);
1276 break;
1277 default:
1278 p.f = call;
1279 add_to_definition (ptr, p);
1280 p.e = lookup_word (word);
1281 add_to_definition (ptr, p);
1282 free (word);
1283 }
1284
1285 string = nextword (string, &word);
1286 }
1287 p.f = 0;
1288 add_to_definition (ptr, p);
1289 free (word);
1290 string = nextword (string, &word);
1291 }
1292 else
1293 {
1294 fprintf (stderr, "syntax error at %s\n", string - 1);
1295 }
1296 }
1297 free (word);
1298 }
1299
1300 static void
1301 bang (void)
1302 {
1303 *(long *) ((isp[0])) = isp[-1];
1304 isp -= 2;
1305 icheck_range ();
1306 pc++;
1307 }
1308
1309 static void
1310 atsign (void)
1311 {
1312 isp[0] = *(long *) (isp[0]);
1313 pc++;
1314 }
1315
1316 static void
1317 hello (void)
1318 {
1319 printf ("hello\n");
1320 pc++;
1321 }
1322
1323 static void
1324 stdout_ (void)
1325 {
1326 isp++;
1327 icheck_range ();
1328 *isp = 1;
1329 pc++;
1330 }
1331
1332 static void
1333 stderr_ (void)
1334 {
1335 isp++;
1336 icheck_range ();
1337 *isp = 2;
1338 pc++;
1339 }
1340
1341 static void
1342 print (void)
1343 {
1344 if (*isp == 1)
1345 write_buffer (tos, stdout);
1346 else if (*isp == 2)
1347 write_buffer (tos, stderr);
1348 else
1349 fprintf (stderr, "print: illegal print destination `%ld'\n", *isp);
1350 isp--;
1351 tos--;
1352 icheck_range ();
1353 check_range ();
1354 pc++;
1355 }
1356
1357 static void
1358 read_in (string_type *str, FILE *file)
1359 {
1360 char buff[10000];
1361 unsigned int r;
1362 do
1363 {
1364 r = fread (buff, 1, sizeof (buff), file);
1365 catbuf (str, buff, r);
1366 }
1367 while (r);
1368 buff[0] = 0;
1369
1370 catbuf (str, buff, 1);
1371 }
1372
1373 static void
1374 usage (void)
1375 {
1376 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1377 exit (33);
1378 }
1379
1380 /* There is no reliable way to declare exit. Sometimes it returns
1381 int, and sometimes it returns void. Sometimes it changes between
1382 OS releases. Trying to get it declared correctly in the hosts file
1383 is a pointless waste of time. */
1384
1385 static void
1386 chew_exit (void)
1387 {
1388 exit (0);
1389 }
1390
1391 int
1392 main (int ac, char *av[])
1393 {
1394 unsigned int i;
1395 string_type buffer;
1396 string_type pptr;
1397
1398 init_string (&buffer);
1399 init_string (&pptr);
1400 init_string (stack + 0);
1401 tos = stack + 1;
1402 ptr = &pptr;
1403
1404 add_intrinsic ("push_text", push_text);
1405 add_intrinsic ("!", bang);
1406 add_intrinsic ("@", atsign);
1407 add_intrinsic ("hello", hello);
1408 add_intrinsic ("stdout", stdout_);
1409 add_intrinsic ("stderr", stderr_);
1410 add_intrinsic ("print", print);
1411 add_intrinsic ("skip_past_newline", skip_past_newline);
1412 add_intrinsic ("catstr", icatstr);
1413 add_intrinsic ("copy_past_newline", icopy_past_newline);
1414 add_intrinsic ("dup", other_dup);
1415 add_intrinsic ("drop", drop);
1416 add_intrinsic ("idrop", idrop);
1417 add_intrinsic ("remchar", remchar);
1418 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1419 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1420 add_intrinsic ("bulletize", bulletize);
1421 add_intrinsic ("courierize", courierize);
1422 /* If the following line gives an error, exit() is not declared in the
1423 ../hosts/foo.h file for this host. Fix it there, not here! */
1424 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1425 add_intrinsic ("exit", chew_exit);
1426 add_intrinsic ("swap", swap);
1427 add_intrinsic ("outputdots", outputdots);
1428 add_intrinsic ("maybecatstr", maybecatstr);
1429 add_intrinsic ("translatecomments", translatecomments);
1430 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1431 add_intrinsic ("indent", indent);
1432 add_intrinsic ("internalmode", internalmode);
1433 add_intrinsic ("print_stack_level", print_stack_level);
1434 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1435
1436 /* Put a nl at the start. */
1437 catchar (&buffer, '\n');
1438
1439 read_in (&buffer, stdin);
1440 remove_noncomments (&buffer, ptr);
1441 for (i = 1; i < (unsigned int) ac; i++)
1442 {
1443 if (av[i][0] == '-')
1444 {
1445 if (av[i][1] == 'f')
1446 {
1447 string_type b;
1448 FILE *f;
1449 init_string (&b);
1450
1451 f = fopen (av[i + 1], "r");
1452 if (!f)
1453 {
1454 fprintf (stderr, "Can't open the input file %s\n",
1455 av[i + 1]);
1456 return 33;
1457 }
1458
1459 read_in (&b, f);
1460 compile (b.ptr);
1461 perform ();
1462 delete_string (&b);
1463 }
1464 else if (av[i][1] == 'i')
1465 {
1466 internal_wanted = 1;
1467 }
1468 else if (av[i][1] == 'w')
1469 {
1470 warning = 1;
1471 }
1472 else
1473 usage ();
1474 }
1475 }
1476 write_buffer (stack + 0, stdout);
1477 free_words ();
1478 delete_string (&pptr);
1479 delete_string (&buffer);
1480 if (tos != stack)
1481 {
1482 fprintf (stderr, "finishing with current stack level %ld\n",
1483 (long) (tos - stack));
1484 return 1;
1485 }
1486 return 0;
1487 }