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