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(¯oDefs[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