ROBOhdrs

[ Top ] [ Modules ]

NAME

robohdrs

DESCRIPTION

Standalone program to insert ROBODoc headers to source code files. This program processes one source file at the time. Existing ROBODoc headers, if any, are not checked for. Beware since this may result in double headers. Current working directory should be the same as where the source file is located.

USES

Exuberant Ctags 5.3.1 or newer required

USAGE

robohdrs [options] <source file>

EXAMPLE

robohdrs -p myproj test1.c robohdrs -s -p myproj -i "MODIFICATION HISTORY" -i IDEAS test2.c

Type `robohdrs -h' to see all command line options.

TODO

SEE ALSO

ROBODoc https://sourceforge.net/projects/robodoc/ Exuberant Ctags http://ctags.sourceforge.net/

COPYRIGHT

(c) 2003 Frans Slothouber and Petteri Kettunen Copying policy: GPL


addList

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

addList

SYNOPSIS

*    static void addList(ctags_t *e, char *fname, char *name, char *decl, char *type, int linenum)

SOURCE

static void
addList( ctags_t * e, char *fname, char *name, char *decl, char *type,
         int linenum )
{
    ctag_t             *newctag, *ctag = e->ctag;

    if ( !ctag )
    {
        /* empty list */
        ctag = ( ctag_t * ) malloc( sizeof( ctag_t ) );
        assert( ctag );
        memset( ctag, 0, sizeof( ctag_t ) );
        e->ctag = ctag;
    }
    else
    {
        while ( ctag->next )
        {
            ctag = ctag->next;
        }
        newctag = ( ctag_t * ) malloc( sizeof( ctag_t ) );
        assert( newctag );
        memset( newctag, 0, sizeof( ctag_t ) );
        ctag->next = newctag;
        newctag->prev = ctag;
        ctag = newctag;
    }

    e->cnt++;

    strncpy( ctag->fname, fname, MAXNAME );
    strncpy( ctag->name, name, MAXNAME );
    strncpy( ctag->decl, decl, MAXLINE );
    strncpy( ctag->type, type, MAXNAME );
    ctag->linenum = linenum;
}

arrangeCtags

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

arrangeCtags

SYNOPSIS

*    static void arrangeCtags(ctags_t *e)

SOURCE

static void
arrangeCtags( ctags_t * e )
{
    ctag_t             *tmp, *ctag = e->ctag, *ep;

    assert( e && e->cnt && e->ctag );
    tmp = ( ctag_t * ) malloc( e->cnt * sizeof( ctag_t ) );
    assert( tmp );

    for ( ep = tmp;; )
    {
        memcpy( ep++, ctag, sizeof( ctag_t ) );
        if ( ctag->next )
        {
            ctag = ctag->next;
        }
        else
        {
            break;
        }
    }

    qsort( tmp, ( size_t ) ( e->cnt ), sizeof( ctag_t ), linenumCompare );
    /* TODO: free ctag */
    e->ctag = tmp;
}

cleanUp

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

cleanUp

SYNOPSIS

*    static void cleanUp(void)

SOURCE

static void
cleanUp( void )
{

}

cmdLine

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

cmdLine

SYNOPSIS

*    static void cmdLine(int argc, char **argv)

SOURCE

static void
cmdLine( int argc, char **argv )
{
    int                 ch;
    custhdr_t          *c, *nc;

    while ( ( ch = getopt( argc, argv, "i:l:p:st:x:" ) ) != -1 )
        switch ( ch )
        {

        case 's':
            /* include source item */
            incSrc = 1;
            break;

        case 't':
            /* specify version control tag */
            strncpy( vcTag, optarg, MAXNAME );
            break;

        case 'p':
            /* specify project name */
            strncpy( projName, optarg, MAXNAME );
            break;

        case 'i':
            if ( !custhdrs )
            {
                assert( ( custhdrs =
                          ( custhdr_t * ) malloc( sizeof( custhdr_t ) ) ) );
                custhdrs->next = 0;
                c = custhdrs;
            }
            else
            {
                c = custhdrs;
                while ( c->next )
                {
                    c = c->next;
                }
                assert( ( nc =
                          ( custhdr_t * ) malloc( sizeof( custhdr_t ) ) ) );
                nc->next = 0;
                c = c->next = nc;
            }
            strncpy( c->name, optarg, MAXNAME );
            break;

        case 'l':
            if ( optarg[0] == 's' && strcmp( optarg, "script" ) == 0 )
            {
                srcSta = SRC_SCRIPT;
                srcRem = SRC_R_SCRIPT;
                srcEnd = SRC_E_SCRIPT;
            }
            else if ( optarg[0] == 'f' && strcmp( optarg, "fortran" ) == 0 )
            {
                srcSta = SRC_FORTRAN;
                srcRem = SRC_R_FORTRAN;
                srcEnd = SRC_E_FORTRAN;
            }
            else if ( optarg[0] == 'f' && strcmp( optarg, "fortran90" ) == 0 )
            {
                srcSta = SRC_F90;
                srcRem = SRC_R_F90;
                srcEnd = SRC_E_F90;
            }
            else if ( optarg[0] == 't' && strcmp( optarg, "tex" ) == 0 )
            {
                srcSta = SRC_TEX;
                srcRem = SRC_R_TEX;
                srcEnd = SRC_E_TEX;
            }
            else if ( optarg[0] == 'a' && strcmp( optarg, "acm" ) == 0 )
            {
                srcSta = SRC_ACM;
                srcRem = SRC_R_ACM;
                srcEnd = SRC_E_ACM;
            }
            else
            {
                usage(  );
            }
            break;

        case 'x':
            strncpy( ctagsBin, optarg, MAXNAME );
            break;

        case '?':
        case 'h':
        default:
            usage(  );
            break;
        }
}

ctags

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

ctags

SYNOPSIS

*    static ctags_t *ctags;

SOURCE

static ctags_t     *ctags;

ctagsBin

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

ctagsBin

SOURCE

static char         ctagsBin[MAXNAME];

custhdrs

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

custhdrs

SYNOPSIS

*    static custhdr_t *custhdrs = 0;

SOURCE

static custhdr_t   *custhdrs = 0;

doCtagsExec

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

doCtagsExec

SYNOPSIS

*    static FILE * doCtagsExec(char *fname)

SOURCE

static FILE        *
doCtagsExec( char *fname )
{
    int                 fd[2], pid;
    FILE               *incoming = NULL;
    char               *mybin, *bin = "ctags";

    mybin = ( ctagsBin[0] ? ctagsBin : bin );

    if ( pipe( fd ) == -1 )
    {
        fprintf( stderr, "pipe failed\n" );
        exit( 1 );
    }

    if ( ( pid = fork(  ) ) == 0 )
    {
        close( 1 );
        dup( fd[1] );
        close( fd[0] );
        if ( execlp( mybin, mybin, "-x", fname, NULL ) == -1 )
        {
            fprintf( stderr, "execlp failed\n" );
            exit( 1 );
        }
    }
    else if ( pid == -1 )
    {
        fprintf( stderr, "fork failed\n" );
        exit( 1 );
    }
    else
    {
        close( 0 );
        dup( fd[0] );
        close( fd[1] );

        if ( ( incoming = fdopen( 0, "r" ) ) == NULL )
        {
            fprintf( stderr, "fdopen failed\n" );
            exit( 1 );
        }
    }

    return incoming;
}

doFile

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

doFile

SYNOPSIS

*    static void doFile(char *proj, char *fname)

SOURCE

static void
doFile( char *proj, char *fname )
{
    char                buf[MAXLINE];

    /* backup */
    sprintf( buf, "/bin/cp -p %s %s~", fname, fname );
    system( buf );

    if ( parseCtagsX( doCtagsExec( fname ) ) < 1 )
    {
        fprintf( stderr, "no tags\n" );
        exit( 1 );
    }

    arrangeCtags( ctags );
    sprintf( buf, "%s~", fname );
    insertHeaders( ctags, proj, fname, buf );
}

incSrc

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

incSrc

SYNOPSIS

*    static char incSrc = 0;

SOURCE

static char         incSrc = 0;

initMe

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

initMe

SYNOPSIS

*    static void initMe(void)

SOURCE

static void
initMe( void )
{
    ctags = &myctags;
    memset( ctags, 0, sizeof( ctags_t ) );
    projName[0] = '\0';
    ctagsBin[0] = '\0';
    vcTag[0] = '\0';
}

insertHeaders

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

insertHeaders

SYNOPSIS

*    static void insertHeaders(ctags_t *e, char *project, char *dstpath, char *srcpath)

SOURCE

static void
insertHeaders( ctags_t * e, char *project, char *dstpath, char *srcpath )
{
    FILE               *ifp, *ofp;
    ctag_t             *ctag = e->ctag;
    int                 lnum = 0, funcline = 0;
    char                buf[MAXLINE], *funcname = 0;

    if ( !ctag || !dstpath || !srcpath )
    {
        return;
    }

    assert( ofp = fopen( dstpath, "w" ) );
    assert( ifp = fopen( srcpath, "r" ) );

    /* include file header only if project name is defined */
    if ( project )
    {
        roboFileHeader( ofp, project, dstpath );
    }

    while ( fgets( buf, MAXLINE, ifp ) != NULL )
    {
        lnum++;
        while ( ctag->prev )
        {
            ctag = ctag->prev;
        }
        for ( ;; )
        {
            if ( incSrc && funcline && lnum >= funcline
                 && ctag->linenum == lnum )
            {
                funcline = 0;
                insertSrcEnd( ofp, funcname );
            }
            if ( ctag->linenum == lnum )
            {
                if ( typeOk( ctag->type ) )
                {
                    roboHeader( ofp, ctag->fname, ctag->name, ctag->type,
                                ctag->decl );
                    funcline = lnum;
                    funcname = ctag->name;
                }
                break;
            }
            else if ( ctag->next )
            {
                ctag = ctag->next;
            }
            else
            {
                break;
            }
        }                       /* end ctag loop */
        fprintf( ofp, "%s", buf );
    }

    if ( incSrc && funcline )
    {
        insertSrcEnd( ofp, funcname );
    }

    fclose( ifp );
    fclose( ofp );
}

insertSrcEnd

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

insertSrcEnd

SYNOPSIS

*    static void insertSrcEnd(FILE *fp, char *funcname)

SOURCE

static void
insertSrcEnd( FILE * fp, char *funcname )
{
    fprintf( fp, "%s********* %s %s\n", end_markers[srcEnd], funcname,
             ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] :
               "" ) );
}

linenumCompare

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

linenumCompare

SYNOPSIS

*    static int linenumCompare(void const * a, void const * b)

SOURCE

static int
linenumCompare( void const *a, void const *b )
{
    ctag_t             *ea = ( ctag_t * ) a, *eb = ( ctag_t * ) b;

    return ( ea->linenum - eb->linenum );
}

main

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

main

SYNOPSIS

*    int main(int argc, char **argv)

SOURCE

int
main( int argc, char **argv )
{
    initMe(  );
    cmdLine( argc, argv );
    argc -= optind;
    argv += optind;
    if ( argc == 1 )
    {
        doFile( projName, argv[0] );
    }
    else
    {
        usage(  );
    }
    cleanUp(  );
    return 0;
}

MAXLINE

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

MAXLINE

SOURCE

#define MAXLINE 10240

MAXNAME

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

MAXNAME

SOURCE

#define MAXNAME 1024

myctags

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

myctags

SYNOPSIS

*    static ctags_t myctags;

SOURCE

static ctags_t      myctags;

parseCtagsX

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

parseCtagsX

SYNOPSIS

*    static int parseCtagsX(FILE *fp)

SOURCE

static int
parseCtagsX( FILE * fp )
{
    char                buf[MAXLINE + 1];
    int                 lnum = 0, tagsParsed = 0;

    while ( fgets( buf, MAXLINE, fp ) != NULL )
    {
        char                decl[MAXNAME + 1], name[MAXNAME + 1];
        char                fname[MAXNAME + 1], type[MAXNAME + 1];
        int                 linenum;

        lnum++;
        /* extract info from a line */
        if ( parseCtagsXLine( buf, fname, name, decl, type, &linenum ) )
        {
            printf( "error parsing line (%d)", lnum );
        }
        else
        {
            addList( ctags, fname, name, decl, type, linenum );
            tagsParsed++;
        }
    }                           /* end while() */
    fclose( fp );

    return tagsParsed;
}

parseCtagsXLine

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

parseCtagsXLine

SYNOPSIS

*    static int parseCtagsXLine(char *buf, char *fname, char *name, char *decl, char *type, int *linenum)

SOURCE

static int
parseCtagsXLine( char *buf, char *fname, char *name, char *decl, char *type,
                 int *linenum )
{
    char               *t, *short;

    /* ctags -x output is: */
    /* usage            function     56 test.c           void usage(void) */
    sscanf( buf, "%s%s%d%s", name, type, linenum, fname );
    short = strstr( buf, fname );
    while ( *short++ != ' ' )
    {
    }
    while ( *short == ' ' )
    {
        ++short;
    }
    t = decl;
    while ( ( *t = *short++ ) != '\n' )
    {
        ++t;
    }
    *t = '\0';

    return 0;
}

PROGNAME

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

PROGNAME

SOURCE

#define PROGNAME "robohdrs"

PROGVERSION

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

PROGVERSION

SOURCE

#define PROGVERSION "0.01"

projName

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

projName

SYNOPSIS

*    static char projName[MAXNAME];

SOURCE

static char         projName[MAXNAME];

roboFileHeader

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

roboFileHeader

FUNCTION

Insert source file header.

SYNOPSIS

*    static void roboFileHeader(FILE *fp, char *proj, char *fname)

SOURCE

static void
roboFileHeader( FILE * fp, char *proj, char *fname )
{
    char               *short;

    short = remark_markers[srcRem];
    fprintf( fp, "%sh* %s/%s\n", header_markers[srcSta],
             ( proj[0] ? proj : fname ), fname );
    fprintf( fp, "%s  NAME\n", short );
    fprintf( fp, "%s    %s\n", short, fname );
    if ( *vcTag )
    {
        fprintf( fp, "%s    %s\n", short, vcTag );
    }
    fprintf( fp, "%s  DESCRIPTION\n", short );
    fprintf( fp, "%s*******%s\n", short,
             ( end_remark_markers[srcEnd] ? end_remark_markers[srcEnd] :
               "" ) );
}

roboHeader

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

roboHeader

SYNOPSIS

*    static void roboHeader(FILE *fp, char *fname, char *name, char *type, char *decl)

SOURCE

static void
roboHeader( FILE * fp, char *fname, char *name, char *type, char *decl )
{
    custhdr_t          *c;
    char               *short;

    short = remark_markers[srcRem];
    if ( type[0] == 'v' )
    {
        fprintf( fp, "%sv* %s/%s\n", header_markers[srcSta], fname, name );
    }
    else if ( type[0] == 'm' )
    {
        fprintf( fp, "%sd* %s/%s\n", header_markers[srcSta], fname, name );
    }
#if 0
    else if ( type[0] == 's' )
    {
        fprintf( fp, "/****s* %s/%s\n", fname, name );
    }
#endif
    else
    {
        fprintf( fp, "%sf* %s/%s\n", header_markers[srcSta], fname, name );
    }

    fprintf( fp, "%s  NAME\n%s    %s\n", short, short, name );
    if ( type[0] != 'm' )
    {
        fprintf( fp, "%s  SYNOPSIS\n%s    %s\n", short, short, decl );
    }
    if ( custhdrs )
    {
        for ( c = custhdrs;; )
        {
            fprintf( fp, "%s  %s\n", short, c->name );
            if ( c->next )
            {
                c = c->next;
            }
            else
            {
                break;
            }
        }
    }

    if ( incSrc )
    {
        fprintf( fp, "%s  SOURCE\n%s\n", short,
                 ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] :
                   short ) );
    }
    else
    {
        fprintf( fp, "%s***%s\n", short,
                 ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] :
                   "" ) );
    }
}

srcSta

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

srcSta

SEE ALSO

src_constants

SOURCE

static short        srcSta = SRC_C;
static short        srcRem = SRC_R_C;
static short        srcEnd = SRC_E_C;

typeOk

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

typeOk

SYNOPSIS

*    static int typeOk(char *t)

SOURCE

static int
typeOk( char *t )
{
    /* return 1 if supported type for headers */
    if ( t[0] == 'f' && strncmp( t, "function", 8 ) == 0 )
    {
        return 1;
    }
    else if ( t[0] == 'v' && strncmp( t, "variable", 8 ) == 0 )
    {
        return 1;               /* global variable */
    }
#if 0
    else if ( t[0] == 's' && strncmp( t, "struct", 6 ) == 0 )
    {
        return 1;
    }
#endif
    else if ( t[0] == 'm' && strncmp( t, "macro", 5 ) == 0 )
    {
        return 1;
    }
    return 0;
}

usage

[ Top ] [ ROBOhdrs ] [ Functions ]

NAME

usage

SYNOPSIS

*    static void usage(void)

SOURCE

static void
usage( void )
{
    printf( "%s version %s, robodoc header insertor\n", PROGNAME,
            PROGVERSION );
    printf( "(c) 2003 Frans Slothouber and Petteri Kettunen\n" );
    printf( "%s comes with ABSOLUTELY NO WARRANTY.\n", PROGNAME );
    printf
        ( "This is free software, and you are welcome to redistribute it\n" );
    printf( "under the GNU GENERAL PUBLIC LICENSE terms and conditions.\n" );
    printf( "usage: %s [options] <source file>\n", PROGNAME );
    printf( "Options are as follows:\n" );
    printf( "  -h   show this help text\n" );
    printf
        ( "  -i   specify header item (repeat to include multiple items)\n" );
    printf( "  -l   specify source code language (default C/C++)\n" );
    printf
        ( "       Supported options are: fortran, fortran90, script, and tex.\n" );
    printf( "  -p   specify project name\n" );
    printf( "  -s   include SOURCE item\n" );
    printf( "  -t   specify CVS/RCS tag to be inserted into a file\n" );
    printf( "  -x   specify path to ctags binary\n" );
    printf( "NOTE: requires Exuberant Ctags 5.3.1 (or newer)\n" );
    printf( "EXAMPLES:\n" );
    printf
        ( "robohdrs -s -p myproj -i \"MODIFICATION HISTORY\" -i IDEAS test.c\n" );
    printf
        ( "robohdrs -s -p myproj -l script -t '%cHeader:%c' test.tcl\n", '$', '$' );
    exit( 1 );
}

vcTag

[ Top ] [ ROBOhdrs ] [ Variables ]

NAME

vcTag

DESCRIPTION

Version control tag string. This is always specified by the user.

SYNOPSIS

*    static char vcTag[MAXNAME];

SOURCE

static char         vcTag[MAXNAME];