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