home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / nethack-3.1 / sys / amiga / splitter / arg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-10  |  5.2 KB  |  240 lines

  1. /*    SCCS Id: @(#)arg.c        3.1   93/01/08
  2. /*    Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993 */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * arg.c - semi-generic argument parser
  7.  */
  8. #include <exec/types.h>
  9. #include <exec/lists.h>
  10. #include <proto/exec.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <ctype.h>
  14. #include <string.h>
  15. #include "arg.h"
  16.  
  17. static char *a_desc;
  18. static int a_argc;
  19. static char **a_argv;
  20. static int a_apos;
  21. static char more=0;
  22. static char *argp;
  23.  
  24. static char *arg_fillbuf(void);
  25. /*static char *splitline(struct fentry *); L505 bug? see below */
  26. static char *splitline2(char *);
  27.  
  28. char *argarg;
  29.  
  30. #ifndef ARGLEN
  31. #define ARGLEN 134        /* longest line we can deal with */
  32. #endif
  33.  
  34. static struct List flist;    /* stack of files to read from */
  35. struct fentry {            /* structures on that stack */
  36.     struct Node node;
  37.     FILE *fp;
  38.     char *ptr;
  39.     char buf[ARGLEN];
  40. };
  41.  
  42. static char *splitline(struct fentry *); /* L505 bug? can't be above def  */
  43.  
  44. #define ListHead(x) ((x).lh_Head)
  45. #define ListEmpty(x) (!(x).lh_Head->ln_Succ)
  46.  
  47. /*
  48.  * arg_init(description string, argc, argv)
  49.  * Called by user to initialize system - must be called before calling
  50.  * other entry points.  desc is getopt(3) style description string; argc and
  51.  * argv are the arguments to main().
  52.  */
  53. void arg_init(char *desc,int argc,char *argv[]){
  54.     a_desc=desc;
  55.     a_argc=argc;
  56.     a_argv=argv;
  57.     a_apos=0;
  58.     NewList(&flist);
  59. }
  60.  
  61. /*
  62.  * arg_next(void)
  63.  * Called by user to return each argument.  See arg.h for exceptional return
  64.  * values - normally returns the argument flag found; if a flag takes an
  65.  * argument, the argument is returned in argarg.
  66.  * An argument beginning with @ is taken to be a file name from which to read
  67.  * further arguments - such files are held on a stack and read as found, then
  68.  * the previous file (or the command line) is continued.
  69.  * In an argument file, the following are recognized:
  70.  * #  as the first character of a line only, causes the line to be ignored
  71.  * @  recursively read arguments from another file
  72.  * \n embedded newline
  73.  * \r embedded carriage return
  74.  * \f embedded formfeed
  75.  * \b embedded backspace
  76.  * \  literal next character (except above)
  77.  * "  start/end double quoted string
  78.  * '  start/end single quoted string
  79.  */
  80. int arg_next(){
  81.     char *cp;
  82.     char key;
  83.  
  84.     if(!more){                /* anything still buffered? */
  85.         if(!(argp=arg_fillbuf())){    /* nothing more */
  86.             argarg=0;        /* be neat */
  87.             return(ARG_DONE);
  88.         }
  89.     }
  90.     if(more ||(*argp=='-' && argp++)){
  91.         for(cp=a_desc;*cp;cp++){
  92.             if(*cp== *argp){
  93.                 key=*argp++;
  94.                 if(*++cp==':'){
  95.                     if(*argp){
  96.                         argarg=argp;
  97.                     }else{
  98.                         argarg=arg_fillbuf();
  99.                         if(!argarg)return(ARG_ERROR);
  100.                     }
  101.                     more=0;
  102.                 }else{
  103.                     argarg=0; /* doesn't take an arg */
  104.                     more= *argp;
  105.                 }
  106.                 return((int) key);
  107.             }
  108.         }
  109.         return(ARG_ERROR);    /* no such option */
  110.     }else{
  111.         argarg=argp;
  112.         more=0;
  113.         return(ARG_FREE);
  114.     }
  115. }
  116.  
  117. static char *arg_fillbuf(){
  118.     char *p,*nlp;;
  119.  
  120.     if(ListEmpty(flist)){
  121.         if(++a_apos>a_argc)return(0);
  122.         p=a_argv[a_apos];
  123.     }else{
  124.         struct fentry *f=(struct fentry *)ListHead(flist);
  125.         if(!f->ptr){
  126.             do{
  127.                 if(!fgets(f->buf,ARGLEN,f->fp)){
  128.                     if(ferror(f->fp)){
  129.                         fprintf(stderr,
  130.                             "I/O error on @file\n");
  131.                         return(0);
  132.                     }
  133.                     fclose(f->fp);
  134.                     RemHead(&flist);
  135.                     free(f);
  136.                     return(arg_fillbuf());
  137.                 }
  138.             }while(f->buf[0]=='#');    /* comment */
  139.             if(nlp=strchr(f->buf,'\n'))*nlp='\0';
  140.         }
  141.         p=splitline(f);
  142.         if(p== (char *)-1)return(0);        /* error */
  143.         if(!p)return(arg_fillbuf());    /* skip blank line */
  144.     }
  145.     if(p && *p=='@'){
  146.         struct fentry *f=calloc(sizeof(struct fentry),1);
  147.         f->fp=fopen(++p,"r");
  148.         if(!(f->fp)){
  149.             fprintf(stderr,"Can't open @file '%s'\n",p);
  150.             free(f);
  151.             return(0);
  152.         }
  153.         AddHead(&flist,(struct Node *)f);
  154.         return(arg_fillbuf());
  155.     }
  156.     return(p);
  157. }
  158.  
  159. static char *splitline(struct fentry *f){
  160.     char *out=(f->ptr?f->ptr:f->buf);
  161.     char *ret;
  162.     while(*out && isspace(*out))out++;
  163.     if(!*out)return(0);    /* blank line or spaces at end */
  164.     ret=out;
  165.     while(*out && !isspace(*out)){
  166.         switch(*out){
  167.         case '\\':
  168.         case '\"':
  169.         case '\'':
  170.             out=splitline2(out);
  171.             if(!out)return((char *)-1);    /* error */
  172.             break;
  173.         default:
  174.             out++;
  175.             break;
  176.         }
  177.     }
  178.     if(!*out){
  179.         f->ptr=0;    /* this was last arg on current line */
  180.     }else{
  181.         *out='\0';
  182.         f->ptr= ++out;
  183.         if(!(*f->ptr))f->ptr=0;
  184.     }
  185.     return ret;
  186. }
  187.  
  188. static char *splitline2(char *p){
  189.     char *out=p;
  190.     char c;
  191.     char dq=0,sq=0;
  192.     while(*p){
  193.         switch(c= *p++){
  194.         case '\\':
  195.             switch(c= *p++){
  196.             case 'n':    *out++='\n';break;
  197.             case 'r':    *out++='\r';break;
  198.             case 'f':    *out++='\f';break;
  199.             case 'b':    *out++='\b';break;
  200.             case 0:        p--;break;
  201.             default:    *out++=c;break;
  202.             }
  203.             break;
  204.         case '\"':    if(sq){
  205.                     *out++=c;
  206.                 }else{
  207.                     dq=1-dq;
  208.                 }
  209.                 break;
  210.         case '\'':    if(dq){
  211.                     *out++=c;
  212.                 }else{
  213.                     sq=1-sq;
  214.                 }
  215.                 break;
  216.         case ' ':    if(!sq && !dq){*out=0;return(p-1);}
  217.                 *out++=' ';
  218.                 break;
  219.         default:    *out++=c;break;
  220.         }
  221.     }
  222.     if(sq ||dq){
  223.         fprintf(stderr,"Warning - quote error in @file\n");
  224.         return((char *)-1);
  225.     }
  226.     *out=0;
  227.     return(p);
  228. }
  229.  
  230. #ifdef DEBUG_ARG
  231. main(int argc,char *argv[]){
  232.     int x=0;
  233.     arg_init(getenv("test_arg"),argc,argv);
  234.     do{
  235.         x=arg_next();
  236.         printf("r=%d (%d)'%s'\n",x,argarg,argarg);
  237.     }while(x >= 0);
  238. }
  239. #endif /* DEBUG_ARG */
  240.