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