V10/cmd/docgen/docgen.c
/**********
docgen.c
(091984 version: from llc 080284; minor changes by vbt)
modify *mmfile, *msfile, and *mcfile strings as needed to supply
full pathnames for mmdata, msdata, and mcsdata files;
**********/
#include <stdio.h>
#include <signal.h>
char *mmfile="/usr/lib/docgen/mmdata";
char *msfile="/usr/lib/docgen/msdata";
char *mcfile="/usr/lib/docgen/mcsdata";
char *wr = "/usr/lib/docgen/wr";
#define eatblanks(a) while((c=getc(a)) == ' '|| c == '\t')
#define MAX 100
#define CMAX 7500
#define LMAX 200
#define QMAX 100
#define NPATH 10
#define NENT 200
#define BUFS 512
#define LABMAX 20
#define STACK 10
#define NEST 10
int inap;
int debug = 0;
int sdebug = 0;
int verbose = 0;
#define ARGS 1
#define ONELINE 2
#define MANY 4
#define OUT 8
#define PRINT 16
#define SKIP 32
#define BLOOP 128
#define PATH 256
#define QUEST 512
#define STUFF 1024
#define NAME 2048
#define SUM 4096
#define PAR 8192
#define FLOOP 16384
#define SEVERAL 32768
#define QSTUFF 65536
struct q_a {
char *qtext;
char *text;
char *macro;
unsigned long type;
struct qa *argq;
} s[MAX];
struct q_a *p = s;
unsigned long gettype();
int sig_in_ed();
char buf[CMAX];
char *ptr = buf;
char obuf[BUFS];
char *optr = obuf;
FILE *outp;
char *ofile;
char line[LMAX];
char sline[LMAX];
char *first;
int lineno = 1;
struct qa {
char *text;
struct qa *nexta;
} ques[QMAX];
struct qa *qp = ques;
struct pa {
char *name;
struct list *root;
} paths[NPATH];
struct pa *pp = paths;
struct list {
struct q_a *entry;
struct list *next;
struct list *loop;
char *quest;
struct list *floop;
} list[NENT];
struct list *lp = list;
struct list *stack[STACK];
struct list **st = stack;
struct pa *findpath();
struct lab {
struct list *path;
struct list *place;
} save[LABMAX], *sav=save;
struct lab *savp;
struct lab *savc[10];
unsigned stype[10];
int curly = 0;
char *onepath;
char *qfile;
char *namesf="tagfile";
char nname[50];
FILE *popen(), *edp;
main(argc,argv)
int argc;
char *argv[];
{
qfile = mcfile;
while(argc > 1 && *argv[1] == '-'){
switch(argv[1][1]){
case 'f':
if(argc > 2)qfile=argv[2];
argc--;
argv++;
break;
case 'm':
if(argv[1][2] == 's')qfile=msfile;
else if(argv[1][2] == 'c')qfile=mcfile;
else if(argv[1][2] == 'm')qfile=mmfile;
else {
fprintf("unknown macro package %s\n",argv);
exit(0);
}
break;
case 'w':
qfile = wr;
break;
case 'd':
sdebug=1;
break;
case 'p':
debug=1;
break;
case 'v':
verbose=1;
break;
default:
fprintf(stderr,"unknown flag %c\n",argv[1][1]);
exit(0);
}
argc--; argv++;
}
if(argc > 1)ofile=argv[1];
init(qfile);
if(onepath != 0){
pp=findpath(onepath);
lp=pp->root;
process(1);
}
else process(0);
done();
}
init(file)
char *file;
{
FILE *inp;
int c;
int i;
int printall=0;
char command[50];
FILE *dumb;
if(ofile == 0){
if(file == wr){
printf("Tags going to file tagfile\n");
ofile = namesf;
}
else if(file == mcfile){
printf("Output going to file temp.cover\n");
ofile = "temp.cover";
}
else {
printf("Output going to file temp\n");
ofile = "temp";
}
}
if((inp=fopen(file,"r"))==NULL){
fprintf(stderr,"can't open script file %s\n",file);
exit(0);
}
pp->name = onepath = ptr;
i=0;
while((c=getc(inp)) != '\n'){
if(c == ','){
*ptr++ = '\0';
(++pp)->name = ptr;
i++;
if(pp > &paths[NPATH-1])
error("more than 10 paths-NPATH");
}
else if(c != ' ' && c != '\t')
*ptr++ = c;
}
*ptr++ = '\0';
if(i > 0)onepath=0;
lineno++;
first = ptr;
if(getstr(inp)== 0)
if(onepath == 0)
error("text string expected");
while(getentry(inp) != 0){
if(p++ >= &s[MAX-1])
error("number of instructions exceeded-MAX");
}
if(debug)printf("\n");
if((dumb = fopen(ofile,"r")) != NULL){
if(file == wr){
printf("File %s already exists; Tags will be appended\n",ofile);
printall++;
}
else {
printf("File %s already exists; Text will be appended\n",ofile);
}
fclose(dumb);
}
if((dumb = fopen(ofile,"a")) == NULL){
fprintf(stderr,"can't open %s\n",ofile);
exit(1);
}
fclose(dumb);
sprintf(command,"ed - %s\n",ofile);
signal(SIGINT,sig_in_ed);
if((edp = popen(command,"w")) == NULL){
printf("can't involk ed\n");
exit(0);
}
setbuf(edp,NULL);
if(printall){
printf("The following tags are already defined:\n");
fputs("1,$p\n",edp);
fflush(edp);
sleep(8);
printf("\n");
}
fputs("a\n",edp);
inap = 1;
}
getentry(inp)
FILE *inp;
{
char *l;
int c;
int comment = 0;
if(debug)printf("\n place %o ",p);
savp = sav;
l = line;
while((*l = c = getc(inp)) != ':'){
if(c == EOF)return(0);
if(c == '*'){
if(comment){
comment=0;
continue;
}
else {
comment=1;
continue;
}
}
if(comment){
if(c == '\n')lineno++;
continue;
}
if(c == '\\'){
*l = getc(inp);
if(++l >= &line[LMAX-1])
error("line length exceeded-LMAX");
continue;
}
if(c == '}'){
if(debug)printf("found }\n");
l=ptr;
getstr(inp);
addloop(--curly,l);
eatline(inp);
sav = savc[curly];
p->type = BLOOP;
return(1);
}
if(c == ','){
*l = '\0';
addentry(line,p);
l=line;
}
else if(c == '\n'){
l=line;
lineno++;
}
else if(c != ' ' && c != '\t'){
if(l++ >= &line[LMAX-1])
error("line length exceeded-LMAX");
}
}
*l = '\0';
addentry(line,p);
p->macro = ptr;
while((*ptr = c = getc(inp))!= ':'){
if(c == '\\'){
*ptr = getc(inp);
if(++ptr >= &buf[CMAX-1])
error("string buffer exceeded-CMAX");
}
else if(c == ' ' && ptr == p->macro);
else if(c == '{' && ptr == p->macro){
if(debug)printf("in { savp %o\n",savp);
(sav++)->path = 0;
stype[curly] = BLOOP;
savc[curly++] = savp;
if(curly >= NEST)
error("nesting depth exceeded-NEST");
if((c = getc(inp)) == ' '|| c == '\t')
eatblanks(inp);
if(c == '\n'){
lineno++;
if((c = getc(inp)) == ' '|| c == '\t')
eatblanks(inp);
}
if(c == '"'){
p->type = FLOOP;
ungetc(c,inp);
l=ptr;
getstr(inp);
p->qtext = l;
stype[curly-1] = FLOOP;
}
else {
ungetc(c,inp);
p->type = BLOOP;
}
return(1);
}
else if(ptr++ >= &buf[CMAX-1])
error("string buffer exceeded-CMAX");
}
if(p->macro == ptr)p->macro=0;
else *ptr++ = '\0';
p->type = gettype(inp);
if(p->type&QUEST){
p->qtext = ptr;
if(getstr(inp) == 0)
error("text string expected");
}
else p->qtext = 0;
p->text = ptr;
if(p->type&(ONELINE|SEVERAL|PRINT|MANY|PATH))
if(getstr(inp)== 0)
error("text string expected");
if(p->text == ptr)p->text = 0;
if(debug)printf(" macro %s type %d text %s ",p->macro,p->type,p->text);
if(sdebug)db(p);
if(p->type & (ARGS |SKIP)){
p->argq = qp;
qp->text = ptr;
while(getstr(inp) != 0){
qp->nexta = (qp+1);
if(debug||sdebug)printf("\n arg question= %s",qp->text);
if(debug)printf(" next %o",qp->nexta);
if(qp++ >= &ques[QMAX-1])
error("number of questions exceeded-QMAX");
qp->text = ptr;
}
(qp-1)->nexta = 0;
if(debug)printf("\n last %s next %o",(qp-1)->text,(qp-1)->nexta);
if(sdebug)printf("\n");
}
sav = savp;
return(1);
}
getstr(inp)
FILE *inp;
{
int c;
while((c=getc(inp)) == ' ' || c == '\t' || c == '\n')if(c == '\n')lineno++;
if(c != '\"'){
ungetc(c,inp);
return(0);
}
while((*ptr=c=getc(inp)) != '\"'){
if(ptr++ >= &buf[CMAX])
error("string buffer exceeded-CMAX");
if(c == '\n')lineno++;
}
*ptr++ = '\0';
return(1);
}
addentry(ch,p)
char *ch;
struct q_a *p;
{
struct list *ll;
if(debug || sdebug)printf("path= %s, ",ch);
for(pp=paths;pp->name != 0 && pp < &paths[NPATH];pp++){
if(match(ch,pp->name)){
if(pp->root == 0){
pp->root = lp;
}
else {
ll=pp->root;
while(ll->next != 0)ll=ll->next;
ll->next = lp;
}
if(debug)printf("entry %o path %o\n",lp,pp);
sav->path = (struct list *)pp;
sav->place = lp;
lp->entry = p;
if(lp++ >= &list[NENT-1])
error("tree exceeded-NENT");
if(sav++ >= &save[LABMAX-1])
error("saved paths exceeded-LABMAX");
return;
}
}
printf("no path to %s\n",ch);
exit(0);
}
addloop(in,cp)
char *cp;
{
struct lab *sp;
struct list *ll;
sp = savc[in];
while((ll = sp->path) != 0){
if(debug)printf("addloop sp %o path %o",sp,sp->path);
while(ll->next != 0){
ll=ll->next;
}
if(debug)printf("ll %o place %o\n",ll,sp->place);
if(ll->loop != 0){
ll->next = lp;
lp->loop = sp->place;
lp->quest = cp;
lp->entry = p;
if(lp++ >= &list[NENT-1])
error("tree exceeded - NENT");
}
else {
ll->loop = sp->place;
ll->quest = cp;
}
if(stype[in] == FLOOP){
sp->place->floop = lp;
lp->entry = p;
if(lp++ >= &list[NENT-1])
error("tree exceeded - NENT");
}
sp++;
}
}
unsigned long
gettype(inp)
FILE *inp;
{
int c;
unsigned long i;
i=0;
another:
while((c=getc(inp)) == ' ' || c == '\t');
switch(c){
case 'A':
i |= ARGS;
break;
case 'M':
i |= MANY;
break;
case 'O':
if((c=getc(inp)) == 'U')
i |= OUT;
else if(c == 'N')
i|= ONELINE;
else error("unknown action");
break;
case 'P':
if((c=getc(inp)) == 'R')
i |= PRINT;
else if(c == 'A'){
if((c=getc(inp)) == 'T')
i |= PATH;
else if(c == 'R')
i |= PAR|MANY;
else error("unknown action");
}
else error("unknown action");
break;
case 'S':
if((c=getc(inp)) == 'T')
i |= STUFF|ARGS;
else if(c == 'K')
i |= SKIP;
else if(c == 'U')
i |= SUM|MANY;
else if(c == 'E')
i |= SEVERAL;
else error("unknown action");
break;
case 'Q':
if((c=getc(inp)) == 'U')
i |= QUEST;
else if(c == 'S')
i |= QSTUFF|ARGS;
else error("unknown action");
break;
case 'N':
i |= NAME|ONELINE;
break;
default:
error("unknown action");
}
while((c=getc(inp))!= '\n')
if(c == '&')goto another;
lineno++;
if(i&OUT)
if(i & ~OUT){
if(i & ~(OUT|QUEST))
error("action error - OUT not alone");
}
if(i & PRINT)
if(i & ~PRINT){
if(i & ~(PRINT|QUEST))
error("action error - PRINT not alone");
}
if(i & PATH)
if(i & ~PATH)error("action error - PATH not alone");
if((i&(MANY|ONELINE))==(MANY|ONELINE))
error("contridictory actions - MANY & ONELINE");
return(i);
}
process(start)
int start;
{
if(start == 0){
printf("%s\n",first);
getl(stdin,line);
pp=findpath(line);
lp = pp->root;
}
more:
while(lp){
if(question(lp->entry)== 1)
continue;
if(lp->loop != 0){
printf("%s\n",lp->quest);
getl(stdin,line);
if(line[0] == 'y'|| line[0] == 'Y')
lp=lp->loop;
else{
if(lp->loop->entry->type & 1){
lp->loop->entry->type &= 0177776;
}
if(line[0] == 'q')done();
else lp=lp->next;
}
}
else
lp = lp->next;
}
if(*st != 0){
lp = *st--;
if(lp->loop != 0){
printf("%s\n",lp->quest);
getl(stdin,line);
if(line[0] == 'y' || line[0] == 'Y')
lp=lp->loop;
else{
if(lp->loop->entry->type & 1)
lp->loop->entry->type &= 0177776;
if(line[0] == 'q')done();
else lp=lp->next;
}
}
else lp=lp->next;
goto more;
}
}
question(rp)
struct q_a *rp;
{
int blanks;
char *ch, *sv;
rest:
if(debug)printf("in question %o\n",rp);
if(rp->type & BLOOP)
return(0);
if(rp->type & FLOOP){
if(rp->type & 1)return(0);
printf("%s\n",rp->qtext);
getl(stdin,line);
if(line[0] == 'y' || line[0] == 'Y'){
lp = lp->next;
rp->type |= 1;
}
else if(line[0] == 'q')done();
else lp= lp->floop;
return(1);
}
if(rp->type & PATH){
*(++st) = lp;
if(st >= &stack[STACK-1])
error("stack depth exceeded-STACK");
printf("%s\n",rp->text);
getl(stdin,line);
if(line[0] == '\0'){
st--;
return(0);
}
pp=findpath(line);
lp = pp->root;
return(1);
}
if(rp->type&QUEST){
printf("%s\n",rp->qtext);
getl(stdin,line);
if(line[0] != 'Y' && line[0] != 'y')return(0);
}
if(rp->text != 0)
if((rp->type&MANY) == 0)printf("%s\n",rp->text);
if(rp->type&(ONELINE|SEVERAL))
getl(stdin,sline);
if(rp->type&NAME){
return(newname(sline));
}
if(rp->type&SUM){
summary();
}
if(rp->type&PAR){
par();
}
if(rp->type&(STUFF|QSTUFF)){
sv = ch = rp->macro;
qp = rp->argq;
do{
while(*ch != '$'){
if(*ch == '\\')ch++;
if(*ch == '\0')break;
ch++;
}
if(*ch == '$'){
*ch = '\0';
out(sv);
*ch++ = '$';
sv = ch;
}
printf("%s\n",qp->text);
getl(stdin,line);
if(rp->type&QSTUFF)
if(line[0] == '\0')break;
if(*(ch-1) == '$')
out(line);
qp = qp->nexta;
} while(qp != 0);
if(rp->type&STUFF)
out(sv);
else if(*sv == '"')out("\"");
out("\n");
}
else if(rp->type&(ARGS | SKIP)){
if((rp->type&SKIP) == 0 && rp->macro != 0)
out(rp->macro);
qp = rp->argq;
do{
printf("%s\n",qp->text);
blanks = getl(stdin,line);
if(rp->type&SKIP){
if(line[0] == '\0')
return(0);
else out(rp->macro);
}
out(" ");
if(line[0] == '\0')blanks++;
if(blanks)out("\"");
out(line);
if(blanks)out("\"");
qp=qp->nexta;
} while(qp != 0);
out("\n");
}
else if((rp->type&(OUT|ONELINE|MANY))&& rp->macro != 0){
out(rp->macro);
out("\n");
}
if(rp->type&SEVERAL){
out(rp->macro);
out(" ");
out(sline);
out("\n");
}
if(rp->type&ONELINE){
out(sline);
out("\n");
}
if(rp->type&MANY){
if(rp->type&(SUM))
printf("%s named %s.sum\n",rp->text,nname);
else if(rp->type&PAR)
printf("%s named %s.par\n",rp->text,nname);
else printf("%s\n",rp->text);
printf(" end with : alone on a line (or read a file with :r filename)\n");
getl(stdin,line);
if(line[0] == ':' && line[1] == 'r'){
ch = &line[2];
more:
readfiles(ch);
printf("Type other file names or return\n");
getl(stdin,line);
if(line[0] == '\0')return(0);
ch = line;
goto more;
}
toed();
}
return(0);
}
sig_in_ed(){
inap = 0;
printf("type q to quit ");
getl(stdin,line);
if(line[0] == 'q')done();
fputs("a\n",edp);
optr = obuf;
inap=1;
signal(SIGINT,sig_in_ed);
process(1);
done();
}
getl(inp,l)
char *l;
FILE *inp;
{
int c;
int blanks;
blanks=0;
while((*l = c = getc(inp)) != '\n'){
l++;
if(c == ' ' || c == '\t')blanks++;
}
*l++ = 0;
return(blanks);
}
out(ch)
char *ch;
{
char c;
while(*ch != '\0'){
if(*ch == '\n'){
*optr++ = *ch++;
*optr = '\0';
fputs(obuf,edp);
optr=obuf;
if(verbose)printf("%s",obuf);
}
else *optr++ = *ch++;
if(optr >= &obuf[BUFS-1]){
*optr = '\0';
fputs(obuf,edp);
optr = obuf;
}
}
}
ofl()
{
if(optr != obuf){
*optr='\0';
fputs(obuf,edp);
optr=obuf;
}
if(inap)
fputs(".\nw\na\n",edp);
else {
fputs("w\na\n",edp);
inap=1;
}
}
done(){
ofl();
fputs(".\nq\n",edp);
exit(0);
}
match(ch,hh)
char *ch, *hh;
{
while(*ch == *hh){
if(*ch == '\0')return(1);
ch++;
hh++;
}
return(0);
}
struct pa *
findpath(ch)
char *ch;
{
for(pp=paths;pp->name != 0;pp++){
if(match(ch,pp->name))
return(pp);
}
printf("can't find path for %s\n",ch);
exit(0);
}
eatline(inp)
FILE *inp;
{
while(getc(inp) != '\n');
lineno++;
}
readfiles(ptr)
char *ptr;
{
FILE *io;
int nomore;
char *bp;
char fname[50];
ofl();
fputs(".\n",edp);
nomore = 0;
while(1){
while(*ptr == ' ')ptr++;
bp = ptr;
while(*ptr != ' ' && *ptr != '\0')ptr++;
if(*ptr == '\0')nomore++;
else *ptr++ = '\0';
sprintf(fname,"$r %s\n",bp);
fputs(fname,edp);
if(nomore != 0)break;
}
fputs("a\n",edp);
}
error(sp)
char *sp;
{
fprintf(stderr,"%s at line %d file %s\n",sp,lineno,qfile);
exit(1);
}
db(dbp)
struct q_a *dbp;
{
printf(" macro= %s type=",dbp->macro);
if(dbp->type&ARGS)printf(" ARGS");
if(dbp->type&SKIP)printf(" SKIP");
if(dbp->type&OUT)printf(" OUT");
if(dbp->type&PRINT)printf(" PRINT");
if(dbp->type&ONELINE)printf(" ONELINE");
if(dbp->type&SEVERAL)printf(" SEVERAL");
if(dbp->type&MANY)printf(" MANY");
if(dbp->type&PATH)printf(" PATH");
if(dbp->text != 0)printf("\nmain text= %s\n",dbp->text);
else printf("\n");
}
newname(s)
char *s;
{
int i;
char *name1, *name2;
int pid, rpid, retcode;
char *sp,spac[10];
restart:
sp = spac;
*sp = '\0';
if(*s == ' ' || *s == '\t')
while(*s== ' ' || *s == '\t')*sp++ = *s++;
*sp = '\0';
for(i=0;*s != '\0';i++)
nname[i] = *s++;
if(nname[0] == ':'){
switch(nname[1]){
case 'p':
sprintf(line,".\nw\ne %s\n1,$p\na\n",ofile);
fputs(line,edp);
sleep(8);
return(1);
case 'r':
sprintf(line,".\nw\ne %s\na\n",&nname[3]);
printf("Type text to append to file %s\n",&nname[3]);
fputs(line,edp);
getl(stdin,line);
toed();
return(1);
case 'j':
name1=0;
name2 = nname;
nextn:
for(; *name2 != ' ';name2++)
if(*name2 == '\0'){
printf("error in command line: %s\nplease retype\n",nname);
getl(stdin,sline);
s=sline;
goto restart;
}
*name2++ = '\0';
while(*name2 == ' ')name2++;
if(name1 == 0){
name1 = name2;
goto nextn;
}
sprintf(line,".\nw\ne %s.sum\n$r %s.sum\nw\n",name1,name2);
fputs(line,edp);
sprintf(line,"e %s.par\n$r %s.par\nw\n",name1,name2);
fputs(line,edp);
sprintf(line,"e %s\n/%s/d\nw\na\n",ofile);
fputs(line,edp);
return(1);
default:
printf("unknown command %s\n",nname);
printf("please retype\n");
goto restart;
}
}
if(nname[0] == '!'){
if((pid = fork()) == 0){
execl("/bin/sh","sh","-c",&nname[1],0);
exit(0);
}
while((rpid=wait(&retcode))!=pid&& rpid != -1);
printf("!\n");
return(1);
}
if(i > 10){
printf("tag too long - please type new tag ");
getl(stdin,sline);
s=sline;
goto restart;
}
nname[i] = '\0';
sprintf(line, ".\nw\ne %s\na\n%s%s\n",ofile,spac,nname);
fputs(line,edp);
return(0);
}
summary(){
FILE *ff;
sprintf(line,"%s.sum",nname);
if((ff = fopen(line,"a")) == NULL){
printf("can't open %s\n",line);
}
sprintf(line,".\nw\ne %s.sum\na\n",nname);
fputs(line,edp);
fclose(ff);
}
par(){
FILE *ff;
sprintf(line,"%s.par",nname);
if((ff=fopen(line,"a")) == NULL){
printf("can't open %s\n",line);
exit(1);
}
sprintf(line,".\nw\ne %s.par\na\n",nname);
fputs(line,edp);
fclose(ff);
}
toed(){
while(1){
if(line[1] == '\0'){
switch(line[0]){
case 'i':
case 'a':
case 'c':
inap++;
break;
case '.':
inap = 0;
break;
case 'q':
if(inap != 0)break;
case ':':
if(inap == 0){fputs("a\n",edp);
inap++;
}
return(0);
}
}
fputs(line,edp);
fputs("\n",edp);
getl(stdin,line);
}
}