checklibs.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4 
5 
6 #define NUM_PROC 200
7 #define LINE_LEN 200
8 #define RECOMMENDED_LEN 100
9 FILE *f;
11 int tabs=0;
13 int lines=0;
14 unsigned char buf[LINE_LEN];
15 int proc_cnt=0;
16 unsigned char *proc[NUM_PROC];
17 unsigned char have_doc[NUM_PROC];
18 unsigned char have_example[NUM_PROC];
19 unsigned char proc_found[NUM_PROC];
20 int non_ascii=0;
22 int star_nl=0;
23 int footer=0;
24 int header=0;
25 int crlf=0;
26 
27 void get_next()
28 {
29  int i;
30  memset(buf,0,LINE_LEN);
31  fgets(buf,LINE_LEN,f);
32  lines++;
33  if (buf[0]!='\0')
34  {
35  int non_ascii_found=0;
36  if (strchr(buf,'\r')!=NULL) crlf++;
37  if ((buf[LINE_LEN-1]!='\0')||(strlen(buf)>RECOMMENDED_LEN))
38  {
39  if (verylong_lines==0) printf("warning: very long line (%d):\n%s\n",lines,buf);
41  }
42  if ((strstr(buf," \n")!=NULL)||(strstr(buf," \r\n")!=NULL)) trailing_spaces++;
43  if (strchr(buf,'\t')!=NULL) tabs++;
44 
45  for(i=0;(i<LINE_LEN) && (buf[i]!='\0'); i++)
46  {
47  if (buf[i]>=127) { non_ascii_found=1;non_ascii++;non_ascii_line=lines; break; }
48  }
49  if (non_ascii_found) printf("non-ascii:>>%s<<\n",buf);
50  if (footer==0) /* we are still in the header */
51  {
52  if (strstr(buf,"@*")!=NULL) star_nl++;
53  }
54  }
55 }
56 
57 void scan_proc(int *l)
58 {
59  unsigned char *p;
60  while(1)
61  {
62  get_next(); (*l)++;
63  if (((p=strchr(buf,'('))!=NULL)&&(isalnum(*(--p))||(*p=='_')))
64  {
65  unsigned char *s=buf;
66  while(*s==' ') s++;
67  p++; (*p)='\0';
68  if ((((int)(long)(s-buf))>10)||(strchr(s,' ')!=NULL))
69  {
70  printf("warning: probably not a proc ? (%s)\n",s);
71  }
72  else
73  {
74  if (strlen(s)<4)
75  printf("error: minimal length of a procedure name is 4: %s\n",s);
77  }
78  }
79  else if (strstr(buf,"LIB ")!=NULL) break;
80  else if (strstr(buf,"LIB\"")!=NULL) break;
81  else if (strstr(buf,"proc ")!=NULL) break;
82  else if (strncmp(buf,"\";",2)==0) break; /* poor mans end-of-info*/
83  else if ((p=strstr(buf,":"))!=NULL)
84  { /* handles all capital letters + : */
85  /* SEE ALSO, KEYWORDS, NOTE, ... */
86  int ch;
87  unsigned char *pp=buf;
88  while((*pp==' ')||(*pp=='\t')) pp++;
89  ch=strspn(pp,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
90  if ((ch>1)||(pp+ch==p))
91  {
92  break;
93  }
94  }
95  }
96  if (proc_cnt==0)
97  printf("warning: no proc found in the section PROCEDURES ?\n");
98  printf("\n# proc mentioned in the header: %d\n",proc_cnt);
99 }
100 
101 void scan_keywords(int *l)
102 {
103  /* the main problem with KEYWORDS: seperator between is ;,
104  * but it MUST NOT appear at the end */
105  unsigned char *p;
106  while(!feof(f))
107  {
108  p=strrchr(buf,';'); /* the last ; in the line*/
109  if (p==NULL) { get_next(); (*l)++; return; }
110  while (*p==' ') p++;
111  if (isalpha(*p)) { get_next(); (*l)++; return; }
112  if (*p=='\0') { get_next(); (*l)++; }
113  else if (strstr(buf,"LIB ")!=NULL) break;
114  else if (strstr(buf,"LIB\"")!=NULL) break;
115  else if (strstr(buf,"proc ")!=NULL) break;
116  else if (strncmp(buf,"\";",2)==0) break; /* poor mans end-of-info*/
117  else if ((p=strstr(buf,":"))!=NULL)
118  { /* handles all capital letters + : */
119  /* SEE ALSO, KEYWORDS, NOTE, ... */
120  int ch;
121  unsigned char *pp=buf;
122  while((*pp==' ')||(*pp=='\t')) pp++;
123  ch=strspn(pp,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
124  if ((ch>1)||(pp+ch==p))
125  {
126  break;
127  }
128  }
129  }
130  printf("error: seperate keywords by ; but do not have ; after the last keyword\n");
131 }
132 void scan_info(int *l)
133 {
134  int have_LIBRARY=0;
135  int have_AUTHORS=0;
136  int have_PROCEDURES=0;
137  int have_SEEALSO=0;
138  int have_KEYWORDS=0;
139  int have_OVERVIEW=0;
140  int have_NOTE=0;
141  int have_other=0;
142  int texinfo=0;
143  unsigned char *p;
144 
145  while(!feof(f))
146  {
147  if (strstr(buf,"LIBRARY: ")!=NULL)
148  {
149  have_LIBRARY++;
150  /* musrt be first*/
151  if (have_other+have_AUTHORS+have_PROCEDURES+have_KEYWORDS+have_SEEALSO!=0)
152  printf("error: LIBRARY: must be the first section in info\n");
153  }
154  else if (strstr(buf,"NOTE:")!=NULL)
155  {
156  if (have_PROCEDURES!=0)
157  printf("error: only KEYWORDS/SEE ALSO may follow PROCEDURES\n");
158  have_NOTE++;
159  }
160  else if (strstr(buf,"OVERVIEW:")!=NULL)
161  {
162  have_OVERVIEW++;
163  if (have_PROCEDURES!=0)
164  printf("error: only KEYWORDS/SEE ALSO may follow PROCEDURES\n");
165  }
166  else if (strstr(buf,"KEYWORDS: ")!=NULL)
167  {
168  have_KEYWORDS++;
169  }
170  else if (strstr(buf,"SEE ALSO: ")!=NULL)
171  {
172  have_SEEALSO++;
173  }
174  else if ((strstr(buf,"AUTHORS: ")!=NULL)
175  ||(strstr(buf,"AUTHOR: ")!=NULL))
176  {
177  have_AUTHORS++;
178  if (have_PROCEDURES!=0)
179  printf("error: only KEYWORDS/SEE ALSO may follow PROCEDURES\n");
180  }
181  else if ((p=strstr(buf,"PROCEDURES"))!=NULL)
182  {
183  unsigned char *pp=buf;
184  while (pp!=p)
185  {
186  if ((*pp!=' ')&&(*pp!='\t')) break;
187  pp++;
188  }
189  if (p==pp)
190  {
191  have_PROCEDURES++;
192  scan_proc(l);
193  continue;
194  }
195  else
196  {
197  printf("error: unknown section in library header: %s",buf);
198  have_other++;
199  }
200  }
201  else if ((p=strstr(buf,":"))!=NULL)
202  {
203  int ch;
204  unsigned char *pp=buf;
205  while((*pp==' ')||(*pp=='\t')) pp++;
206  ch=strspn(pp,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
207  if ((ch>1)||(pp+ch==p))
208  {
209  /* check for other allowed sections: REFERENCES*/
210  if ((ch!=10)||(strncmp(pp,"REFERENCES",10)!=0))
211  {
212  printf("error: unknown section in library header: %s",buf);
213  have_other++;
214  }
215  if (have_PROCEDURES!=0)
216  printf("error: only KEYWORDS/SEE ALSO may follow PROCEDURES\n");
217  }
218  }
219  else if (strncmp(buf,"\";",2)==0) goto e_o_info; /* poor mans end-of-info*/
220  else
221  {
222  p=buf;
223  if (strchr(buf,'@')!=NULL)
224  { texinfo++; printf("%s",buf); }
225  }
226  get_next(); (*l)++;
227  }
228  e_o_info:
229  printf("\nSUMMARY OF THE HEADER:\n");
230  if (have_LIBRARY!=1)
231  printf("error: missing/duplicate LIBRARY (%d lines found, should be 1)\n",have_LIBRARY);
232  if (have_AUTHORS!=1)
233  printf("error: missing/duplicate AUTHOR/AUTHORS (%d lines found, should be 1)\n",have_AUTHORS);
234  if (have_PROCEDURES!=1)
235  printf("error: missing/duplicate PROCEDURES (%d lines found, should be 1)\n",have_PROCEDURES);
236  if (have_SEEALSO>1)
237  printf("error: duplicate SEE ALSO (%d lines found)\n",have_SEEALSO);
238  if (have_KEYWORDS>1)
239  printf("error: duplicate KEYWORDS (%d lines found)\n",have_KEYWORDS);
240  if (have_NOTE==1)
241  printf("hint: avoid NOTE: if not used for a library requirement\n");
242  else if (have_NOTE>1)
243  printf("error: duplicate NOTE (%d lines found)\n",have_NOTE);
244  if ((have_OVERVIEW==1)&&(proc_cnt<3))
245  printf("hint: avoid OVERVIEW: for small libraries\n");
246  else if (have_OVERVIEW>1)
247  printf("error: duplicate OVERVIEW (%d lines found)\n",have_OVERVIEW);
248 
249  if (have_other!=0)
250  printf("error: other header entries found (illegal ?) :%d lines found, should be 0\n",have_other);
251  if ((star_nl>0)&&(star_nl*10>=header))
252  {
253  printf("warning: %d forced line breaks in %d header lines: @* should be used very rarely!\n",star_nl,header);
254  }
255  if (texinfo>0)
256  {
257  printf("warning: %d texinfo commands in %d header lines: should be used very rarely!\n",texinfo,header);
258  }
259 }
260 
261 int main(int argc, char** argv)
262 {
263  int have_version=0;
264  int have_category=0;
265  int have_info=0;
266  unsigned char *p;
267 
268  memset(proc,0,NUM_PROC*sizeof(char*));
269  memset(have_doc,0,NUM_PROC);
270  memset(have_example,0,NUM_PROC);
271  memset(proc_found,0,NUM_PROC);
272  if (argc!=2) { printf("usage: %s lib-file\n",argv[0]); return 1;}
273 
274  printf("\n CHECKING LIBRARY %s\n\n",argv[1]);
275 
276  f=fopen(argv[1],"r");
277  if(f==NULL) { printf("cannot read %s\n",argv[1]); return 2; }
278  buf[0]='\0';
279  get_next(); header++;
280  if (strncmp(buf,"//",2)!=0) { printf("error: lib must start with //\n"); }
281  else { get_next(); header++; }
282  /* pass 1: check header */
283  while(1)
284  {
285  if ((p=strstr(buf,"version="))!=NULL)
286  {
287  unsigned char *pp=buf;
288  while (pp!=p)
289  {
290  if ((*pp!=' ')&&(*pp!='\t')) break;
291  pp++;
292  }
293  if (p=pp)
294  {
295  have_version++;
296  pp=p+8;
297  while((*pp)==' ') pp++;
298  /* syntax of version string: "version <filename> <version> <date> "
299  if (*pp)!='"')
300  printf("error: version string should ....");
301  */
302  }
303  }
304  if ((p=strstr(buf,"category="))!=NULL)
305  {
306  unsigned char *pp=buf;
307  while (pp!=p)
308  {
309  if ((*pp!=' ')&&(*pp!='\t')) break;
310  pp++;
311  }
312  if (p=pp) have_category++;
313  }
314  if ((p=strstr(buf,"info="))!=NULL)
315  {
316  unsigned char *pp=buf;
317  while (pp!=p)
318  {
319  if ((*pp!=' ')&&(*pp!='\t')) break;
320  pp++;
321  }
322  if (p=pp) { have_info++; scan_info(&header); }
323  }
324  if ((p=strstr(buf,"LIB\""))!=NULL)
325  {
326  printf("error: use a space between LIB and \"\n");
327  if (p!=buf)
328  { printf("end of header ? LIB should be in col. 1:>>%s<<\n",buf); }
329  break; /* end of header */
330  }
331  if ((p=strstr(buf,"LIB \""))!=NULL)
332  {
333  if (p!=buf)
334  { printf("end of header ? LIB should be in col. 1:>>%s<<\n",buf); }
335  break; /* end of header */
336  }
337  if ((p=strstr(buf,"proc "))!=NULL)
338  {
339  if ((p!=buf)&&(strncmp(buf,"static proc ",12)!=0))
340  { printf("end of header ? proc should be in col. 1:>>%s<<\n",buf); }
341  break; /* end of header */
342  }
343  get_next(); header++;
344  if(feof(f)) break;
345  }
346  printf("header parsed: %d lines of %s\n\n",header,argv[1]);
347  /* part 2: procs */
348  while(!feof(f))
349  {
350  if ((strstr(buf,"static")==(char*)buf) && (strstr(buf,"proc")==NULL))
351  {
352  printf("error: 'static' without 'proc' found\n");
353  get_next();
354  }
355  if(((p=strstr(buf,"proc "))!=NULL)
356  &&(strncmp(buf,"static proc ",12)!=0))
357  {
358  unsigned char *pp=buf;
359  int i;
360  while(*pp==' ') pp++;
361  if ((pp!=buf)&&(pp==p))
362  {
363  printf("warning: proc should be in col. 1: line %d:%s",lines,buf);
364  }
365  else if (pp!=p)
366  {
367  footer++; get_next(); continue; /* this is not a proc start*/
368  }
369  p+=5; /* skip proc+blank*/
370  while(*p==' ') p++;
371  pp=p;
372  while(isalnum(*p)||(*p=='_')) p++;
373  *p='\0';
374  for(i=proc_cnt-1;i>=0;i--)
375  {
376  if(strcmp(proc[i],pp)==0) break;
377  }
378  if (i<0)
379  {
380  printf("hint: global proc %s not found in header\n",pp);
381  footer++; get_next();
382  }
383  else
384  {
385  proc_found[i]=1;
386  footer++; get_next(); /* doc should start at next line */
387  p=buf;
388  while(*p==' ') p++;
389  if (*p == '"') have_doc[i]=1;
390  /* serach for example */
391  while(!feof(f))
392  {
393  if(strncmp(buf,"proc ",5)==0) break;
394  if(strncmp(buf,"static proc ",12)==0) break;
395  if(strncmp(buf,"example",7)==0)
396  {
397  have_example[i]=1;
398  break;
399  }
400  footer++; get_next();
401  }
402  }
403  }
404  else {get_next();footer++;}
405  }
406  {
407  int i;
408  for(i=proc_cnt-1; i>=0;i--)
409  {
410  if(proc_found[i]==0) printf("proc %s not found\n",proc[i]);
411  else
412  {
413  if(have_doc[i]==0) printf("proc %s has no documentation\n",proc[i]);
414  if(have_example[i]==0) printf("proc %s has no example (or it does not start in col. 1)\n",proc[i]);
415  }
416  }
417  }
418  /* part 3: summary*/
419  printf("\nproc part parsed: %d lines of %s\n",footer,argv[1]);
420  if (have_version!=1) printf("version missing/duplicate (%d)\n",have_version);
421  if (have_category!=1) printf("category missing/duplicate (%d)\n",have_category);
422  if (have_info!=1) printf("info missing/duplicate (%d)\n",have_info);
423 
424  printf("\nGENERAL SUMMARY:\n");
425  if(tabs!=0) printf("warning: lib should not contain tabs, >=%d found\n",tabs);
426  if(trailing_spaces!=0) printf("hint: lib should not contain trailing_spaces, >=%d found\n",trailing_spaces);
427  if(verylong_lines!=0) printf("hint: lib should not contain very long lines, >=%d found\n",verylong_lines);
428  if(non_ascii>0)
429  printf("error: lib should not contain non-ascii characters, %d found, last in line %d\n",non_ascii, non_ascii_line);
430  if (crlf>=lines-1)
431  {
432  printf("warning: DOS format (%d)\n",crlf);
433  }
434  else if (crlf>0)
435  {
436  printf("error: some lines are in DOS format, some not (%d/%d)\n",crlf,lines);
437  }
438  printf("%d lines parsed\n",lines);
439  printf("%d proc found in header\n",proc_cnt);
440  fclose(f);
441  return 0;
442 }
int main(int argc, char **argv)
Definition: checklibs.c:261
const CanonicalForm int s
Definition: facAbsFact.cc:55
unsigned char * proc[NUM_PROC]
Definition: checklibs.c:16
int crlf
Definition: checklibs.c:25
#define NUM_PROC
Definition: checklibs.c:6
return P p
Definition: myNF.cc:203
void scan_keywords(int *l)
Definition: checklibs.c:101
#define RECOMMENDED_LEN
Definition: checklibs.c:8
int non_ascii
Definition: checklibs.c:20
unsigned char proc_found[NUM_PROC]
Definition: checklibs.c:19
poly pp
Definition: myNF.cc:296
int non_ascii_line
Definition: checklibs.c:21
void scan_proc(int *l)
Definition: checklibs.c:57
FILE * f
Definition: checklibs.c:9
int i
Definition: cfEzgcd.cc:123
#define LINE_LEN
Definition: checklibs.c:7
int header
Definition: checklibs.c:24
int verylong_lines
Definition: checklibs.c:12
#define strdup
Definition: omAllocFunc.c:17
int trailing_spaces
Definition: checklibs.c:10
int lines
Definition: checklibs.c:13
unsigned char have_doc[NUM_PROC]
Definition: checklibs.c:17
unsigned char buf[LINE_LEN]
Definition: checklibs.c:14
int proc_cnt
Definition: checklibs.c:15
#define NULL
Definition: omList.c:10
int footer
Definition: checklibs.c:23
unsigned char have_example[NUM_PROC]
Definition: checklibs.c:18
void get_next()
Definition: checklibs.c:27
void scan_info(int *l)
Definition: checklibs.c:132
int star_nl
Definition: checklibs.c:22
int l
Definition: cfEzgcd.cc:94
int tabs
Definition: checklibs.c:11