union mix
{
struct labelnode *pointer;
int value;
};
struct labelnode
{
struct labelnode *next;
union mix labels ;
char text[maxtag];
};
char block[maxtag] ;
char *infile,*outfile;
int change,verbose,exits,printtext,labels,tags,silent,checking,printchanges;
int tagsout,noline,deutsch,include_input;
FILE *input,*output;
int exitcode;
char *pos;
int line,column,pass,end;
struct labelnode *groups;
/* *** next *** */
char next(void) /* get next text position */
{
char c;
int k;
c=*pos++;
if (c=='\n')
{
if (noline&&(lb[0]=='\n')) {}
else if (change&&(pass==2)) fputs(lb,output);
if (fgets(lb,lmax,input)==0)
{
end=1;
return(0);
}
noline=0;
pos=lb;
k=strlen(lb);
if (k==0 || lb[k-1]!='\n')
{
lb[k]='\n';
lb[k+1]=0;
}
c='\n';
}
if (printtext) printf("%c",c);
column+=1;
return(c);
}
/* *** various supporting functions *** */
void skip(int l) /* skip l characters */
{
int i;
if (l>0)
for (i=0;i<l;i++) next();
}
int scannumber(void) /* scan text for an integer */
{
int sign=0,n=0;
if (*pos=='-') {
sign=1;
next();
}
if (!(isdigit(*pos)))
{
printf("\nIllegal Number");
error();
}
while (isdigit(*pos))
{
n=n*10+(*pos)-'0';
next();
}
if (sign) return(-n);
else return(n);
}
void putcommand(char *a,int *l)
/* puts a word at pos to a and its length to l */
{
char *p;
p=pos;
*l=0;
if (isalpha(*p))
{
do {
*a++=*p++;
(*l)++;
} while((isalpha(*p))&&(*l<50));
*a=0;
}
else
{
*a++=*p;
*a=0;
*l=1;
}
}
void show(char *text) /* print text, if verbose is on */
{
if ((verbose)&&(!printtext)) printf("%s",text);
}
/* *** find and scanfor *** */
int find(char *text) /* advance in the file, starting from pos.
if text="", find end of file, else stop at text
if text found, return 1, else 0.*/
{
int l;
void advance(void) ;
l=strlen(text);
do
{
if (l>0)
if (strncmp(pos,text,l)==0) {
skip(l);
return(1);
}
advance();
} while (!end);
return(0);
}
void scanfor(char *text) /* scan till text appears */
{
if(!(find(text))) {
printf("\n%s missing",text);
error();
}
}
/* *** subroutines for german syntax *** */
void umlaut(char a)
{
int lbl;
char repl[3];
if (deutsch&&(pass==2))
{
pos=pos-1;
repl[0]='\\';
repl[1]='"';
repl[2]=a;
lbl=strlen(lb)+1;
if (lbl+3>=lmax)
{
printf("\nLine buffer overflow");
error();
exit(exitcode);
}
memmove(pos+2,pos,lbl-(int)(pos-lb));
memmove(pos,repl,3);
};
}
void szet(void)
{
int lbl;
char repl[5];
if (deutsch&&(pass==2))
{
pos=pos-1;
repl[0]='{';
repl[1]='\\';
repl[2]='s';
repl[3]='s';
repl[4]='}';
lbl=strlen(lb)+1;
if (lbl+5>=lmax)
{
printf("\nLine buffer overflow");
error();
exit(exitcode);
}
memmove(pos+4,pos,lbl-(int)(pos-lb));
memmove(pos,repl,5);
};
}
/* *** label handling commands *** */
struct labelnode *findlast(struct labelnode *r)
/* find the last label in a list */
{
if (r==0) return(0);
while (r->next!=0) {
r=r->next;
};
return(r);
}
struct labelnode *findnode(struct labelnode *r,char *label)
/* scan a list of labels for label */
{
if (r==0) return(0);
while (strcmp(label,r->text)!=0)
{
if (r->next==0) return(0);
r=r->next;
}
return(r);
}
struct labelnode *findlabel(char *group,char *label)
/* find a label in label list, return label */
{
struct labelnode *r,*findnode();
if ((r=findnode(groups,group))==0) return(0);
r=r->labels.pointer;
while (r!=0)
{
if (strcmp(label,r->text)==0) return(r);
r=r->next;
}
return(0);
}
struct labelnode *newnode(struct labelnode *r,char *label)
/* connects a new label to r */
{
struct labelnode *new;
new=(struct labelnode *)malloc(sizeof(struct labelnode));
if (new==0)
{
printf("\nNo more space for labels");
error();
exit(exitcode);
};
if (r!=0) r->next=new;
new->next=0;
new->labels.pointer=0;
memmove(new->text,label,16);
return(new);
}
int newvalue(char *group)
/* find the next number in group */
{
int count=1;
struct labelnode *r;
if ((r=findnode(groups,group))==0) return(count);
r=r->labels.pointer;
while (r!=0) {
count=r->labels.value;
r=r->next;
}
return(count+1);
}
void correctlabel(char *group,char *label,char *p1,char *p2)
/* remove p1-p2 from text and add
corresponding number */
{
int n,l,lbl,flag;
struct labelnode *r;
char string[12];
if (strcmp(group,"block")!=0)
{
flag=1;
if ((r=findlabel(group,label))==0)
{
printf("\nLabel %s.%s not defined",group,label);
error();
n=0;
}
else n=r->labels.value;
}
else
{
flag=0;
noline=1;
}
if (change)
{
if (flag) sprintf(string,"%d",n);
else string[0]=0;
l=strlen(string);
lbl=strlen(lb)+1;
if (lbl+l-(int)(p2-p1)>=lmax)
{
printf("\nLine buffer overflow");
error();
exit(exitcode);
}
memmove(p1+l,p2,lbl-(int)(p2-lb));
memmove(p1,string,l);
if (printchanges&&flag)
printf("\n%s.%s changed to %d",group,label,n);
pos+=l-(int)(p2-p1);
}
}
void printlabels(void) /* print all used labels */
{
struct labelnode *g,*l;
printf("\nUsed Labels and Tags : ");
g=groups;
while (g!=0)
{
l=g->labels.pointer;
while (l!=0)
{
printf("\n%s.%s = %d",g->text,l->text,l->labels.value);
l=l->next;
}
g=g->next;
}
}
void outlabels(void) /* print all used labels */
{
struct labelnode *g,*l;
void outopen(char *) ;
outopen(outfile);
g=groups;
while (g!=0)
{
l=g->labels.pointer;
while (l!=0)
{
fprintf(output,"#;%s.%s=%d\n",g->text,l->text,l->labels.value);
l=l->next;
}
g=g->next;
}
fclose(output);
}
void addlabel(char *group,char *label,int n)
/* add a label to the label list, value n */
{
struct labelnode *r,*new,dummy,*newnode(),*findnode();
struct labelnode *findlast(),*findlabel();
if (strcmp(group,"block")==0)
{
/* redefine the default block with label */
if (strlen(label)<maxtag-2) memmove(block,label,maxtag);
else {
printf("\nBlock %s illegal",label);
error();
}
}
else
{
/* add the label */
if(findlabel(group,label)!=0)
{
printf("\nDouble declaration of label %s.%s",group,label);
error();
};
if (groups==0) r=groups=newnode(0,group);
else /* there is a group already */
{
r=findnode(groups,group); /* look up group */
if (r==0) r=newnode(findlast(groups),group);
}
if (r->labels.pointer==0) /* if new group */
{
new=newnode(&dummy,label);
r->labels.pointer=dummy.next;
}
else new=newnode(findlast(r->labels.pointer),label); /* append label */
new->labels.value=n;
}
}
/* *** tag commands *** */
int gettag(char *group,char *label,char **p1,char **p2,int *n,int *val)
/* read a tag or label, and note start and end of labeltext */
{
int br;
char *p,*ph;
skipblanks();
if (*pos=='!' || *pos=='#')
{
*p1=pos;
if (*pos=='!') next();
*p2=pos;
*label=0;
*group=0;
return(1);
}
if (*pos=='{') {
next();
br=1;
} else br=0;
p=ph=*p1=pos;
if (*pos=='@') next();
while (*pos!='}')
{
skipalnumbs();
if (*pos!='.') break;
ph=pos;
next();
*p1=pos;
}
skipalnum();
*p2=pos;
if (((*p2-*p1)>maxtag-1)||((ph-p)>maxtag-2)) return(0);
if (ph!=p) {
memmove(group,p,(int)(ph-p));
*(group+(int)(ph-p))=0;
}
else memmove(group,block,maxtag-1);
memmove(label,*p1,(int)(*p2-*p1));
*(label+(int)(*p2-*p1))=0;
if (*val&&(*pos=='=')) {
next();
*n=scannumber();
*val=1;
*p2=pos;
}
else *val=0;
if (*pos=='_') {
next();
*p2=pos;
}
if (br)
if (*pos!='}') return(0);
else next();
return(1);
}
/* *** subroutines to process special syntax features *** */
void brackets(void) /* process {...} */
{
int l,c;
l=line;
c=column;
show("{ ");
if(!(find("}")))
{
printf("\n{ unbalanced in line %d, column %d",l,c);
error();
}
else show("} ");
}
void informula(void) /* process $...$ */
{
int l,c;
show("+$ ");
l=line;
c=column;
if (!(find("$")))
{
printf("\nUnmatched $ in line %d, column %d",l,c);
error();
};
if (*pos=='$')
{
printf("\n$$ not allowed here");
error();
}
else show("-$ ");
}
void formula(void) /* process $$...$$ */
{
int l,c;
show("+$$ ");
l=line;
c=column;
if (!(find("$")) || *pos++!='$')
{
printf("\nUnmatched $$ in line %d, column %c",l,c);
error();
};
if (*pos=='$')
{
printf("$$$ is illegal");
error();
}
else show("-$$ ");
}
void comment(void) /* pass a coment %... */
{
while (*pos!='\n') {
next();
};
}
void label(void) /* process a label, i.e note the label #=... or change #: to
a number, depending on pass, collect #; and cancel */
{
char group[maxtag],label[maxtag],a,*p,*p1,*p2;
int n,val;
p=pos;
a=*pos;
next();
if ((a=='=')||(a==':')||(a==';'))
{
if (a==':') val=0;
else val=1; /* =value allowed? */
if(!(gettag(group,label,&p1,&p2,&n,&val)))
{
printf("\nIllegal Label");
error();
exit(exitcode);
};
if (pass==1)
if ((a=='=')||(a==';'))
{
if (!val) n=newvalue(group); /* n was not found in =n */
addlabel(group,label,n);
}
if (pass==2)
{
if (strcmp(group,"block")==0) addlabel(group,label,0);
if (a==';') {
correctlabel("block",label,p-1,pos);
noline=1;
}
else correctlabel(group,label,p-1,pos);
}
}
}
/* *** command processing functions *** */
void tag(void) /* process \tag {...} or \tag ... */
{
char label[maxtag],group[maxtag],*p1,*p2;
int n,val=1;
if (tags)
{
*group='@';
if (!(gettag(group+1,label,&p1,&p2,&n,&val)))
{
printf("\nIllegal Tag");
error();
exit(exitcode);
};
if ((pass==1)&&(*p1!='!')&&(*p1!='#'))
{
if (!val) n=newvalue(group); /* =n not found */
addlabel(group,label,n);
}
else if (pass==2)
if ((*p1!='!')&&(*p1!='#'))
correctlabel(group,label,p1,p2);
else correctlabel("block",label,p1,p2);
}
}
void thetag(void)
{
char label[maxtag],group[maxtag],*p1,*p2;
int n,val=0;
if (tags)
{
*group='@';
if (!(gettag(group+1,label,&p1,&p2,&n,&val)))
{
printf("\nIllegal Tag");
error();
exit(exitcode);
};
if (pass==2)
if ((*p1!='!') && (*p1!='#'))
correctlabel(group,label,p1,p2);
else correctlabel("block",label,p1,p2);
}
}
void command(void) /* process a command \... */
{
char com[50];
int l;
putcommand(com,&l);
skip(l);
if (strcmp(com,"tag")==0) tag();
else if (strcmp(com,"thetag")==0) thetag();
else if (strcmp(com,"input")==0 && include_input) doinput();
}
/* *** subroutines to process the file *** */
void advance(void) /* advance pos one character or command */
{
char c;
c=next();
if (checking)
switch(c)
{
case '\n':
{
line+=1;
column=1;
if (verbose) printf(" %d ",line);
break;
}
case '{':
{
brackets();
break;
}
case '}':
{
printf("\nUnmatched }");
error();
break;
}
case '$':
{
if (*pos=='$')
{
next();
if (*pos=='$')
{
printf("$$$ is illegal");
error();
}
else formula();
}
else informula();
break;
}
case '\\':
{
command();
break;
}
case '%':
{
comment();
break;
}
case '#':
{
if (labels) label();
break;
}
case '�':
case '�':
{
umlaut('o');
break;
}
case '�':
case '�':
{
umlaut('a');
break;
}
case '�':
case '�':
{
umlaut('u');
break;
}
case '�':
case '�':
{
umlaut('O');
break;
}
case '�':
case '�':
{
umlaut('A');
break;
}
case '�':
case '�':
{
umlaut('U');
break;
}
case '�':
case '�':
case '�':
{
szet();
break;
}
default:
{
};
}
else
switch(c)
{
case '#':
{
if (labels) label();
break;
}
case '\n' :
{
column=1;
line+=1;
if (verbose) printf("%d ",line);
break;
}
default:
{
};
}
}
/* *** main subroutines *** */
void getparams(int n,char *a[]) /* read parameters from command line */
{
char *i;
if ((n<3)||(*a[1]!='-'))
{
printf("\nUsage -vpltsne file1.tex file2.tex");
printf("\nv=verbose, p=print, l=labels, t=tags");
printf("\ns=silent, n=no checking e=don't exit on error");
printf("\no=output tags and labels, d=deutsch, i=include input");
wait();
exit(1);
}
verbose=printtext=labels=tags=silent=deutsch=include_input=0;
exits=checking=1;
for (i=a[1]+1;*i!=0;i++)
switch(toupper(*i))
{
case 'V':
{
verbose=1;
break;
}
case 'P':
{
printtext=1;
verbose=0;
break;
}
case 'L':
{
labels=1;
break;
}
case 'T':
{
tags=1;
break;
}
case 'S':
{
silent=1;
break;
}
case 'N':
{
checking=0;
break;
}
case 'E':
{
exits=0;
break;
}
case 'O':
{
tagsout=1;
break;
}
case 'D':
{
deutsch=1;
break;
}
case 'I':
{
include_input=1;
break;
}
default:
{
}
}
infile=a[2];
if (n<4) change=0;
else {
outfile=a[3];
change=1;
};
if (tagsout) change=0 ;
}
void inopen(char *filename)
{
char name[512];
if ((input=fopen(filename,"r"))==0)
{
strcpy(name,filename);
strcat(name,".tex");
if ((input=fopen(name,"r"))==0)
{
printf("\nUnable to open %s",filename);
wait();
exit(1);
}
};
setvbuf(input,0,_IOFBF,bufsize);
lb[0]='\n';
pos=lb;
noline=1;
}
void outopen(char *filename)
{
if ((output=fopen(filename,"w"))==0)
{
printf("\nUnable to open %s",filename);
wait();
exit(1);
};
setvbuf(output,0,_IOFBF,bufsize);
}
void checkfile(void) /* check the syntax of the file at filestart */
{
printf("\nPass 1 : \n"); /* line swap on */
line=0;
column=1;
groups=0;
block[0]=0;
pass=1;
end=0;
inopen(infile);
if (labels||tags) find("");
if ((labels||tags)&&(!silent)) printlabels();
if (tagsout) outlabels() ;
else
{
pass=2;
line=0;
column=1;
printtext=0;
printchanges=verbose;
verbose=0;
end=0;
block[0]=0;
rewind(input);
lb[0]='\n';
pos=lb;
noline=1;
if (change) outopen(outfile);
printf("\nPass 2 : \n");
find("");
if (change) fclose(output) ;
}
printlast();
fclose(input) ;
printf("\n\n");
}
main(int argc,char *argv[]) /* main function to read in, process and write file */
{
printf(
"\n ***** Checker, Copyright by R. Grothmann, Version %s ***** \n",
__DATE__);
getparams(argc,argv);
if (change) printf("\nModifying %s to %s.",infile,outfile);
else printf("\nChecking %s.",infile);
checkfile();
return(exitcode);
}