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