2 Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen,
3 Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner,
4 Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai.
6 This file is part of ROBODoc
8 ROBODoc is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* $Id: robohdrs.c,v 1.14 2007/07/10 19:13:52 gumpu Exp $ */
25 /****h* Docuwala/ROBOhdrs
29 * Standalone program to insert ROBODoc headers to source code files.
30 * This program processes one source file at the time. Existing
31 * ROBODoc headers, if any, are not checked for. Beware since this
32 * may result in double headers. Current working directory should
33 * be the same as where the source file is located.
35 * Exuberant Ctags 5.3.1 or newer required
37 * robohdrs [options] <source file>
39 * robohdrs -p myproj test1.c
40 * robohdrs -s -p myproj -i "MODIFICATION HISTORY" -i IDEAS test2.c
42 * Type `robohdrs -h' to see all command line options.
44 * - garbage collection
45 * - support for other languages which ctags program supports
47 * ROBODoc https://sourceforge.net/projects/robodoc/
48 * Exuberant Ctags http://ctags.sourceforge.net/
50 * (c) 2003 Frans Slothouber and Petteri Kettunen
53 * 2003-08-08/petterik: #define `d' header (bug rep. from Anand Dhanakshirur)
54 * 2003-08-04/petterik: -t option (suggestion from Anand Dhanakshirur)
55 * 2003-02-21/petterik: -l option, script option tested
72 int main( int argc, char** argv )
74 printf( "Not supported on this platform\n" );
75 printf( "This program requires fork()\n" );
88 /****v* ROBOhdrs/PROGNAME
93 #define PROGNAME "robohdrs"
94 /********** PROGNAME */
95 /****v* ROBOhdrs/PROGVERSION
100 #define PROGVERSION "0.01"
101 /********** PROGVERSION */
102 /****v* ROBOhdrs/MAXLINE
107 #define MAXLINE 10240
108 /********** MAXLINE */
109 /****v* ROBOhdrs/MAXNAME
116 /********** MAXNAME */
118 /****v* ROBOhdrs/ctagsBin
123 static char ctagsBin[MAXNAME];
125 /********** ctagsBin */
127 /****v* ROBOhdrs/srcSta
135 static short srcSta = SRC_C;
136 static short srcRem = SRC_R_C;
137 static short srcEnd = SRC_E_C;
139 /********** srcSta */
141 typedef struct _ctag_t
153 typedef struct _custhdr_t
160 typedef struct _ctags_t
167 /****v* ROBOhdrs/myctags
171 * static ctags_t myctags;
174 static ctags_t myctags;
176 /********** myctags */
177 /****v* ROBOhdrs/ctags
181 * static ctags_t *ctags;
184 static ctags_t *ctags;
187 /****v* ROBOhdrs/custhdrs
191 * static custhdr_t *custhdrs = 0;
194 static custhdr_t *custhdrs = 0;
196 /********** custhdrs */
197 /****v* ROBOhdrs/projName
201 * static char projName[MAXNAME];
204 static char projName[MAXNAME];
206 /********** projName */
207 /****v* ROBOhdrs/vcTag
211 * Version control tag string. This is always specified by the user.
213 * static char vcTag[MAXNAME];
216 static char vcTag[MAXNAME];
218 /********** projName */
219 /****v* ROBOhdrs/incSrc
223 * static char incSrc = 0;
226 static char incSrc = 0;
228 /********** incSrc */
229 /****f* ROBOhdrs/usage
233 * static void usage(void)
239 printf( "%s version %s, robodoc header insertor\n", PROGNAME,
241 printf( "(c) 2003 Frans Slothouber and Petteri Kettunen\n" );
242 printf( "%s comes with ABSOLUTELY NO WARRANTY.\n", PROGNAME );
244 ( "This is free software, and you are welcome to redistribute it\n" );
245 printf( "under the GNU GENERAL PUBLIC LICENSE terms and conditions.\n" );
246 printf( "usage: %s [options] <source file>\n", PROGNAME );
247 printf( "Options are as follows:\n" );
248 printf( " -h show this help text\n" );
250 ( " -i specify header item (repeat to include multiple items)\n" );
251 printf( " -l specify source code language (default C/C++)\n" );
253 ( " Supported options are: fortran, fortran90, script, and tex.\n" );
254 printf( " -p specify project name\n" );
255 printf( " -s include SOURCE item\n" );
256 printf( " -t specify CVS/RCS tag to be inserted into a file\n" );
257 printf( " -x specify path to ctags binary\n" );
258 printf( "NOTE: requires Exuberant Ctags 5.3.1 (or newer)\n" );
259 printf( "EXAMPLES:\n" );
261 ( "robohdrs -s -p myproj -i \"MODIFICATION HISTORY\" -i IDEAS test.c\n" );
263 ( "robohdrs -s -p myproj -l script -t '%cHeader:%c' test.tcl\n", '$', '$' );
269 /****f* ROBOhdrs/cmdLine
273 * static void cmdLine(int argc, char **argv)
277 cmdLine( int argc, char **argv )
282 while ( ( ch = getopt( argc, argv, "i:l:p:st:x:" ) ) != -1 )
287 /* include source item */
292 /* specify version control tag */
293 strncpy( vcTag, optarg, MAXNAME );
297 /* specify project name */
298 strncpy( projName, optarg, MAXNAME );
305 ( custhdr_t * ) malloc( sizeof( custhdr_t ) ) ) );
317 ( custhdr_t * ) malloc( sizeof( custhdr_t ) ) ) );
321 strncpy( c->name, optarg, MAXNAME );
325 if ( optarg[0] == 's' && strcmp( optarg, "script" ) == 0 )
328 srcRem = SRC_R_SCRIPT;
329 srcEnd = SRC_E_SCRIPT;
331 else if ( optarg[0] == 'f' && strcmp( optarg, "fortran" ) == 0 )
333 srcSta = SRC_FORTRAN;
334 srcRem = SRC_R_FORTRAN;
335 srcEnd = SRC_E_FORTRAN;
337 else if ( optarg[0] == 'f' && strcmp( optarg, "fortran90" ) == 0 )
343 else if ( optarg[0] == 't' && strcmp( optarg, "tex" ) == 0 )
349 else if ( optarg[0] == 'a' && strcmp( optarg, "acm" ) == 0 )
362 strncpy( ctagsBin, optarg, MAXNAME );
373 /********** cmdLine */
374 /****f* ROBOhdrs/linenumCompare
378 * static int linenumCompare(void const * a, void const * b)
382 linenumCompare( void const *a, void const *b )
384 ctag_t *ea = ( ctag_t * ) a, *eb = ( ctag_t * ) b;
386 return ( ea->linenum - eb->linenum );
389 /********** linenumCompare */
390 /****f* ROBOhdrs/arrangeCtags
394 * static void arrangeCtags(ctags_t *e)
398 arrangeCtags( ctags_t * e )
400 ctag_t *tmp, *ctag = e->ctag, *ep;
402 assert( e && e->cnt && e->ctag );
403 tmp = ( ctag_t * ) malloc( e->cnt * sizeof( ctag_t ) );
408 memcpy( ep++, ctag, sizeof( ctag_t ) );
419 qsort( tmp, ( size_t ) ( e->cnt ), sizeof( ctag_t ), linenumCompare );
420 /* TODO: free ctag */
424 /********** arrangeCtags */
425 /****f* ROBOhdrs/typeOk
429 * static int typeOk(char *t)
435 /* return 1 if supported type for headers */
436 if ( t[0] == 'f' && strncmp( t, "function", 8 ) == 0 )
440 else if ( t[0] == 'v' && strncmp( t, "variable", 8 ) == 0 )
442 return 1; /* global variable */
445 else if ( t[0] == 's' && strncmp( t, "struct", 6 ) == 0 )
450 else if ( t[0] == 'm' && strncmp( t, "macro", 5 ) == 0 )
458 /********** typeOk */
459 /****f* ROBOhdrs/initMe
463 * static void initMe(void)
470 memset( ctags, 0, sizeof( ctags_t ) );
476 /********** initMe */
478 /****f* ROBOhdrs/parseCtagsXLine
482 * static int parseCtagsXLine(char *buf, char *fname, char *name, char *decl, char *type, int *linenum)
486 parseCtagsXLine( char *buf, char *fname, char *name, char *decl, char *type,
491 /* ctags -x output is: */
492 /* usage function 56 test.c void usage(void) */
493 sscanf( buf, "%s%s%d%s", name, type, linenum, fname );
494 s = strstr( buf, fname );
495 while ( *s++ != ' ' )
503 while ( ( *t = *s++ ) != '\n' )
512 /********** parseCtagsXLine */
514 /****f* ROBOhdrs/addList
518 * static void addList(ctags_t *e, char *fname, char *name, char *decl, char *type, int linenum)
522 addList( ctags_t * e, char *fname, char *name, char *decl, char *type,
525 ctag_t *newctag, *ctag = e->ctag;
530 ctag = ( ctag_t * ) malloc( sizeof( ctag_t ) );
532 memset( ctag, 0, sizeof( ctag_t ) );
541 newctag = ( ctag_t * ) malloc( sizeof( ctag_t ) );
543 memset( newctag, 0, sizeof( ctag_t ) );
544 ctag->next = newctag;
545 newctag->prev = ctag;
551 strncpy( ctag->fname, fname, MAXNAME );
552 strncpy( ctag->name, name, MAXNAME );
553 strncpy( ctag->decl, decl, MAXLINE );
554 strncpy( ctag->type, type, MAXNAME );
555 ctag->linenum = linenum;
558 /********** addList */
559 /****f* ROBOhdrs/parseCtagsX
563 * static int parseCtagsX(FILE *fp)
567 parseCtagsX( FILE * fp )
569 char buf[MAXLINE + 1];
570 int lnum = 0, tagsParsed = 0;
572 while ( fgets( buf, MAXLINE, fp ) != NULL )
574 char decl[MAXNAME + 1], name[MAXNAME + 1];
575 char fname[MAXNAME + 1], type[MAXNAME + 1];
579 /* extract info from a line */
580 if ( parseCtagsXLine( buf, fname, name, decl, type, &linenum ) )
582 printf( "error parsing line (%d)", lnum );
586 addList( ctags, fname, name, decl, type, linenum );
595 /********** parseCtagsX */
597 /****f* ROBOhdrs/roboFileHeader
601 * Insert source file header.
603 * static void roboFileHeader(FILE *fp, char *proj, char *fname)
607 roboFileHeader( FILE * fp, char *proj, char *fname )
611 s = remark_markers[srcRem];
612 fprintf( fp, "%sh* %s/%s\n", header_markers[srcSta],
613 ( proj[0] ? proj : fname ), fname );
614 fprintf( fp, "%s NAME\n", s );
615 fprintf( fp, "%s %s\n", s, fname );
618 fprintf( fp, "%s %s\n", s, vcTag );
620 fprintf( fp, "%s DESCRIPTION\n", s );
621 fprintf( fp, "%s*******%s\n", s,
622 ( end_remark_markers[srcEnd] ? end_remark_markers[srcEnd] :
626 /********** roboFileHeader */
628 /****f* ROBOhdrs/roboHeader
632 * static void roboHeader(FILE *fp, char *fname, char *name, char *type, char *decl)
636 roboHeader( FILE * fp, char *fname, char *name, char *type, char *decl )
641 s = remark_markers[srcRem];
642 if ( type[0] == 'v' )
644 fprintf( fp, "%sv* %s/%s\n", header_markers[srcSta], fname, name );
646 else if ( type[0] == 'm' )
648 fprintf( fp, "%sd* %s/%s\n", header_markers[srcSta], fname, name );
651 else if ( type[0] == 's' )
653 fprintf( fp, "/****s* %s/%s\n", fname, name );
658 fprintf( fp, "%sf* %s/%s\n", header_markers[srcSta], fname, name );
661 fprintf( fp, "%s NAME\n%s %s\n", s, s, name );
662 if ( type[0] != 'm' )
664 fprintf( fp, "%s SYNOPSIS\n%s %s\n", s, s, decl );
668 for ( c = custhdrs;; )
670 fprintf( fp, "%s %s\n", s, c->name );
684 fprintf( fp, "%s SOURCE\n%s\n", s,
685 ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] :
690 fprintf( fp, "%s***%s\n", s,
691 ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] :
696 /********** roboHeader */
698 /****f* ROBOhdrs/insertSrcEnd
702 * static void insertSrcEnd(FILE *fp, char *funcname)
707 insertSrcEnd( FILE * fp, char *funcname )
709 fprintf( fp, "%s********* %s %s\n", end_markers[srcEnd], funcname,
710 ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] :
714 /********** insertSrcEnd */
716 /****f* ROBOhdrs/insertHeaders
720 * static void insertHeaders(ctags_t *e, char *project, char *dstpath, char *srcpath)
724 insertHeaders( ctags_t * e, char *project, char *dstpath, char *srcpath )
727 ctag_t *ctag = e->ctag;
728 int lnum = 0, funcline = 0;
729 char buf[MAXLINE], *funcname = 0;
731 if ( !ctag || !dstpath || !srcpath )
736 assert( ofp = fopen( dstpath, "w" ) );
737 assert( ifp = fopen( srcpath, "r" ) );
739 /* include file header only if project name is defined */
742 roboFileHeader( ofp, project, dstpath );
745 while ( fgets( buf, MAXLINE, ifp ) != NULL )
754 if ( incSrc && funcline && lnum >= funcline
755 && ctag->linenum == lnum )
758 insertSrcEnd( ofp, funcname );
760 if ( ctag->linenum == lnum )
762 if ( typeOk( ctag->type ) )
764 roboHeader( ofp, ctag->fname, ctag->name, ctag->type,
767 funcname = ctag->name;
771 else if ( ctag->next )
779 } /* end ctag loop */
780 fprintf( ofp, "%s", buf );
783 if ( incSrc && funcline )
785 insertSrcEnd( ofp, funcname );
792 /********** insertHeaders */
793 /****f* ROBOhdrs/doCtagsExec
797 * static FILE * doCtagsExec(char *fname)
801 doCtagsExec( char *fname )
805 char *mybin, *bin = "ctags";
807 mybin = ( ctagsBin[0] ? ctagsBin : bin );
809 if ( pipe( fd ) == -1 )
811 fprintf( stderr, "pipe failed\n" );
815 if ( ( pid = fork( ) ) == 0 )
820 if ( execlp( mybin, mybin, "-x", fname, NULL ) == -1 )
822 fprintf( stderr, "execlp failed\n" );
826 else if ( pid == -1 )
828 fprintf( stderr, "fork failed\n" );
837 if ( ( incoming = fdopen( 0, "r" ) ) == NULL )
839 fprintf( stderr, "fdopen failed\n" );
847 /********** doCtagsExec */
848 /****f* ROBOhdrs/doFile
852 * static void doFile(char *proj, char *fname)
856 doFile( char *proj, char *fname )
861 sprintf( buf, "/bin/cp -p %s %s~", fname, fname );
864 if ( parseCtagsX( doCtagsExec( fname ) ) < 1 )
866 fprintf( stderr, "no tags\n" );
870 arrangeCtags( ctags );
871 sprintf( buf, "%s~", fname );
872 insertHeaders( ctags, proj, fname, buf );
875 /********** doFile */
876 /****f* ROBOhdrs/cleanUp
880 * static void cleanUp(void)
889 /********** cleanUp */
892 /****f* ROBOhdrs/main
896 * int main(int argc, char **argv)
900 main( int argc, char **argv )
903 cmdLine( argc, argv );
908 doFile( projName, argv[0] );
921 #endif /* HAVE_FORK */