2 Copyright (C) 1990-1992 Free Software Foundation, Inc.
3 Contributed by steve chamberlain @cygnus
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 Yet another way of extracting documentation from source.
22 No, I haven't finished it yet, but I hope you people like it better
27 Basically, this is a sort of string forth, maybe we should call it
30 You define new words thus:
31 : <newword> <oldwords> ;
53 /* Here is a string type ... */
58 unsigned int write_idx
;
68 static void DEFUN(init_string_with_size
,(buffer
, size
),
69 string_type
*buffer AND
72 buffer
->write_idx
= 0;
74 buffer
->ptr
= malloc(size
);
77 static void DEFUN(init_string
,(buffer
),
80 init_string_with_size(buffer
, DEF_SIZE
);
84 static int DEFUN(find
, (str
, what
),
91 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
93 if (*p
== str
->ptr
[i
])
102 static void DEFUN(write_buffer
,(buffer
),
105 fwrite(buffer
->ptr
, buffer
->write_idx
, 1, stdout
);
109 static void DEFUN(delete_string
,(buffer
),
116 static char *DEFUN(addr
, (buffer
, idx
),
117 string_type
*buffer AND
120 return buffer
->ptr
+ idx
;
123 static char DEFUN(at
,(buffer
, pos
),
124 string_type
*buffer AND
127 if ( pos
>= buffer
->write_idx
)
131 return buffer
->ptr
[pos
];
134 static void DEFUN(catchar
,(buffer
, ch
),
135 string_type
*buffer AND
138 if (buffer
->write_idx
== buffer
->size
)
141 buffer
->ptr
= realloc(buffer
->ptr
, buffer
->size
);
144 buffer
->ptr
[buffer
->write_idx
++ ] = ch
;
148 static void DEFUN(overwrite_string
,(dst
, src
),
153 dst
->size
= src
->size
;
154 dst
->write_idx
= src
->write_idx
;
158 static void DEFUN(catstr
,(dst
, src
),
163 for (i
= 0; i
< src
->write_idx
; i
++)
165 catchar(dst
, src
->ptr
[i
]);
170 static void DEFUN(cattext
,(buffer
, string
),
171 string_type
*buffer AND
177 catchar(buffer
, *string
);
182 static void DEFUN(catbuf
,(buffer
, buf
, len
),
183 string_type
*buffer AND
190 catchar(buffer
, *buf
);
198 DEFUN(skip_white_and_stars
,(src
, idx
),
202 while (isspace(at(src
,idx
))
203 || (at(src
,idx
) == '*' && at(src
,idx
+1) !='/'))
209 /***********************************************************************/
212 string_type stack
[STACK
];
215 unsigned int idx
= 0; /* Pos in input buffer */
216 string_type
*ptr
; /* and the buffer */
217 typedef void (*stinst_type
)();
219 stinst_type sstack
[STACK
];
220 stinst_type
*ssp
= &sstack
[0];
222 int *isp
= &istack
[0];
224 typedef int *word_type
;
231 struct dict_struct
*next
;
238 typedef struct dict_struct dict_type
;
239 #define WORD(x) static void x()
241 static void DEFUN(exec
,(word
),
253 stinst_type
*oldpc
= pc
;
255 e
= (dict_type
*)(pc
[1]);
286 cattext(tos
,*((char **)pc
));
293 /* This function removes everything not inside comments starting on
294 the first char of the line from the string, also when copying
295 comments, removes blank space and leading *'s
296 Blank lines are turned into one blank line
300 DEFUN(remove_noncomments
,(src
,dst
),
304 unsigned int idx
= 0;
308 /* Now see if we have a comment at the start of the line */
309 if (at(src
,idx
) == '\n'
310 && at(src
,idx
+1) == '/'
311 && at(src
,idx
+2) == '*')
315 idx
= skip_white_and_stars(src
,idx
);
317 /* Remove leading dot */
318 if (at(src
, idx
) == '.')
321 /* Copy to the end of the line, or till the end of the
325 if (at(src
, idx
) == '\n')
327 /* end of line, echo and scrape of leading blanks */
328 if (at(src
,idx
+1) == '\n')
332 idx
= skip_white_and_stars(src
, idx
);
334 else if (at(src
, idx
) == '*' && at(src
,idx
+1) == '/')
337 cattext(dst
,"\nENDDD\n");
342 catchar(dst
, at(src
, idx
));
350 /* turn foobar name(stuff); into foobar EXFUN(name,(stuff));
355 DEFUN_VOID(exfunstuff
)
364 /* make sure that it's not already exfuned */
365 if(find(tos
,"EXFUN") || find(tos
,"PROTO") || !find(tos
,"(")) {
371 /*Find the open paren*/
372 for (openp
= 0; at(tos
, openp
) != '(' && at(tos
,openp
); openp
++)
376 /* Step back to the fname */
378 while (fname
&& isspace(at(tos
, fname
)))
380 while (fname
&& !isspace(at(tos
,fname
)) && at(tos
,fname
) != '*')
385 for (idx
= 0; idx
< fname
; idx
++)
387 catchar(&out
, at(tos
,idx
));
390 cattext(&out
,"EXFUN(");
391 for (idx
= fname
; idx
< openp
; idx
++)
393 catchar(&out
, at(tos
,idx
));
396 while (at(tos
,idx
) && at(tos
,idx
) !=';')
398 catchar(&out
, at(tos
, idx
));
401 cattext(&out
,");\n");
403 overwrite_string(tos
, &out
);
411 and *} into comments */
413 WORD(translatecomments
)
415 unsigned int idx
= 0;
421 if (at(tos
,idx
) == '{' && at(tos
,idx
+1) =='*')
426 else if (at(tos
,idx
) == '*' && at(tos
,idx
+1) =='}')
433 catchar(&out
, at(tos
, idx
));
439 overwrite_string(tos
, &out
);
445 /* find something like
450 merge with words on tos and output them to stderror
455 string_type
*nos
= tos
-1;
457 unsigned int nosscan
= 0;
458 unsigned int idx
= 0;
462 if (at(tos
,idx
) == '~')
464 /* Skip the whitespace */
465 while (at(nos
, nosscan
) == ' ')
468 /* Sub the next word from the nos*/
469 while (at(nos
, nosscan
) != ' ' &&
470 at(nos
, nosscan
) != 0)
472 fprintf(stderr
, "%c", at(nos
, nosscan
));
479 fprintf(stderr
,"%c", at(tos
, idx
));
492 /* turn everything not starting with a . into a comment */
496 unsigned int idx
= 0;
502 if (at(tos
,idx
) == '\n' && at(tos
,idx
+1) =='*')
507 else if (at(tos
,idx
) == '*' && at(tos
,idx
+1) =='}')
514 catchar(&out
, at(tos
, idx
));
520 overwrite_string(tos
, &out
);
526 /* Mod tos so that only lines with leading dots remain */
528 DEFUN_VOID(outputdots
)
530 unsigned int idx
= 0;
536 if (at(tos
, idx
) == '\n' && at(tos
, idx
+1) == '.')
540 while (at(tos
, idx
) && at(tos
, idx
)!='\n')
542 if (at(tos
,idx
) == '{' && at(tos
,idx
+1) =='*')
547 else if (at(tos
,idx
) == '*' && at(tos
,idx
+1) =='}')
554 catchar(&out
, at(tos
, idx
));
566 overwrite_string(tos
, &out
);
571 /* Find lines starting with . and | and put example around them on tos
573 {* into open comment and *} into close comment
580 unsigned int idx
= 0;
586 if (at(tos
, idx
) == '\n'
587 && (at(tos
, idx
+1 ) == '.'
588 || at(tos
,idx
+1) == '|'))
590 cattext(&out
,"\n@smallexample\n");
595 while (at(tos
, idx
) && at(tos
, idx
)!='\n')
597 if (at(tos
,idx
)=='{' && at(tos
,idx
+1) =='*')
602 else if (at(tos
,idx
)=='*' && at(tos
,idx
+1) =='}')
607 else if (at(tos
,idx
) == '{')
612 else if (at(tos
,idx
) == '}')
619 catchar(&out
, at(tos
, idx
));
626 while (at(tos
, idx
) == '\n'
627 && (at(tos
, idx
+1) == '.')
628 || (at(tos
,idx
+1) == '|'));
629 cattext(&out
,"@end smallexample");
633 catchar(&out
, at(tos
, idx
));
638 overwrite_string(tos
, &out
);
645 O+ emit @itemize @bullet
657 unsigned int idx
= 0;
662 while (at(tos
, idx
)) {
663 if (at(tos
, idx
) == '@' &&
664 at(tos
, idx
+1) == '*')
671 if (at(tos
, idx
) == '\n' && at(tos
, idx
+1) == 'o')
673 if (at(tos
,idx
+2) == '+') {
674 cattext(&out
,"\n@table @code\n");
677 else if (at(tos
,idx
+2) == '-') {
678 cattext(&out
,"\n@end table\n");
681 else if (isspace(at(tos
,idx
+2))) {
682 cattext(&out
,"\n@item ");
686 catchar(&out
, at(tos
, idx
));
692 if (at(tos
, idx
) == '\n' && at(tos
, idx
+1) == 'O')
694 if (at(tos
,idx
+2) == '+') {
695 cattext(&out
,"\n@itemize @bullet\n");
699 else if (at(tos
,idx
+2) == '-') {
700 cattext(&out
,"\n@end itemize\n");
704 catchar(&out
, at(tos
, idx
));
710 catchar(&out
, at(tos
, idx
));
721 /* Turn <<foo>> into @code{foo} in place at TOS
722 Turn <[foo]> into @var{foo} in place at TOS
730 unsigned int idx
= 0;
735 if (at(tos
, idx
) == '<'
736 && at(tos
, idx
+1) == '<'
737 && (!isspace(at(tos
,idx
+ 2)) || at(tos
,idx
+3) == '>'))
739 /* This qualifies as a << startup */
741 cattext(&out
,"@code{");
744 else if (at(tos
, idx
) == '<'
745 && at(tos
, idx
+1) == '['
746 && !isspace(at(tos
,idx
+ 2)))
748 /* This qualifies as a <[ startup */
750 cattext(&out
,"@var{");
752 else if (at(tos
, idx
) == '>'
753 && at(tos
,idx
+1) =='>')
759 else if (at(tos
, idx
) == ']'
760 && at(tos
,idx
+1) =='>')
767 catchar(&out
, at(tos
, idx
));
776 /* A command is all upper case,and alone on a line */
778 DEFUN( iscommand
,(ptr
, idx
),
782 unsigned int len
= 0;
783 while (at(ptr
,idx
)) {
784 if (isupper(at(ptr
,idx
)) || at(ptr
,idx
) == ' ' ||
790 else if(at(ptr
,idx
) == '\n')
792 if (len
>4) return 1;
802 DEFUN(copy_past_newline
,(ptr
, idx
, dst
),
807 while (at(ptr
, idx
) && at(ptr
, idx
) != '\n')
809 catchar(dst
, at(ptr
, idx
));
813 catchar(dst
, at(ptr
, idx
));
819 WORD(icopy_past_newline
)
823 idx
= copy_past_newline(ptr
, idx
, tos
);
829 Take the string at the top of the stack, do some prettying */
834 WORD(kill_bogus_lines
)
845 /* Drop leading nl */
846 while (at(tos
,idx
) == '\n')
852 /* Find the last char */
858 /* find the last non white before the nl */
861 while (idx
&& isspace(at(tos
,idx
)))
865 /* Copy buffer upto last char, but blank lines before and after
871 if (at(tos
,c
) == '\n'
872 && at(tos
,c
+1) == '\n'
873 && at(tos
,c
+2) == '.')
875 /* Ignore two linelines before a dot*/
878 else if (at(tos
,c
) == '.' && sl
)
880 /* remember that this line started with a dot */
883 else if (at(tos
,c
) == '\n'
884 && at(tos
,c
+1) == '\n'
888 /* Ignore two newlines when last line was dot */
891 catchar(&out
, at(tos
,c
));
892 if (at(tos
,c
) == '\n')
896 if (dot
== 2)dot
=1;else dot
= 0;
919 while (at(tos
,idx
)) {
947 catchar(&out
,at(tos
,idx
));
961 /* Change the TOS so that all that is left is the stuff inside the
965 WORD(get_stuff_in_angle
)
967 unsigned int idx
= 0;
973 if (at(tos
,idx
) == '<' && at(tos
,idx
+1) =='<')
977 while (!(at(tos
,idx
) == '>' && at(tos
,idx
+1) == '>'))
979 catchar(&out
, at(tos
, idx
));
988 overwrite_string(tos
, &out
);
993 WORD(get_stuff_in_command
)
998 while (at(ptr
, idx
)) {
999 if (iscommand(ptr
, idx
)) break;
1000 idx
= copy_past_newline(ptr
, idx
, tos
);
1036 WORD(skip_past_newline
)
1039 && at(ptr
,idx
) != '\n')
1048 internal_mode
= *(isp
);
1055 if (internal_wanted
== internal_mode
)
1066 DEFUN(nextword
,(string
, word
),
1077 while (isspace(*string
) || *string
== '-') {
1080 while (*string
&& *string
!= '\n')
1088 if (!*string
) return 0;
1090 word_start
= string
;
1096 while (*string
!= '"')
1106 while (!isspace(*string
))
1113 *word
= malloc(length
+ 1);
1119 for (idx
= 0; idx
< length
; idx
++)
1122 if (src
[idx
] == '\\' && src
[idx
+1] == 'n')
1128 else *dst
++ = src
[idx
];
1144 DEFUN(lookup_word
,(word
),
1147 dict_type
*ptr
= root
;
1149 if (strcmp(ptr
->word
, word
) == 0) return ptr
;
1153 fprintf(stderr
,"Can't find %s\n",word
);
1159 static void DEFUN_VOID(perform
)
1163 while (at(ptr
, idx
)) {
1164 /* It's worth looking through the command list */
1165 if (iscommand(ptr
, idx
))
1173 (void) nextword(addr(ptr
, idx
), &next
);
1176 word
= lookup_word(next
);
1187 fprintf(stderr
,"warning, %s is not recognised\n", next
);
1188 skip_past_newline();
1192 else skip_past_newline();
1198 DEFUN(newentry
,(word
),
1201 dict_type
*new = (dict_type
*)malloc(sizeof(dict_type
));
1205 new->code
= (stinst_type
*)malloc(sizeof(stinst_type
));
1206 new->code_length
= 1;
1214 DEFUN(add_to_definition
,(entry
, word
),
1215 dict_type
*entry AND
1218 if (entry
->code_end
== entry
->code_length
)
1220 entry
->code_length
+= 2;
1222 (stinst_type
*) realloc((char *)(entry
->code
),
1223 entry
->code_length
*sizeof(word_type
));
1225 entry
->code
[entry
->code_end
] = word
;
1227 return entry
->code_end
++;
1237 DEFUN(add_intrinsic
,(name
, func
),
1241 dict_type
*new = newentry(name
);
1242 add_to_definition(new, func
);
1243 add_to_definition(new, 0);
1253 DEFUN(add_var
,(name
),
1256 dict_type
*new = newentry(name
);
1257 add_to_definition(new, push_number
);
1258 add_to_definition(new, (stinst_type
)(&(new->var
)));
1259 add_to_definition(new,0);
1267 DEFUN(compile
, (string
),
1273 /* add words to the dictionary */
1275 string
= nextword(string
, &word
);
1276 while (string
&& *string
&& word
[0])
1278 if (strcmp(word
,"var")==0)
1280 string
=nextword(string
, &word
);
1283 string
=nextword(string
, &word
);
1290 /* Compile a word and add to dictionary */
1291 string
= nextword(string
, &word
);
1293 ptr
= newentry(word
);
1294 string
= nextword(string
, &word
);
1295 while (word
[0] != ';' )
1302 /* got a string, embed magic push string
1304 add_to_definition(ptr
, push_text
);
1305 add_to_definition(ptr
, (stinst_type
)(word
+1));
1317 /* Got a number, embedd the magic push number
1319 add_to_definition(ptr
, push_number
);
1320 add_to_definition(ptr
, atol(word
));
1323 add_to_definition(ptr
, call
);
1324 add_to_definition(ptr
, lookup_word(word
));
1327 string
= nextword(string
, &word
);
1329 add_to_definition(ptr
,0);
1330 string
= nextword(string
, &word
);
1334 fprintf(stderr
,"syntax error at %s\n",string
-1);
1341 static void DEFUN_VOID(bang
)
1343 *(int *)((isp
[0])) = isp
[-1];
1351 isp
[0] = *(int *)(isp
[0]);
1364 static void DEFUN(read_in
, (str
, file
),
1365 string_type
*str AND
1372 r
= fread(buff
, 1, sizeof(buff
), file
);
1373 catbuf(str
, buff
, r
);
1378 catbuf(str
, buff
,1);
1383 static void DEFUN_VOID(usage
)
1385 fprintf(stderr
,"usage: -[d|i|g] <file >file\n");
1389 int DEFUN(main
,(ac
,av
),
1400 init_string(&buffer
);
1402 init_string(stack
+0);
1406 add_intrinsic("push_text", push_text
);
1407 add_intrinsic("!", bang
);
1408 add_intrinsic("@", atsign
);
1409 add_intrinsic("hello",hello
);
1410 add_intrinsic("skip_past_newline", skip_past_newline
);
1411 add_intrinsic("catstr", icatstr
);
1412 add_intrinsic("copy_past_newline", icopy_past_newline
);
1413 add_intrinsic("dup", dup
);
1414 add_intrinsic("remchar", remchar
);
1415 add_intrinsic("get_stuff_in_command", get_stuff_in_command
);
1416 add_intrinsic("get_stuff_in_angle", get_stuff_in_angle
);
1417 add_intrinsic("do_fancy_stuff", do_fancy_stuff
);
1418 add_intrinsic("bulletize", bulletize
);
1419 add_intrinsic("courierize", courierize
);
1420 add_intrinsic("swap", swap
);
1421 add_intrinsic("outputdots", outputdots
);
1422 add_intrinsic("exfunstuff", exfunstuff
);
1423 add_intrinsic("maybecatstr", maybecatstr
);
1424 add_intrinsic("translatecomments", translatecomments
);
1425 add_intrinsic("kill_bogus_lines", kill_bogus_lines
);
1426 add_intrinsic("indent", indent
);
1427 add_intrinsic("quickref", quickref
);
1428 add_intrinsic("internalmode", internalmode
);
1430 /* Put a nl at the start */
1431 catchar(&buffer
,'\n');
1433 read_in(&buffer
, stdin
);
1434 remove_noncomments(&buffer
, ptr
);
1435 for (i
= 1; i
< ac
; i
++)
1437 if (av
[i
][0] == '-')
1439 if (av
[i
][1] == 'f')
1445 f
= fopen(av
[i
+1],"r");
1448 fprintf(stderr
,"Can't open the input file %s\n",av
[i
+1]);
1457 else if (av
[i
][1] == 'i')
1459 internal_wanted
= 1;
1464 write_buffer(stack
+0);