This is chew.c in view mode; [Download] [Up]
/* chew
Copyright (C) 1990-1991 Free Software Foundation, Inc.
Contributed by steve chamberlain @cygnus
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
Yet another way of extracting documentation from source.
No, I haven't finished it yet, but I hope you people like it better
that the old way
sac
Basically, this is a sort of string forth, maybe we should call it
struth?
You define new words thus:
: <newword> <oldwords> ;
There is no
*/
#include <ansidecl.h>
#include "sysdep.h"
#define DEF_SIZE 5000
#define STACK 50
int internal_wanted;
int internal_mode;
int warning;
/* Here is a string type ... */
typedef struct buffer
{
char *ptr;
unsigned int write_idx;
unsigned int size;
} string_type;
static void DEFUN(init_string_with_size,(buffer, size),
string_type *buffer AND
unsigned int size )
{
buffer->write_idx = 0;
buffer->size = size;
buffer->ptr = malloc(size);
}
static void DEFUN(init_string,(buffer),
string_type *buffer)
{
init_string_with_size(buffer, DEF_SIZE);
}
static int DEFUN(find, (str, what),
string_type *str AND
char *what)
{
unsigned int i;
char *p;
p = what;
for (i = 0; i < str->write_idx && *p; i++)
{
if (*p == str->ptr[i])
p++;
else
p = what;
}
return (*p == 0);
}
static void DEFUN(write_buffer,(buffer),
string_type *buffer)
{
fwrite(buffer->ptr, buffer->write_idx, 1, stdout);
}
static void DEFUN(delete_string,(buffer),
string_type *buffer)
{
free(buffer->ptr);
}
static char *DEFUN(addr, (buffer, idx),
string_type *buffer AND
unsigned int idx)
{
return buffer->ptr + idx;
}
static char DEFUN(at,(buffer, pos),
string_type *buffer AND
unsigned int pos)
{
if ( pos >= buffer->write_idx)
{
return 0;
}
return buffer->ptr[pos];
}
static void DEFUN(catchar,(buffer, ch),
string_type *buffer AND
char ch)
{
if (buffer->write_idx == buffer->size)
{
buffer->size *=2;
buffer->ptr = realloc(buffer->ptr, buffer->size);
}
buffer->ptr[buffer->write_idx ++ ] = ch;
}
static void DEFUN(overwrite_string,(dst, src),
string_type *dst AND
string_type *src)
{
free(dst->ptr);
dst->size = src->size;
dst->write_idx = src->write_idx;
dst->ptr = src->ptr;
}
static void DEFUN(catstr,(dst, src),
string_type *dst AND
string_type *src)
{
unsigned int i;
for (i = 0; i < src->write_idx; i++)
{
catchar(dst, src->ptr[i]);
}
}
static void DEFUN(cattext,(buffer, string),
string_type *buffer AND
char *string)
{
while (*string)
{
catchar(buffer, *string);
string++;
}
}
static void DEFUN(catbuf,(buffer, buf, len),
string_type *buffer AND
char *buf AND
unsigned int len)
{
while (len--)
{
catchar(buffer, *buf);
buf++;
}
}
static unsigned int
DEFUN(skip_white_and_stars,(src, idx),
string_type *src AND
unsigned int idx)
{
while (isspace(at(src,idx))
|| (at(src,idx) == '*' && at(src,idx +1) !='/'
&& at(src,idx -1) != '\n'))
idx++;
return idx;
}
/***********************************************************************/
string_type stack[STACK];
string_type *tos;
unsigned int idx = 0; /* Pos in input buffer */
string_type *ptr; /* and the buffer */
typedef void (*stinst_type)();
stinst_type *pc;
stinst_type sstack[STACK];
stinst_type *ssp = &sstack[0];
int istack[STACK];
int *isp = &istack[0];
typedef int *word_type;
struct dict_struct
{
char *word;
struct dict_struct *next;
stinst_type *code;
int code_length;
int code_end;
int var;
};
typedef struct dict_struct dict_type;
#define WORD(x) static void x()
static void DEFUN(exec,(word),
dict_type *word)
{
pc = word->code;
while (*pc)
{
(*pc)();
}
}
WORD(call)
{
stinst_type *oldpc = pc;
dict_type *e;
e = (dict_type *)(pc [1]);
exec(e);
pc = oldpc + 2;
}
WORD(remchar)
{
tos->write_idx--;
pc++;
}
WORD(push_number)
{
isp++;
pc++;
*isp = (int)(*pc);
pc++;
}
WORD(push_text)
{
tos++;
init_string(tos);
pc++;
cattext(tos,*((char **)pc));
pc++;
}
/* This function removes everything not inside comments starting on
the first char of the line from the string, also when copying
comments, removes blank space and leading *'s
Blank lines are turned into one blank line
*/
static void
DEFUN(remove_noncomments,(src,dst),
string_type *src AND
string_type *dst)
{
unsigned int idx = 0;
while (at(src,idx))
{
/* Now see if we have a comment at the start of the line */
if (at(src,idx) == '\n'
&& at(src,idx+1) == '/'
&& at(src,idx+2) == '*')
{
idx+=3;
idx = skip_white_and_stars(src,idx);
/* Remove leading dot */
if (at(src, idx) == '.')
idx++;
/* Copy to the end of the line, or till the end of the
comment */
while (at(src, idx))
{
if (at(src, idx) == '\n')
{
/* end of line, echo and scrape of leading blanks */
if (at(src,idx +1) == '\n')
catchar(dst,'\n');
catchar(dst,'\n');
idx++;
idx = skip_white_and_stars(src, idx);
}
else if (at(src, idx) == '*' && at(src,idx+1) == '/')
{
idx +=2 ;
cattext(dst,"\nENDDD\n");
break;
}
else
{
catchar(dst, at(src, idx));
idx++;
}
}
}
else idx++;
}
}
/* turn:
foobar name(stuff);
into:
foobar
name PARAMS ((stuff));
and a blank line.
*/
static void
DEFUN_VOID(paramstuff)
{
unsigned int openp;
unsigned int fname;
unsigned int idx;
string_type out;
init_string(&out);
/* make sure that it's not already param'd or proto'd */
if(find(tos,"PARAMS") || find(tos,"PROTO") || !find(tos,"(")) {
catstr(&out,tos);
}
else
{
/* Find the open paren */
for (openp = 0; at(tos, openp) != '(' && at(tos,openp); openp++)
;
fname = openp;
/* Step back to the fname */
fname--;
while (fname && isspace(at(tos, fname)))
fname --;
while (fname && !isspace(at(tos,fname)) && at(tos,fname) != '*')
fname--;
fname++;
for (idx = 0; idx < fname; idx++) /* Output type */
{
catchar(&out, at(tos,idx));
}
cattext(&out, "\n"); /* Insert a newline between type and fnname */
for (idx = fname; idx < openp; idx++) /* Output fnname */
{
catchar(&out, at(tos,idx));
}
cattext(&out," PARAMS (");
while (at(tos,idx) && at(tos,idx) !=';')
{
catchar(&out, at(tos, idx));
idx++;
}
cattext(&out,");\n\n");
}
overwrite_string(tos, &out);
pc++;
}
/* turn {*
and *} into comments */
WORD(translatecomments)
{
unsigned int idx = 0;
string_type out;
init_string(&out);
while (at(tos, idx))
{
if (at(tos,idx) == '{' && at(tos,idx+1) =='*')
{
cattext(&out," /*");
idx+=2;
}
else if (at(tos,idx) == '*' && at(tos,idx+1) =='}')
{
cattext(&out,"*/");
idx+=2;
}
else
{
catchar(&out, at(tos, idx));
idx++;
}
}
overwrite_string(tos, &out);
pc++;
}
/* turn everything not starting with a . into a comment */
WORD(manglecomments)
{
unsigned int idx = 0;
string_type out;
init_string(&out);
while (at(tos, idx))
{
if (at(tos,idx) == '\n' && at(tos,idx+1) =='*')
{
cattext(&out," /*");
idx+=2;
}
else if (at(tos,idx) == '*' && at(tos,idx+1) =='}')
{
cattext(&out,"*/");
idx+=2;
}
else
{
catchar(&out, at(tos, idx));
idx++;
}
}
overwrite_string(tos, &out);
pc++;
}
/* Mod tos so that only lines with leading dots remain */
static void
DEFUN_VOID(outputdots)
{
unsigned int idx = 0;
string_type out;
init_string(&out);
while (at(tos, idx))
{
if (at(tos, idx) == '\n' && at(tos, idx+1) == '.')
{
idx += 2;
while (at(tos, idx) && at(tos, idx)!='\n')
{
if (at(tos,idx) == '{' && at(tos,idx+1) =='*')
{
cattext(&out," /*");
idx+=2;
}
else if (at(tos,idx) == '*' && at(tos,idx+1) =='}')
{
cattext(&out,"*/");
idx+=2;
}
else
{
catchar(&out, at(tos, idx));
idx++;
}
}
catchar(&out,'\n');
}
else
{
idx++;
}
}
overwrite_string(tos, &out);
pc++;
}
/* Find lines starting with . and | and put example around them on tos */
WORD(courierize)
{
string_type out;
unsigned int idx = 0;
int command = 0;
init_string(&out);
while (at(tos, idx))
{
if (at(tos, idx) == '\n'
&& (at(tos, idx +1 ) == '.'
|| at(tos,idx+1) == '|'))
{
cattext(&out,"\n@example\n");
do
{
idx += 2;
while (at(tos, idx) && at(tos, idx)!='\n')
{
if (at(tos,idx)=='{' && at(tos,idx+1) =='*')
{
cattext(&out," /*");
idx+=2;
}
else if (at(tos,idx)=='*' && at(tos,idx+1) =='}')
{
cattext(&out,"*/");
idx+=2;
}
else if (at(tos,idx) == '{' && !command)
{
cattext(&out,"@{");
idx++;
}
else if (at(tos,idx) == '}' && !command)
{
cattext(&out,"@}");
idx++;
}
else
{
if (at(tos,idx) == '@')
command = 1;
else if (isspace(at(tos,idx)) || at(tos,idx) == '}')
command = 0;
catchar(&out, at(tos, idx));
idx++;
}
}
catchar(&out,'\n');
}
while (at(tos, idx) == '\n'
&& (at(tos, idx+1) == '.')
|| (at(tos,idx+1) == '|'));
cattext(&out,"@end example");
}
else
{
catchar(&out, at(tos, idx));
idx++;
}
}
overwrite_string(tos, &out);
pc++;
}
/* Finds any lines starting with "o ", if there are any, then turns
on @itemize @bullet, and @items each of them. Then ends with @end
itemize, inplace at TOS*/
WORD(bulletize)
{
unsigned int idx = 0;
int on = 0;
string_type out;
init_string(&out);
while (at(tos, idx)) {
if (at(tos, idx) == '@' &&
at(tos, idx+1) == '*')
{
cattext(&out,"*");
idx+=2;
}
else
if (at(tos, idx) == '\n' &&
at(tos, idx+1) == 'o' &&
isspace(at(tos, idx +2)))
{
if (!on)
{
cattext(&out,"\n@itemize @bullet\n");
on = 1;
}
cattext(&out,"\n@item\n");
idx+=3;
}
else
{
catchar(&out, at(tos, idx));
if (on && at(tos, idx) == '\n' &&
at(tos, idx+1) == '\n' &&
at(tos, idx+2) != 'o')
{
cattext(&out, "@end itemize");
on = 0;
}
idx++;
}
}
if (on)
{
cattext(&out,"@end itemize\n");
}
delete_string(tos);
*tos = out;
pc++;
}
/* Turn <<foo>> into @code{foo} in place at TOS*/
WORD(do_fancy_stuff)
{
unsigned int idx = 0;
string_type out;
init_string(&out);
while (at(tos, idx))
{
if (at(tos, idx) == '<'
&& at(tos, idx+1) == '<'
&& !isspace(at(tos,idx + 2)))
{
/* This qualifies as a << startup */
idx +=2;
cattext(&out,"@code{");
while(at(tos,idx) &&
at(tos,idx) != '>' )
{
catchar(&out, at(tos, idx));
idx++;
}
cattext(&out,"}");
idx+=2;
}
else
{
catchar(&out, at(tos, idx));
idx++;
}
}
delete_string(tos);
*tos = out;
pc++;
}
/* A command is all upper case,and alone on a line */
static int
DEFUN( iscommand,(ptr, idx),
string_type *ptr AND
unsigned int idx)
{
unsigned int len = 0;
while (at(ptr,idx)) {
if (isupper(at(ptr,idx)) || at(ptr,idx) == ' ' ||
at(ptr,idx) == '_')
{
len++;
idx++;
}
else if(at(ptr,idx) == '\n')
{
if (len >4) return 1;
return 0;
}
else return 0;
}
return 0;
}
DEFUN(copy_past_newline,(ptr, idx, dst),
string_type *ptr AND
unsigned int idx AND
string_type *dst)
{
while (at(ptr, idx) && at(ptr, idx) != '\n')
{
catchar(dst, at(ptr, idx));
idx++;
}
catchar(dst, at(ptr, idx));
idx++;
return idx;
}
WORD(icopy_past_newline)
{
tos++;
init_string(tos);
idx = copy_past_newline(ptr, idx, tos);
pc++;
}
/* indent
Take the string at the top of the stack, do some prettying */
WORD(kill_bogus_lines)
{
int sl ;
int nl = 0;
int idx = 0;
int c;
int dot = 0 ;
string_type out;
init_string(&out);
/* Drop leading nl */
while (at(tos,idx) == '\n')
{
idx++;
}
c = idx;
/* Find the last char */
while (at(tos,idx))
{
idx++;
}
/* find the last non white before the nl */
idx--;
while (idx && isspace(at(tos,idx)))
idx--;
idx++;
/* Copy buffer upto last char, but blank lines before and after
dots don't count */
sl = 1;
while (c < idx)
{
if (at(tos,c) == '\n'
&& at(tos,c+1) == '\n'
&& at(tos,c+2) == '.')
{
/* Ignore two newlines before a dot*/
c++;
}
else if (at(tos,c) == '.' && sl)
{
/* remember that this line started with a dot */
dot=2;
}
else if (at(tos,c) == '\n'
&& at(tos,c+1) == '\n'
&& dot)
{
c++;
/* Ignore two newlines when last line was dot */
}
catchar(&out, at(tos,c));
if (at(tos,c) == '\n')
{
sl = 1;
if (dot == 2)dot=1;else dot = 0;
}
c++;
}
/* Append nl*/
catchar(&out, '\n');
pc++;
delete_string(tos);
*tos = out;
}
WORD(indent)
{
string_type out;
int tab = 0;
int idx = 0;
int ol =0;
init_string(&out);
while (at(tos,idx)) {
switch (at(tos,idx))
{
case '\n':
cattext(&out,"\n");
idx++;
if (tab)
{
cattext(&out," ");
}
ol = 0;
break;
case '(':
tab++;
if (ol == 0)
cattext(&out," ");
idx++;
cattext(&out,"(");
ol = 1;
break;
case ')':
tab--;
cattext(&out,")");
idx++;
ol=1;
break;
default:
catchar(&out,at(tos,idx));
ol=1;
idx++;
break;
}
}
pc++;
delete_string(tos);
*tos = out;
}
WORD(get_stuff_in_command)
{
tos++;
init_string(tos);
while (at(ptr, idx)) {
if (iscommand(ptr, idx)) break;
idx = copy_past_newline(ptr, idx, tos);
}
pc++;
}
WORD(swap)
{
string_type t;
t = tos[0];
tos[0] = tos[-1];
tos[-1] =t;
pc++;
}
WORD(other_dup)
{
tos++;
init_string(tos);
catstr(tos, tos-1);
pc++;
}
WORD(icatstr)
{
catstr(tos-1, tos);
delete_string(tos);
tos--;
pc++;
}
WORD(skip_past_newline)
{
while (at(ptr,idx)
&& at(ptr,idx) != '\n')
idx++;
idx++;
pc++;
}
WORD(internalmode)
{
internal_mode = *(isp);
isp--;
pc++;
}
WORD(maybecatstr)
{
if (internal_wanted == internal_mode)
{
catstr(tos-1, tos);
}
delete_string(tos);
tos--;
pc++;
}
char *
DEFUN(nextword,(string, word),
char *string AND
char **word)
{
char *word_start;
int idx;
char *dst;
char *src;
int length = 0;
while (isspace(*string) || *string == '-') {
if (*string == '-')
{
while (*string && *string != '\n')
string++;
}
else {
string++;
}
}
if (!*string) return 0;
word_start = string;
if (*string == '"')
{
string++;
length++;
while (*string != '"')
{
string++;
length++;
}
}
else
{
while (!isspace(*string))
{
string++;
length++;
}
}
*word = malloc(length + 1);
dst = *word;
src = word_start;
for (idx= 0; idx < length; idx++)
{
if (src[idx] == '\\' && src[idx+1] == 'n')
{
*dst++ = '\n';
idx++;
}
else *dst++ = src[idx];
}
*dst++ = 0;
if(*string)
return string + 1;
else
return 0;
}
dict_type *root;
dict_type *
DEFUN(lookup_word,(word),
char *word)
{
dict_type *ptr = root;
while (ptr) {
if (strcmp(ptr->word, word) == 0) return ptr;
ptr = ptr->next;
}
if (warning)
fprintf(stderr,"Can't find %s\n",word);
return 0;
}
static void DEFUN_VOID(perform)
{
tos = stack;
while (at(ptr, idx)) {
/* It's worth looking through the command list */
if (iscommand(ptr, idx))
{
unsigned int i;
int found = 0;
char *next;
dict_type *word ;
(void) nextword(addr(ptr, idx), &next);
word = lookup_word(next);
if (word)
{
exec(word);
}
else
{
if (warning)
fprintf(stderr,"warning, %s is not recognised\n", next);
skip_past_newline();
}
}
else skip_past_newline();
}
}
dict_type *
DEFUN(newentry,(word),
char *word)
{
dict_type *new = (dict_type *)malloc(sizeof(dict_type));
new->word = word;
new->next = root;
root = new;
new->code = (stinst_type *)malloc(sizeof(stinst_type ));
new->code_length = 1;
new->code_end = 0;
return new;
}
unsigned int
DEFUN(add_to_definition,(entry, word),
dict_type *entry AND
stinst_type word)
{
if (entry->code_end == entry->code_length)
{
entry->code_length += 2;
entry->code =
(stinst_type *) realloc((char *)(entry->code),
entry->code_length *sizeof(word_type));
}
entry->code[entry->code_end] = word;
return entry->code_end++;
}
void
DEFUN(add_intrinsic,(name, func),
char *name AND
void (*func)())
{
dict_type *new = newentry(name);
add_to_definition(new, func);
add_to_definition(new, 0);
}
WORD(push_addr)
{
}
void
DEFUN(add_var,(name),
char *name)
{
dict_type *new = newentry(name);
add_to_definition(new, push_number);
add_to_definition(new, (stinst_type)(&(new->var)));
add_to_definition(new,0);
}
void
DEFUN(compile, (string),
char *string)
{
int jstack[STACK];
int *jptr = jstack;
/* add words to the dictionary */
char *word;
string = nextword(string, &word);
while (string && *string && word[0])
{
if (strcmp(word,"var")==0)
{
string=nextword(string, &word);
add_var(word);
string=nextword(string, &word);
}
else
if (word[0] == ':')
{
dict_type *ptr;
/* Compile a word and add to dictionary */
string = nextword(string, &word);
ptr = newentry(word);
string = nextword(string, &word);
while (word[0] != ';' )
{
switch (word[0])
{
case '"':
/* got a string, embed magic push string
function */
add_to_definition(ptr, push_text);
add_to_definition(ptr, (stinst_type)(word+1));
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* Got a number, embedd the magic push number
function */
add_to_definition(ptr, push_number);
add_to_definition(ptr, (stinst_type)atol(word));
break;
default:
add_to_definition(ptr, call);
add_to_definition(ptr, (stinst_type)lookup_word(word));
}
string = nextword(string, &word);
}
add_to_definition(ptr,0);
string = nextword(string, &word);
}
else
{
fprintf(stderr,"syntax error at %s\n",string-1);
}
}
}
static void DEFUN_VOID(bang)
{
*(int *)((isp[0])) = isp[-1];
isp-=2;
pc++;
}
WORD(atsign)
{
isp[0] = *(int *)(isp[0]);
pc++;
}
WORD(hello)
{
printf("hello\n");
pc++;
}
static void DEFUN(read_in, (str, file),
string_type *str AND
FILE *file)
{
char buff[10000];
unsigned int r;
do
{
r = fread(buff, 1, sizeof(buff), file);
catbuf(str, buff, r);
}
while (r);
buff[0] = 0;
catbuf(str, buff,1);
}
static void DEFUN_VOID(usage)
{
fprintf(stderr,"usage: -[d|i|g] <file >file\n");
exit(33);
}
/* There is no reliable way to declare exit. Sometimes it returns
int, and sometimes it returns void. Sometimes it changes between
OS releases. Trying to get it declared correctly in the hosts file
is a pointless waste of time. */
static void
chew_exit ()
{
exit (0);
}
int DEFUN(main,(ac,av),
int ac AND
char *av[])
{
unsigned int i;
string_type buffer;
string_type pptr;
init_string(&buffer);
init_string(&pptr);
init_string(stack+0);
tos=stack+1;
ptr = &pptr;
add_intrinsic("push_text", push_text);
add_intrinsic("!", bang);
add_intrinsic("@", atsign);
add_intrinsic("hello",hello);
add_intrinsic("skip_past_newline", skip_past_newline );
add_intrinsic("catstr", icatstr );
add_intrinsic("copy_past_newline", icopy_past_newline );
add_intrinsic("dup", other_dup );
add_intrinsic("remchar", remchar );
add_intrinsic("get_stuff_in_command", get_stuff_in_command );
add_intrinsic("do_fancy_stuff", do_fancy_stuff );
add_intrinsic("bulletize", bulletize );
add_intrinsic("courierize", courierize );
/* If the following line gives an error, exit() is not declared in the
../hosts/foo.h file for this host. Fix it there, not here! */
/* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
add_intrinsic("exit", chew_exit );
add_intrinsic("swap", swap );
add_intrinsic("outputdots", outputdots );
add_intrinsic("paramstuff", paramstuff );
add_intrinsic("maybecatstr", maybecatstr );
add_intrinsic("translatecomments", translatecomments );
add_intrinsic("kill_bogus_lines", kill_bogus_lines);
add_intrinsic("indent", indent);
add_intrinsic("internalmode", internalmode);
/* Put a nl at the start */
catchar(&buffer,'\n');
read_in(&buffer, stdin);
remove_noncomments(&buffer, ptr);
for (i= 1; i < ac; i++)
{
if (av[i][0] == '-')
{
if (av[i][1] == 'f')
{
string_type b;
FILE *f;
init_string(&b);
f = fopen(av[i+1],"r");
if (!f)
{
fprintf(stderr,"Can't open the input file %s\n",av[i+1]);
return 33;
}
read_in(&b, f);
compile(b.ptr);
perform();
}
else if (av[i][1] == 'i')
{
internal_wanted = 1;
}
else if (av[i][1] == 'w')
{
warning = 1;
}
}
}
write_buffer(stack+0);
return 0;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.