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