Annotation of coherent/g/usr/bin/vi/vmswild.c, revision 1.1.1.1

1.1       root        1: /*
                      2:    This 'C' module may be included prior to the ``main'' programs on VMS in
                      3:    order to allow 'C' arguments to contain redirection symbols (<,>,>>) and
                      4:    VMS wild cards (*,% ...], [-).  By including this module, two programs
                      5:    redirect() and expand() are run prior to turning control over to
                      6:    your main() entry point.
                      7: 
                      8: /*
                      9:     redirect-- Gregg Townsend circa 1983,
                     10:     expand-- John Campbell circa 1987
                     11: 
                     12:    This code is public domain, others may use it freely. Credit, however, to
                     13:    Gregg Townsend (who wrote ``redirect()'') and John Campbell (who followed
                     14:    with ``expand()'') would be appreciated.  If someone writes the next
                     15:    logical successor ``pipe()'', please email a copy to
                     16:    ...!arizona!naucse!jdc (John Campbell) :-).
                     17: */
                     18: 
                     19: #include <rms>   /* No easy way to tell if this has already been included. */
                     20: #ifndef ERANGE   /* Include only if missing. */
                     21: /* #include <stdlib>  causes lots of warnings. */
                     22: #endif
                     23: #include <stdio.h>  /* Stdio.h won't include itself twice. */
                     24: 
                     25: /* Expansion of wild cards is done using RMS. */
                     26: typedef struct NAMBLK { struct NAM nam;         /* VMS nam block structure */
                     27:                  char es[NAM$C_MAXRSS],         /* Extended string         */
                     28:                       rs[NAM$C_MAXRSS];         /* Resultant string        */
                     29:                };
                     30: 
                     31: #define ErrorExit 2
                     32: 
                     33: /* Allow the user to override _N_FARGS or _E_FLAG if they wish. */
                     34: #ifndef _N_FARGS
                     35: #define _N_FARGS 0
                     36: #endif
                     37: #ifndef _E_FLAG
                     38: #define _E_FLAG 2
                     39: #endif
                     40: /*
                     41:    Since the following will possibly be included in a single module, try
                     42:    hard to avoid name conflicts. (Just being static doesn't cut it if
                     43:    compiled in the same module.)
                     44: */
                     45: #define redirect     _r_edirect
                     46: #define filearg      _f_ilearg
                     47: #define expand       _e_xpand
                     48: #define wild_found   _w_ild_found
                     49: #define wild_expand  _w_ild_expand
                     50: 
                     51: main(argc, argv, envp)
                     52: int argc;
                     53: char *argv[], *envp[];
                     54: {
                     55:    char **expand();
                     56: 
                     57:    redirect (&argc, argv, _N_FARGS);
                     58:    argv = expand (&argc, argv, _E_FLAG);
                     59: 
                     60: /* Make the user's main entry point this routine's entry point. */
                     61: #define main _user_main
                     62:    _user_main (argc, argv, envp);
                     63: }
                     64: 
                     65: /*
                     66:  * redirect(&argc,argv,nfargs) - redirect standard I/O
                     67:  *    int *argc         number of command arguments (from call to main)
                     68:  *    char *argv[]      command argument list (from call to main)
                     69:  *    int nfargs        number of filename arguments to process
                     70:  *
                     71:  * argc and argv will be adjusted by redirect.
                     72:  *
                     73:  * redirect processes a program's command argument list and handles redirection
                     74:  * of stdin, and stdout.  Any arguments which redirect I/O are removed from the
                     75:  * argument list, and argc is adjusted accordingly.  redirect would typically be
                     76:  * called as the first statement in the main program.
                     77:  *
                     78:  * Files are redirected based on syntax or position of command arguments.
                     79:  * Arguments of the following forms always redirect a file:
                     80:  *
                     81:  *    <file     redirects standard input to read the given file
                     82:  *    >file     redirects standard output to write to the given file
                     83:  *    >>file    redirects standard output to append to the given file
                     84:  *
                     85:  * It is often useful to allow alternate input and output files as the
                     86:  * first two command arguments without requiring the <file and >file
                     87:  * syntax.  If the nfargs argument to redirect is 2 or more then the
                     88:  * first two command arguments, if supplied, will be interpreted in this
                     89:  * manner:  the first argument replaces stdin and the second stdout.
                     90:  * A filename of "-" may be specified to occupy a position without
                     91:  * performing any redirection.
                     92:  *
                     93:  * If nfargs is 1, only the first argument will be considered and will
                     94:  * replace standard input if given.  Any arguments processed by setting
                     95:  * nfargs > 0 will be removed from the argument list, and again argc will
                     96:  * be adjusted.  Positional redirection follows syntax-specified
                     97:  * redirection and therefore overrides it.
                     98:  *
                     99:  */
                    100: 
                    101: 
                    102: redirect(argc,argv,nfargs)
                    103: int *argc, nfargs;
                    104: char *argv[];
                    105: {
                    106:    int i;
                    107: 
                    108:    i = 1;
                    109:    while (i < *argc)  {         /* for every command argument... */
                    110:       switch (argv[i][0])  {            /* check first character */
                    111:          case '<':                      /* <file redirects stdin */
                    112:             filearg(argc,argv,i,1,stdin,"r");
                    113:             break;
                    114:          case '>':                      /* >file or >>file redirects stdout */
                    115:             if (argv[i][1] == '>')
                    116:                filearg(argc,argv,i,2,stdout,"a");
                    117:             else
                    118:                filearg(argc,argv,i,1,stdout,"w");
                    119:             break;
                    120:          default:                       /* not recognized, go on to next arg */
                    121:             i++;
                    122:       }
                    123:    }
                    124:    if (nfargs >= 1 && *argc > 1)        /* if positional redirection & 1 arg */
                    125:       filearg(argc,argv,1,0,stdin,"r"); /* then redirect stdin */
                    126:    if (nfargs >= 2 && *argc > 1)        /* likewise for 2nd arg if wanted */
                    127:       filearg(argc,argv,1,0,stdout,"w");/* redirect stdout */
                    128: }
                    129: 
                    130: 
                    131: 
                    132: /* filearg(&argc,argv,n,i,fp,mode) - redirect and remove file argument
                    133:  *    int *argc         number of command arguments (from call to main)
                    134:  *    char *argv[]      command argument list (from call to main)
                    135:  *    int n             argv entry to use as file name and then delete
                    136:  *    int i             first character of file name to use (skip '<' etc.)
                    137:  *    FILE *fp          file pointer for file to reopen (typically stdin etc.)
                    138:  *    char mode[]       file access mode (see freopen spec)
                    139:  */
                    140: 
                    141: filearg(argc,argv,n,i,fp,mode)
                    142: int *argc, n, i;
                    143: char *argv[], mode[];
                    144: FILE *fp;
                    145: {
                    146:    if (strcmp(argv[n]+i,"-"))           /* alter file if arg not "-" */
                    147:       fp = freopen(argv[n]+i,mode,fp);
                    148:    if (fp == NULL)  {                   /* abort on error */
                    149:       fprintf(stderr,"%%can't open %s",argv[n]+i);
                    150:       exit(ErrorExit);
                    151:    }
                    152:    for ( ;  n < *argc;  n++)            /* move down following arguments */
                    153:       argv[n] = argv[n+1];
                    154:    *argc = *argc - 1;                   /* decrement argument count */
                    155: }
                    156: 
                    157: /* EXPAND code. */
                    158: 
                    159: /* Global prototype. */
                    160: char **expand (int *argc, const char *argv[], const int flag);
                    161: /*-
                    162:    ``expand()'' is a routine to expand wild-cards to file specifications.
                    163:    This routine is often used in conjunction with ``redirect()'' to provide
                    164:    both wild card expansion and standard file redirection prior to doing
                    165:    any real work in a 'C' program.
                    166: 
                    167:    Normal usage is to include the following line prior to using argc or
                    168:    argv in main():
                    169: 
                    170:      argv = expand (&argc, argv, 0);
                    171: 
                    172:    ``argc'' will be adjusted by ``expand()'', the return value from expand
                    173:    will replace ``argv''.
                    174: 
                    175:    ``expand()'' processes a program's command argument list and expands any
                    176:    wild cards into zero or more argv entries. Only arguments that posses VMS
                    177:    wild-cards are expanded. Wild cards searched for are ``*'', ``%'',
                    178:    ``...]'', and ``[-''. If the wild-card is found inside a single or double
                    179:    quote ("*" or '%') then they are not counted as wild-cards. Be aware that
                    180:    the expansion of a VMS wild card will match all VMS files, including
                    181:    directory files (".DIR;1").
                    182: 
                    183:    NOTE: The use of quotes in VMS requires thinking about how the CLI expands
                    184:    things before handing the argument line over to your program.  Do not
                    185:    expect "*" to avoid expansion, use """*""" instead.  Likewise, expression
                    186:    substitution precludes the use of (') to quote wild cards:
                    187:            $ A := HELLO
                    188:            $ ECHO 'a'   ! 'C' program that calls ``expand()''
                    189:            hello
                    190:    The easiest way to escape a wild-card may be "'*'".  The point is that
                    191:    ``expand()'' will only recognize quotes passed into main().
                    192: 
                    193:    ``expand()'' references the VMS runtime routines, you will need to
                    194:    link with the 'C' RTL whenever expand is used.
                    195: 
                    196:    Parameters:
                    197: 
                    198:          argc:  Pointer to the number of command arguments (from main),
                    199:                 the contents of this parameter are modified.
                    200: 
                    201:          argv:  Pointer to the initial command argument list (from main),
                    202:                 the contents are copied into a new array which is returned
                    203:                 from this routine.
                    204: 
                    205:          flag:  Flag indicating how to expand wild-cards:
                    206:                    0 - Complete file name expansion
                    207:                    1 - only file name (no directory or version).
                    208:                    2 - directory info and file name (no version).
                    209:                    3 - file name and version info (no directory).
                    210:  -*/
                    211: 
                    212: /* Local prototypes. */
                    213: int wild_found (char *string);
                    214: char **wild_expand (const char *string, char **argv, int *argc,
                    215:                     int extra, int flag);
                    216: /*
                    217:    General note: removing the prototyping and const keywords should
                    218:    allow this code to compile with VMS 'C' compilers prior to version
                    219:    2.3-024.
                    220: */
                    221: 
                    222: 
                    223: char **expand (int *argc, char *argv[], int flag)
                    224: /*
                    225:    Routine to expand all the arguments from main(argc,argv).  The
                    226:    return value is a pointer to a new (expanded) argv array.
                    227: 
                    228:    Parameters:
                    229: 
                    230:          argc:  Pointer to the number of command arguments (from main),
                    231:                 the contents of this parameter are modified.
                    232: 
                    233:          argv:  Pointer to the initial command argument list (from main),
                    234:                 the contents are copied into a new array which is returned
                    235:                 from this routine.
                    236: 
                    237:          flag:  Flag indicating how to expand wild-card:
                    238:                    0 - Complete file name expansion
                    239:                    1 - only file name (no directory or version).
                    240:                    2 - directory info and file name (no version).
                    241:                    3 - file name and version info (no directory).
                    242: */
                    243: {
                    244:    int i, nargc;
                    245:    char **nargv, **wild_expand();
                    246:    char *start, *end;
                    247: 
                    248: /* Get an initial amount of memory for the master nargv array. */
                    249:    if ((nargv = (char **)malloc ((*argc+1) * sizeof (char *))) == NULL) {
                    250:       fprintf (stderr, "Not enough memory to expand argument list\n");
                    251:       exit (ErrorExit);
                    252:    }
                    253: 
                    254: /*
                    255:    Fix the command string so that it only has the name and not the path of
                    256:    the function (more in line with what unix reports with argv[0]
                    257: */
                    258:    start = argv[0];
                    259:    end = argv[0] + strlen (argv[0]);
                    260:    while (start < end) {
                    261:    /* Scan from the back for the first '.' and replace it with a '\0' */
                    262:       if (*end == '.') *end = '\0';
                    263:    /* And trim off path if it is found. */
                    264:       if (*end == ']') {
                    265:          end++;
                    266:          break;
                    267:       }
                    268:       --end;
                    269:    }
                    270:    nargv[0] = end;
                    271: 
                    272: /* Copy each argument, expanding those that have wild characters. */
                    273:    for (nargc = i = 1; i < *argc; i++) {
                    274:       if (wild_found(argv[i]))
                    275:          nargv = wild_expand(argv[i], nargv, &nargc, *argc-i, flag);
                    276:       else
                    277:          nargv[nargc++] = argv[i];
                    278:    }
                    279:    *argc = nargc;
                    280:    nargv[nargc] = NULL;  /* realloc always 0 fills, but... */
                    281: 
                    282:    return nargv;
                    283: }
                    284: 
                    285: 
                    286: static int wild_found (char *string)
                    287: /*
                    288:    Routine to search the given string for a VMS wild-card pattern.
                    289:    Returns 1 if "*", "%", "[-", or "...]" is found.  (This may not
                    290:    be all VMS wild-cards but it is enough for now--anyone that wants
                    291:    to recognize others can change this code.)
                    292: 
                    293:    Parameter:
                    294: 
                    295:       string: '\0' terminated character array.
                    296: */
                    297: {
                    298:    int state = 0;
                    299: 
                    300: /*
                    301:    State of 0 is "rest" state.  State 1 on our way to [-, states 2-4
                    302:    on our way to ...], negative states indicate the two quotes (' -10,
                    303:    " -1).
                    304: */
                    305:    for ( ;*string; string++) {
                    306:       switch (*string) {
                    307:       case '*':
                    308:       case '%':
                    309:          if (state >= 0)
                    310:             return 1;                    /* Unquoted % or * found. */
                    311:       break;
                    312:       case '[':
                    313:          if (state >= 0)
                    314:             state = 1;
                    315:       break;
                    316:       case ']':
                    317:          if (state == 4)
                    318:             return 1;                    /* Unquoted ...] found. */
                    319:          else if (state >= 0)
                    320:             state = 0;
                    321:       break;
                    322:       case '-':
                    323:          if (state == 1)
                    324:             return 1;                    /* Unquoted [- found. */
                    325:          else if (state >= 0)
                    326:             state = 0;
                    327:       break;
                    328:       case '.':
                    329:          if (state == 1 || state == 0)
                    330:             state = 2;                   /* First '.' */
                    331:          else if (state > 1 && state < 5)
                    332:             state++;                     /* ... == states 2, 3, 4 */
                    333:          else if (state >= 0)
                    334:             state = 0;
                    335:       break;
                    336:       case '\'':
                    337:          if (state <= -10)
                    338:             state += 10;           /* One ', possibly one " also */
                    339:          else if (state < 0)
                    340:             state -= 10;           /* 0 ', possibly one " */
                    341:          else
                    342:             state = -10;           /* No ' or " prior to this ' */
                    343:       break;
                    344:       case '"':
                    345:          if (state == -11)
                    346:             state = -10;           /* Both " and ' prior to this. */
                    347:          else if (state == -10)
                    348:             state = -11;           /* A ' prior to this. */
                    349:          else if (state == -1)
                    350:             state = 0;             /* A " prior to this. */
                    351:          else
                    352:             state = -1;            /* No ' or " prior to this " */
                    353:       break;
                    354:       }
                    355:    }
                    356:    return 0;
                    357: }
                    358: 
                    359: 
                    360: static char **wild_expand (const char *wild, char **argv,
                    361:                                         int *argc, int extra, int flag)
                    362: /*
                    363:    Routine to expand wild into new arguments appended to the end
                    364:    of argv[*argc].  This routine must realloc in order to make room
                    365:    for the individual arguments and malloc for enough space for each
                    366:    of the arguments.  The return value is a new **argv.
                    367: 
                    368:    Parameters:
                    369: 
                    370:          wild:  '\0' terminated string that needs to be expanded.
                    371: 
                    372:          argv:  initial starting address of the argv array.
                    373: 
                    374:          argc:  pointer to an integer that tells the current end of the
                    375:                 argument list.
                    376: 
                    377:         extra:  The number of extra pointers that the returned argv
                    378:                 must have available for future assignments.
                    379: 
                    380:          flag:  Flag indicating how to expand wild-card:
                    381:                   0 - Complete file name expansion
                    382:                   1 - only file name (no directory or version).
                    383:                   2 - directory info and file name (no version)
                    384:                   3 - file name and version info (no directory).
                    385: */
                    386: {
                    387:    int more_to_go = 1, err, length, status, len_wild;
                    388:    char *namptr; /* , *strncpy();  Picky, but bothers other main programs */
                    389:    struct FAB fab_blk;
                    390:    struct NAMBLK nam_blk;
                    391: 
                    392:    len_wild = strlen(wild);
                    393: 
                    394: /* Initialize all the fab and nam fields needed for parse and search */
                    395: 
                    396:    fab_blk = cc$rms_fab;                   /* Initialize FAB structure */
                    397: 
                    398:    nam_blk.nam    = cc$rms_nam;            /* Initialize NAM structure */
                    399:    fab_blk.fab$l_dna = ".*";               /* Default file specif.     */
                    400:    fab_blk.fab$b_dns = 2;                  /* Length of default spec.  */
                    401:    fab_blk.fab$l_nam = &nam_blk.nam;       /* Set address of NAM in FAB*/
                    402:    nam_blk.nam.nam$b_ess = NAM$C_MAXRSS;   /* Set extended  string size*/
                    403:    nam_blk.nam.nam$l_esa = &nam_blk.es;    /* and address              */
                    404:    nam_blk.nam.nam$b_rss = NAM$C_MAXRSS;   /* Set resultant string size*/
                    405:    nam_blk.nam.nam$l_rsa = &nam_blk.rs;    /* and address              */
                    406:    nam_blk.nam.nam$l_rlf = NULL;           /* No related file address  */
                    407: 
                    408:    fab_blk.fab$l_fna = wild;           /* Address of file name string  */
                    409:    fab_blk.fab$b_fns = len_wild;       /* Length of file name string   */
                    410: 
                    411: /* Prepare to enter the search loop, parse fab. */
                    412:    err = SYS$PARSE (&fab_blk);
                    413: 
                    414: /* Catch the directory not found error and return no files found. */
                    415:    if (err != RMS$_NORMAL)
                    416:       exit(err);
                    417: 
                    418:    while (more_to_go) {
                    419:       err = SYS$SEARCH (&fab_blk);
                    420:       if (err == RMS$_NMF || err == RMS$_FNF)
                    421:          more_to_go = 0;               /* Done, no more files found */
                    422:       else if (err != RMS$_NORMAL)
                    423:          exit (err);
                    424:       else {
                    425:       /* Count that we now have this many arguments. */
                    426:          (*argc)++;
                    427: 
                    428:       /* Make sure there is room for a new pointer. */
                    429:          if ((argv = realloc (argv, (*argc + extra)*sizeof(char *))) == NULL) {
                    430:             fprintf (stderr, "Not enough memory to expand argument list\n");
                    431:             exit(ErrorExit);
                    432:          }
                    433: 
                    434:       /* Move the right name into the list. */
                    435:          switch (flag) {
                    436:          case 0:             /* Complete file name */
                    437:             length = nam_blk.nam.nam$b_rsl;
                    438:             namptr = &nam_blk.rs;
                    439:             break;
                    440:          case 1:            /* File name only (no directory or version). */
                    441:             length = nam_blk.nam.nam$b_name + nam_blk.nam.nam$b_type;
                    442:             namptr = nam_blk.nam.nam$l_name;
                    443:             break;
                    444:          case 2:            /* directory and file name (no version) */
                    445:             length = nam_blk.nam.nam$b_rsl - nam_blk.nam.nam$b_ver;
                    446:             namptr = &nam_blk.rs;
                    447:             break;
                    448:          case 3:            /* File name and version (no directory). */
                    449:             length = nam_blk.nam.nam$b_name +
                    450:                      nam_blk.nam.nam$b_type +
                    451:                      nam_blk.nam.nam$b_ver;
                    452:             namptr = nam_blk.nam.nam$l_name;
                    453:             break;
                    454:          default:
                    455:             fprintf (stderr, "illegal flag used in VMS expand call\n");
                    456:             exit (ErrorExit);
                    457:          }
                    458:       /* Copy the requested string into the argument array. */
                    459:          if ((argv[*argc-1] = malloc (length+1)) == NULL) {
                    460:             fprintf (stderr, "Not enough memory to expand argument list\n");
                    461:             exit (ErrorExit);
                    462:          }
                    463:          (void )strncpy (argv[*argc-1], namptr, length);
                    464:          argv[*argc-1][length] = '\0';
                    465:       }
                    466:    }
                    467:    return (argv);
                    468: }
                    469: 
                    470: /* Remove all the defines that might affect the user's code. */
                    471: 
                    472: #undef redirect
                    473: #undef filearg
                    474: #undef expand
                    475: #undef wild_found
                    476: #undef wild_expand
                    477: 
                    478: #ifdef __TST_ECHO     /* Example code using expand(). */
                    479: 
                    480: # ifndef __FILE
                    481: #include stdio
                    482: #endif
                    483: 
                    484: main(argc, argv)
                    485: int argc;
                    486: char *argv[];
                    487: /*
                    488:    This main program allows you to run experiments with ``expand()''.
                    489:    Try $ echo *.*, $ echo -f1 [-...]*.*, $ echo -f[0-3] *.*.
                    490:    Questions about using "%", "\", etc. may be answered by testing
                    491:    with this version of echo.
                    492: 
                    493:    To use this, of course, you need to link directly with expand--
                    494:    avoiding the substitution of main with _user_main above.
                    495: */
                    496: {
                    497:     int i, flag=0;
                    498:     char **expand();
                    499: 
                    500:     for(i=1; i<argc; i++)
                    501:         printf("%s %c", argv[i], (i<argc-1) ? '  ':'\n');
                    502: 
                    503:     if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'f')
                    504:        flag = atoi (&argv[1][2]);
                    505: 
                    506:     argv = expand (&argc, argv, flag);
                    507: 
                    508:     printf ("\n\n");
                    509:     for(i=1; i<argc; i++)
                    510:         printf("%s %c", argv[i], flag%2 == 0 ? '\n' : i%4 == 0 ? '\n':'\t');
                    511: 
                    512: }
                    513: #endif  /* __TST_ECHO */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.