Annotation of coherent/g/usr/bin/vi/vmswild.c, revision 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.