summaryrefslogtreecommitdiff
path: root/support/check
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/check
Initial commit
Diffstat (limited to 'support/check')
-rw-r--r--support/check/check.c960
-rw-r--r--support/check/check.doc221
l---------support/check/check.txt1
-rw-r--r--support/check/readme13
4 files changed, 1195 insertions, 0 deletions
diff --git a/support/check/check.c b/support/check/check.c
new file mode 100644
index 0000000000..9351e376cb
--- /dev/null
+++ b/support/check/check.c
@@ -0,0 +1,960 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#define maxtag 16
+#define lmax 512
+#define bufsize 256*64
+
+#define getch() getchar()
+
+char lb[lmax] ;
+
+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();
+}
+
+void skipblanks(void) /* skip blanks */
+{
+ while (*pos==' ') next();
+}
+
+void skipalnum(void) /* skip a alphanumerical word */
+{
+ while (isalnum(*pos)) next();
+}
+
+void skipalnumbs(void) /* skip a alphanumerical with \ */
+{
+ while (isalnum(*pos) || *pos=='\\') next();
+}
+
+void printlast(void) /* print last position in text */
+{
+ printf("\nLast position checked : Line %d, Column %d (in %s)",
+ line,column,infile);
+}
+
+void wait(void)
+{
+ int a;
+ printf("\nHit return or ESC to exit, please!\n");
+ do {
+ } while((a=getch())==0);
+ if (a==27) exit(1);
+}
+
+void error(void) /* error exit */
+{
+ printlast();
+ wait();
+ exitcode=1;
+ if (exits)
+ exit(exitcode);
+}
+
+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 inopen(char *filename);
+void doinput (void)
+{
+ FILE *oldfile;
+ char name[512],*n,*oldinfile;
+ int c,oldline;
+ oldfile=input;
+ oldinfile=infile;
+ oldline=line;
+ next();
+ n=name;
+ while (*pos!=' ' && *pos!='}' && *pos!='\n')
+ {
+ *n++=next();
+ }
+ *n++=0;
+ inopen(name);
+ line=0;
+ infile=name;
+ find("");
+ fclose(input);
+ input=oldfile;
+ pos=lb;
+ noline=1;
+ *pos='\n';
+ infile=oldinfile;
+ line=oldline;
+ end=0;
+}
+
+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);
+}
+
diff --git a/support/check/check.doc b/support/check/check.doc
new file mode 100644
index 0000000000..83d8b30dd9
--- /dev/null
+++ b/support/check/check.doc
@@ -0,0 +1,221 @@
+
+***********************************************************************
+* *
+* CHECKER *
+* by R. Grothmann *
+* *
+***********************************************************************
+
+ Documentation
+ =============
+
+
+ Introduction
+ ------------
+
+ Checker is a program designed for testing TeX files. Besides checking
+ the syntax, it features labels and automatic tag numbering. Just start
+ checker by entering
+
+ check -options infile outfile
+
+ On the Atari ST you have to click on check.ttp and enter the options
+ and files into the ttp box, appearing on the screen. "options" is a
+ sequence of the letters (capital or not) l,t,s,v,p,n or o. "infile"
+ and "outfile" (optional) are standard filenames. An example is
+
+ check -lt work.txt work.tex
+
+ The program will read in the file work.txt, check it and produce an
+ output to the file work.tex, thereby changing labels and tags to their
+ values. If you omit the outfile, the program will produce no output.
+
+
+ Labels
+ ------
+
+ Labels belong to a group and have a name and a value, which is an
+ integer (positive or negative). They are defined in a program by
+
+ #=group.name
+
+ or
+
+ #={group.name}
+
+ The name is any alphanumeric string (consisting of lowercase or upper-
+ case letters or digits), not exceeding 15 characters. The group may
+ consist of several alphanumeric strings, seperated by "." and not ex-
+ ceeding 14 characters. An example is
+
+ #=1.1.a
+
+ or
+
+ #={1.1.a}
+
+ where "1.1" is the group and "a" is the name. The Value of the label
+ can be assigned to it by the sequence
+
+ #=group.name=value
+
+ or
+
+ #={group.name=value}
+
+ Remember that "value" has to be an integer. For example
+
+ #=refs.miller=10
+
+ If you do not assign a value to the label, it gets the value of the
+ previous label in the group plus 1. If there is no previous label, the
+ value will be 1. On the output, the whole definition of the label is
+ replaced by the value of the label. And so are all references of the
+ label. References are of the following form
+
+ #:group.name
+
+ or
+
+ #:{group.name}
+
+ Of course, you cannot assign a value to a reference. If a label is
+ immediately followed by an underbar "_", then this underbar disappears
+ from the output, for instance
+
+ #:test.a_a
+
+ will be replaced by "1a", if "test.a" has the value 1. The label feature
+ is only active, if the option "l" was given on the command line. Other-
+ wise the program will just read over any #.
+
+
+ Default Group
+ -------------
+
+ If a label is defined or referred to without a group (omitting both
+ the group and the "."), then it is assumed to be a label in the default
+ group. You can set the default group by
+
+ #=block.group
+
+ This is not a label definition. There is never a group named "block".
+ Instead, the default group is set to "group". As an example, let
+
+ #=block.refs
+ #=a
+
+ be a sequence from your file. Then the reference
+
+ #:a
+
+ is a reference to the label "refs.a", unless you have redefined the
+ default group. If you did so, you may refer to that label by
+
+ #:refs.a
+
+
+ Tags
+ ----
+
+ Tags are a part of TeX's syntax. Checker assumes tags to be defined as
+
+ \tag group.name
+
+ or
+
+ \tag {group.name}
+
+ "group" and "name" obey the same syntax rules as in the definition of
+ labels above. They are referred to by
+
+ \thetag{group.name}
+
+ As with labels, you may assign a value to a tag. An example is
+
+ \tag 1.a=0
+
+ On the output, only the name of the tag is replaced by the value of the
+ tag. Thus the above tag would change to
+
+ \tag 1.0
+
+ Of course, all references (\thetag ...) are corrected too. As with
+ labels, the program checks for double definition of a tag. Tags may
+ be proteced by
+
+ \tag !something
+
+ or
+
+ \thetag !something
+
+ The the program will not change "something". Only the "!" will be left
+ out. What was said about default groups, holds for tags too. The tag
+ feature is active, if the option "t" is given in the command line. The
+ "_" works in the same way, as it does with labels.
+
+
+ Syntax checking
+ ---------------
+
+ Unless the option "n" was given, the program checks the syntax in your
+ file for correct usage of "$". "$$", "{" and "}". The program is clever
+ enough to know that "\{" is different from "{". The first error will
+ abort the program and will be reported. Comments "%" are omitted. An
+ error does not abort the program if the option "e" was given int the
+ command line.
+
+
+ Output of Labels and Tags
+ -------------------------
+
+ Only labels and tags are written to the output file, if the option "o"
+ was given in the command line. This is done in such a way that the
+ output file can be read into a TeX file. All labels are written as
+
+ #;group.name=value
+
+ The tags look like
+
+ #;@group.name=value
+
+ The sequence "#;" starts a blind label. Such a label is defined, as
+ if "@;" was replaced by "@=". But on the output, it will not show up.
+ The same is true for tags. So you can just use the old label definitions
+ in a new TeX file. This may be used in a continuation of a previous
+ TeX text. If a blind label or tag occupies a complete line, then this
+ line will not go to output. Otherwise the rest of the line will be
+ in the output.
+
+
+ Other Options
+ -------------
+
+ You have control over the screen output of the program. Least printing
+ is produced with the option "s" (silent). The option "v" lists all the
+ syntax elements the program finds (verbose). The option "p" prints out
+ the complete text (print).
+
+
+ Internals
+ ---------
+
+ Checker is a C program, which uses two passes. Pass 1 checks the syntax
+ and collects all labels and tags. Pass 2 corrects labels and tags and
+ produces the outfile. An existing outfile will be truncated without
+ backup. Reading and Writing is done via a buffer. The preformance is
+ best, when the files are on RAM disk or harddisk.
+
+************************************************************************
+
+ If you have troubles with the program, contact
+
+ R. Grothmann
+ Ostenstr. 18
+ 8078 Eichstaett
+ W-Germany
+
+ EMail: rene.grothmann@ku-eichstaett.de
+
+*************************************************************************
diff --git a/support/check/check.txt b/support/check/check.txt
new file mode 120000
index 0000000000..8095cb5e7f
--- /dev/null
+++ b/support/check/check.txt
@@ -0,0 +1 @@
+check.doc \ No newline at end of file
diff --git a/support/check/readme b/support/check/readme
new file mode 100644
index 0000000000..552ec2ab25
--- /dev/null
+++ b/support/check/readme
@@ -0,0 +1,13 @@
+Overview
+--------
+
+check.c is the source of a TeX file filter. It provides syntax checking
+as well as automatic labelling, and additionally german language support.
+
+
+Hints for compiling check.c
+---------------------------
+
+check.c can be compiled with any ANSI-C C-compiler. On UNIX systems use
+ cc -o check check.c -lm
+to produce an executable check. Read check.doc for usage hints.