1 /***************************************************************************
2     begin       : Fri Jun 02 2004
3     copyright   : (C) 2019 by Martin Preuss
4     email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  *          Please see toplevel file COPYING for license details           *
8  ***************************************************************************/
9 
10 
11 
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 
19 #include <string.h>
20 #include <errno.h>
21 #include <ctype.h>
22 
23 
24 #define MAX_LINESIZE 8192
25 
26 
27 typedef struct MACRO_DEF MACRO_DEF;
28 struct MACRO_DEF {
29   const char *macroName;
30   const char *tmplFileName;
31   const char *fileSuffix;
32 };
33 
34 
35 typedef struct MACRO_STRUCT MACRO_STRUCT;
36 struct MACRO_STRUCT {
37   MACRO_STRUCT *next;
38   MACRO_DEF *macroDef;
39   char *typeName;
40   char *typePrefix;
41 };
42 
43 
44 
45 MACRO_DEF macroDefs[]= {
46   {
47     "GWEN_LIST2_FUNCTION_DEFS",
48     "list2.tmpl",
49     "_list2p"
50   },
51   {
52     "GWEN_LIST2_FUNCTION_LIB_DEFS",
53     "list2.tmpl",
54     "_list2"
55   },
56   {
57     "GWEN_CONSTLIST2_FUNCTION_DEFS",
58     "list2.tmpl",
59     "_constlist2p"
60   },
61   {
62     "GWEN_CONSTLIST2_FUNCTION_LIB_DEFS",
63     "list2.tmpl",
64     "_constlist2"
65   },
66   {
67     "GWEN_LIST_FUNCTION_DEFS",
68     "list1.tmpl",
69     "_listp"
70   },
71   {
72     "GWEN_LIST_FUNCTION_LIB_DEFS",
73     "list1.tmpl",
74     "_list"
75   },
76   {
77     "GWEN_CONSTLIST_FUNCTION_DEFS",
78     "list1.tmpl",
79     "_constlistp"
80   },
81   {
82     "GWEN_CONSTLIST_FUNCTION_LIB_DEFS",
83     "list1.tmpl",
84     "_constlist"
85   },
86   {
87     0, 0, 0
88   }
89 };
90 
91 
92 
93 #define MODE_CHECKONLY   1
94 #define MODE_WRITEHEADER 2
95 #define MODE_WRITESTDOUT 3
96 
97 
98 const char *templatePath=GWEN_HEADERS;
99 int mode=MODE_WRITESTDOUT;
100 int verbosity=0;
101 
102 
103 
104 /* ------------------------------------------------------------------------------------------------
105  * forward declarations
106  * ------------------------------------------------------------------------------------------------
107  */
108 
109 static MACRO_STRUCT *MacroStruct_new(MACRO_DEF *macroDef, const char *typeName, const char *typePrefix);
110 /*static void MacroStruct_free(MACRO_STRUCT *m);*/
111 static int scanLine(MACRO_DEF *macroDef, char *buffer, MACRO_STRUCT **m);
112 static int scanLineForAllMacros(char *buffer, MACRO_STRUCT **m);
113 static MACRO_STRUCT *scanForMacros(const char *fname);
114 static int transformF(FILE *inFile, FILE *outFile, const char *outFileName, MACRO_STRUCT *m);
115 static int transform(const char *inFile, const char *outFile, MACRO_STRUCT *m);
116 static int processFile(const char *fname);
117 int main(int argc, char **argv);
118 
119 
120 
121 /* ------------------------------------------------------------------------------------------------
122  * implementations
123  * ------------------------------------------------------------------------------------------------
124  */
125 
126 
127 
128 
MacroStruct_new(MACRO_DEF * macroDef,const char * typeName,const char * typePrefix)129 MACRO_STRUCT *MacroStruct_new(MACRO_DEF *macroDef,
130                               const char *typeName,
131                               const char *typePrefix)
132 {
133   MACRO_STRUCT *m;
134 
135   m=(MACRO_STRUCT *)malloc(sizeof(MACRO_STRUCT));
136   memset(m, 0, sizeof(MACRO_STRUCT));
137   m->macroDef=macroDef;
138   if (typeName)
139     m->typeName=strdup(typeName);
140   if (typePrefix)
141     m->typePrefix=strdup(typePrefix);
142 
143   return m;
144 }
145 
146 
147 
148 #if 0
149 void MacroStruct_free(MACRO_STRUCT *m)
150 {
151   if (m) {
152     free(m->typeName);
153     free(m->typePrefix);
154     free(m);
155   }
156 }
157 #endif
158 
159 
160 
scanLine(MACRO_DEF * macroDef,char * buffer,MACRO_STRUCT ** m)161 int scanLine(MACRO_DEF *macroDef,
162              char *buffer,
163              MACRO_STRUCT **m)
164 {
165   char *p;
166   char *macroBegin;
167 
168   p=strstr(buffer, macroDef->macroName);
169   if (p) {
170     /* found something, search for opening bracket */
171     macroBegin=p;
172     p+=strlen(macroDef->macroName);
173     while (*p && isspace((int)*p))
174       p++;
175     if (*p && *p!='(')
176       return -1;
177 
178     while (*p) {
179       if (*p=='(') {
180         char *typeName;
181         char *typeNameEnd;
182         char *typePrefix;
183         char *typePrefixEnd;
184 
185         typeName=typePrefix=0;
186         typeNameEnd=typePrefixEnd=0;
187 
188         /* found it, now read the typename */
189         p++;
190         while (*p && isspace((int)*p))
191           p++;
192         typeName=p;
193 
194         /* find comma */
195         while (*p) {
196           if (*p==',') {
197             /* found it, name ends here */
198             if (!typeNameEnd)
199               typeNameEnd=p;
200             p++;
201             while (*p && isspace((int)*p))
202               p++;
203             typePrefix=p;
204 
205             /* find closing bracket */
206             while (*p) {
207               if (*p==')' || *p==',') {
208                 MACRO_STRUCT *lm;
209                 MACRO_STRUCT *sm;
210                 char *s;
211                 char c1, c2;
212 
213                 /* found it, now all is complete */
214                 if (!typePrefixEnd)
215                   typePrefixEnd=p;
216 
217                 /* check whether this is a definition */
218                 s=buffer;
219                 while (*s && isspace((int)*s))
220                   s++;
221                 if (*s=='#') {
222                   s++;
223                   /* preprocessor command, check for define */
224                   while (*s && isspace((int)*s))
225                     s++;
226                   if (strncasecmp(s, "define ", 7)==0) {
227                     s+=7;
228                     /* it is a define, now check if the next nonblank is
229                      * the beginning of this macro */
230                     while (*s && isspace((int)*s))
231                       s++;
232                     if (s==macroBegin) {
233                       if (verbosity>1)
234                         fprintf(stderr, "Found definition for macro \"%s\".\n",
235                                 macroDef->macroName);
236                       return -1;
237                     }
238                   }
239                 }
240 
241                 c1=*typePrefixEnd;
242                 c2=*typeNameEnd;
243                 *typePrefixEnd=0;
244                 *typeNameEnd=0;
245                 sm=*m;
246                 while (sm) {
247                   if (strcmp(sm->macroDef->macroName, macroDef->macroName)==0)
248                     if (strcmp(sm->typeName, typeName)==0)
249                       /* already exists */
250                       break;
251                   sm=sm->next;
252                 }
253                 if (!sm) {
254                   /* macro is new, store it */
255                   lm=MacroStruct_new(macroDef, typeName, typePrefix);
256                   *typePrefixEnd=c1;
257                   *typeNameEnd=c2;
258                   if (*m==0)
259                     *m=lm;
260                   else {
261                     lm->next=*m;
262                     *m=lm;
263                   }
264                   if (verbosity>1)
265                     fprintf(stderr, "Found macro \"%s\" (%s, %s)\n",
266                             lm->macroDef->macroName,
267                             lm->typeName,
268                             lm->typePrefix);
269                 }
270                 return 0;
271               }
272               else if (isspace((int)*p)) {
273                 if (!typePrefixEnd)
274                   typePrefixEnd=p;
275               }
276               else {
277                 if (typePrefixEnd)
278                   return -1;
279               }
280 
281               p++;
282             }
283             /* closing bracket missing, probably need more data... */
284             return 1;
285           }
286           else if (isspace((int)*p)) {
287             if (!typeNameEnd)
288               typeNameEnd=p;
289           }
290           else {
291             if (typeNameEnd)
292               return -1;
293           }
294           p++;
295         }
296         /* comma missing, probably need more data... */
297         return 1;
298       }
299       p++;
300     }
301     /* opening bracket missing, probably need more data... */
302     return 1;
303   }
304   /* macro not found in this line */
305   return -1;
306 }
307 
308 
309 
scanLineForAllMacros(char * buffer,MACRO_STRUCT ** m)310 int scanLineForAllMacros(char *buffer,
311                          MACRO_STRUCT **m)
312 {
313   int i;
314 
315 
316   for (i=0; ; i++) {
317     if (macroDefs[i].macroName==0)
318       return 0;
319     if (scanLine(&macroDefs[i], buffer, m)==1)
320       return 1;
321   }
322 
323   return 0;
324 }
325 
326 
327 
scanForMacros(const char * fname)328 MACRO_STRUCT *scanForMacros(const char *fname)
329 {
330   FILE *f;
331   MACRO_STRUCT *mst;
332   char buffer[MAX_LINESIZE];
333   int line;
334   char *p;
335 
336   mst=0;
337   line=0;
338   if (verbosity)
339     fprintf(stderr, "Reading file \"%s\"\n", fname);
340   f=fopen(fname, "r");
341   if (!f) {
342     fprintf(stderr, "fopen(%s): %s\n", fname, strerror(errno));
343     return 0;
344   }
345 
346   buffer[0]=0;
347   buffer[sizeof(buffer)-1]=0;
348   while (!feof(f)) {
349     int sl;
350     int rv;
351 
352     line++;
353     if (verbosity>3)
354       fprintf(stderr, "Reading line %d\n", line);
355 
356     /* read line */
357     if (buffer[0]==0) {
358       p=fgets(buffer, sizeof(buffer)-1, f);
359     }
360     else {
361       int sizeLeft;
362 
363       if (verbosity>3)
364         fprintf(stderr, "Multi-line macro (%d)\n", line);
365       sl=strlen(buffer);
366       sizeLeft=(sizeof(buffer)-1)-sl;
367       if (sizeLeft<2) {
368         fprintf(stderr, "Line %d: Line full, macro too long\n", line);
369         fclose(f);
370         return 0;
371       }
372       strcat(buffer, " ");
373       p=fgets(buffer+sl+1, sizeLeft, f);
374     }
375 
376     if (!p) {
377       if (ferror(f)) {
378         fprintf(stderr, "fread(%s): %s\n", fname, strerror(errno));
379         fclose(f);
380         return 0;
381       }
382       else
383         /* simple eof */
384         break;
385     }
386 
387     sl=strlen(buffer);
388     if (buffer[sl-1]=='\n')
389       buffer[--sl]=0;
390 
391     if (buffer[sl-1]=='\\') {
392       buffer[--sl]=0;
393     }
394     else {
395       /* now check for macros */
396       rv=scanLineForAllMacros(buffer, &mst);
397       if (rv!=1)
398         /* no more data needed */
399         buffer[0]=0;
400     }
401   } /* while */
402 
403   fclose(f);
404   return mst;
405 }
406 
407 
408 
transformF(FILE * inFile,FILE * outFile,const char * outFileName,MACRO_STRUCT * m)409 int transformF(FILE *inFile,
410                FILE *outFile,
411                const char *outFileName,
412                MACRO_STRUCT *m)
413 {
414   char *p;
415   char buffer[MAX_LINESIZE];
416   int didIt;
417 
418   while (!feof(inFile)) {
419     char *vname;
420     int sl;
421 
422     /* read line */
423     p=fgets(buffer, sizeof(buffer)-1, inFile);
424     if (!p) {
425       if (ferror(inFile)) {
426         fprintf(stderr, "fread(): %s\n", strerror(errno));
427         return 0;
428       }
429       else
430         /* simple eof */
431         break;
432     }
433 
434     sl=strlen(buffer);
435     if (buffer[sl-1]=='\n')
436       buffer[--sl]=0;
437 
438     vname=0;
439     p=buffer;
440     while (*p) {
441       while (*p && *p!='@') {
442         if (EOF==fputc(*p, outFile)) {
443           fprintf(stderr, "fputc(): %s (1)\n", strerror(errno));
444           return 2;
445         }
446         p++;
447       }
448       didIt=0;
449       if (*p=='@') {
450         char *psave;
451 
452         /* got a var... */
453         psave=p;
454         p++;
455         vname=p;
456         while (*p && *p!='@')
457           p++;
458         if (*p=='@') {
459           char c;
460           const char *replacement;
461 
462           /* got it */
463           c=*p;
464           *p=0;
465           if (strcmp(vname, "TYPENAME")==0)
466             replacement=m->typeName;
467           else if (strcmp(vname, "FN_PREFIX")==0)
468             replacement=m->typePrefix;
469           else if (strcmp(vname, "FILENAME")==0)
470             replacement=outFileName;
471           else {
472             /* not a var */
473             replacement=0;
474           }
475           *p=c;
476           p++;
477 
478           if (replacement) {
479             if (fprintf(outFile, "%s", replacement)<1) {
480               fprintf(stderr, "fprintf(): %s\n", strerror(errno));
481               return 2;
482             }
483             didIt=1;
484           }
485           else {
486             /* write the original data */
487             p=psave;
488           }
489         }
490         else
491           /* write the original data */
492           p=psave;
493       }
494       if (!didIt) {
495         if (*p) {
496           if (EOF==fputc(*p, outFile)) {
497             fprintf(stderr, "fputc(): %s\n", strerror(errno));
498             return 2;
499           }
500           p++;
501         }
502       }
503     } /* while line */
504     fprintf(outFile, "\n");
505   } /* while */
506 
507   return 0;
508 }
509 
510 
511 
transform(const char * inFile,const char * outFile,MACRO_STRUCT * m)512 int transform(const char *inFile,
513               const char *outFile,
514               MACRO_STRUCT *m)
515 {
516   FILE *f1;
517   FILE *f2;
518   int rv;
519 
520   f1=fopen(inFile, "r");
521   if (!f1) {
522     fprintf(stderr, "fopen(%s, \"r\"): %s\n", inFile, strerror(errno));
523     return 2;
524   }
525   if (outFile==0) {
526     f2=stdout;
527     rv=transformF(f1, f2, "(stdout)", m);
528   }
529   else {
530     f2=fopen(outFile, "w+");
531     if (!f2) {
532       fprintf(stderr, "fopen(%s, \"w+\"): %s\n", outFile, strerror(errno));
533       fclose(f1);
534       return 2;
535     }
536     rv=transformF(f1, f2, outFile, m);
537   }
538 
539   if (outFile!=0) {
540     if (fclose(f2)) {
541       fprintf(stderr, "fclose(%s): %s\n", outFile, strerror(errno));
542       fclose(f1);
543       return 2;
544     }
545   }
546   if (fclose(f1)) {
547     fprintf(stderr, "fclose(%s): %s\n", inFile, strerror(errno));
548     return 2;
549   }
550 
551   return rv;
552 }
553 
554 
555 
processFile(const char * fname)556 int processFile(const char *fname)
557 {
558   MACRO_STRUCT *m;
559 
560   m=scanForMacros(fname);
561   if (m) {
562     /* do something with the macros */
563     if (mode==MODE_WRITESTDOUT) {
564       MACRO_STRUCT *cm;
565 
566       cm=m;
567       while (cm) {
568         int rv;
569         char tmplBuffer[256];
570 
571         rv=snprintf(tmplBuffer, sizeof(tmplBuffer),
572                     "%s/%s",
573                     templatePath,
574                     cm->macroDef->tmplFileName);
575         if (rv<1 || rv>=(int)sizeof(tmplBuffer)) {
576           fprintf(stderr, "Internal error: buffer too small [processFile]\n");
577           return 3;
578         }
579         rv=transform(tmplBuffer, 0, cm);
580         if (rv) {
581           fprintf(stderr, "Error transforming template file.\n");
582           return rv;
583         }
584 
585         cm=cm->next;
586       }
587     }
588   }
589 
590   return 0;
591 }
592 
593 
594 
595 
596 
597 
598 
599 
600 
main(int argc,char ** argv)601 int main(int argc, char **argv)
602 {
603   int i = 1;
604   int wantHelp;
605 
606   wantHelp=0;
607   if (argc<2) {
608     wantHelp=1;
609   }
610   else {
611     i=1;
612     while (i<argc) {
613       if (strcmp(argv[i], "-I")==0) {
614         i++;
615         if (i>=argc) {
616           fprintf(stderr, "Argument missing for -I\n");
617           return 1;
618         }
619         templatePath=argv[i];
620       }
621       else if (strcmp(argv[i], "-v")==0) {
622         verbosity++;
623       }
624       else if (strcmp(argv[i], "-h")==0 ||
625                strcmp(argv[i], "--help")==0) {
626         wantHelp=1;
627       }
628       else if (strcmp(argv[i], "--doc")==0) {
629         /* only generate header */
630         mode=MODE_WRITEHEADER;
631       }
632       else if (strcmp(argv[i], "--stdout")==0) {
633         /* write all headers to stdout instead of creating one header per
634          * input */
635         mode=MODE_WRITESTDOUT;
636       }
637       else
638         break;
639       i++;
640     }
641   }
642 
643   if (wantHelp) {
644     fprintf(stderr,
645             "MkListDoc (c) 2004 Martin Preuss<martin@libchipcard.de>\n"
646             "Part of Gwenhywfar " GWENHYWFAR_VERSION_FULL_STRING "\n"
647             "This tool is licensed under the LGPL (see COPYING in\n"
648             "toplevel source folder).\n"
649             "MkListDoc expands GWEN_LIST macros and creates a suitable\n"
650             "header file for every encounterd list definition macro.\n"
651             "Example:\n"
652             "You are using GWEN_LIST2 macros to manage list of some objects:\n"
653             " GWEN_LIST2_FUNCTION_DEFS(TYPE_SOMETHING, TypeSomething);\n"
654             "The list is now available but not documented by Doxygen.\n"
655             "This tool now creates output that can then be fed to doxygen\n"
656             "to create appropriate API documentation.\n"
657             "\n"
658             "Usage: %s [OPTIONS] file1 file2 ... fileN\n"
659             "Options are:\n"
660             "-v     increases the verbosity level\n"
661             "-I     path to GWEN include headers\n"
662             "Output is sent to stdout.\n",
663             argv[0]);
664     return 0;
665   }
666 
667   if (i>=argc) {
668     /* no input ? */
669     fprintf(stderr, "No input files.\n");
670     return 1;
671   }
672 
673   while (i<argc) {
674     int rv;
675 
676     /* process all files */
677     rv=processFile(argv[i]);
678     if (rv) {
679       fprintf(stderr, "Too bad...\n");
680       return rv;
681     }
682     i++;
683   } /* while */
684   return 0;
685 }
686 
687 
688 
689 
690 
691 
692 
693 
694 
695 
696 
697