home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / c / parse.lha / parse.c < prev    next >
C/C++ Source or Header  |  1992-08-11  |  9KB  |  262 lines

  1. /*----------------------------------------*\
  2. >  parse.c : (c) 1992 Jean-Pierre RIVIERE  <
  3. \*----------------------------------------*/
  4.  
  5. #include <stdlib.h>
  6. #ifdef AMIGA
  7. #  include <exec/types.h>
  8. #  include <exec/memory.h>
  9. #else
  10. #  define  FreeMem(ptr,size)       free(ptr)
  11. #  define  AllocMem(size,type)     malloc(size)
  12. #  ifndef NULL
  13. #     define NULL 0L
  14. #  endif
  15. #endif
  16.  
  17. #include "parse.h"
  18.  
  19. #ifdef NO_PARSE_ERR_MESS
  20. #  define report_error(erreur)
  21. #else /* NO_PARSE_ERR_MESS */
  22.    char * ParseErrMess;
  23. #  define report_error(erreur)  ParseErrMess = ParseErrorMessage[(erreur) - 1]
  24. #define         ERR_MESS_WITH_LETTER
  25. #  ifndef ERR_MESS_WITHOUT_LETTER
  26. #     define ERR_LETTER " %c"
  27. #  else /* ERR_MESS_WITHOUT_LETTER */
  28. #     define ERR_LETTER
  29. #  endif /* ERR_MESS_WITHOUT_LETTER */
  30. #  ifndef ENGLISH
  31.    static const char * ParseErrorMessage [] = {
  32.       "Manque de mémoire",
  33.       "Appel de fonction erroné",
  34.       "option" ERR_LETTER " inconnue",
  35.       "option oubliée après le tiret",
  36.       "option" ERR_LETTER " répétée",
  37.       "argument de l'option" ERR_LETTER " absent",
  38.       "argument collé à l'option" ERR_LETTER,
  39.       "option" ERR_LETTER " à argument devant être isolée"
  40.    };
  41. #  else /* ENGLISH  */
  42.    static char * ParseErrorMessage [] = {
  43.       "lack of memory",
  44.       "wrong function call",
  45.       "unknown option" ERR_LETTER,
  46.       "forgotten option after the dash",
  47.       "repeated option" ERR_LETTER,
  48.       "lacking an argument after option" ERR_LETTER,
  49.       "argument stuck to option" ERR_LETTER,
  50.       "option" ERR_LETTER " with argument is not lonesome"
  51.    };
  52. #  endif   /* ENGLISH  */
  53. #  undef ERR_LETTER
  54. #endif   /* NO_PARSE_ERR_MESS */
  55.  
  56. /* données statiques pour la gestion des appels
  57.    statistical data for managing the calls      */
  58. static char * Options;     /* ensemble des options    ## set of options       */
  59. static char ** Arguments;  /* ensemble des arguments  ## set of arguments     */
  60. static short Taille;       /* taille du descriptif    ## size of description  */
  61.  
  62. static char parse_option (char *, struct rapport *, short *);
  63.  
  64. /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
  65.  
  66. static char * strseek (char * s, char r)
  67.   /** entrée                              *** input
  68.       s  : chaîne à parcourir              : string to parse
  69.       r  : caractère à trouver             : character to look for
  70.   *** valeur                              *** value
  71.       pointeur sur le premier caractère r    pointer on the first r character
  72.       de la chaîne ou sur sa fin             or on the end of the string
  73.   **/
  74.  
  75. /*** recherche un caractère dans une chaîne décrivant les options
  76.      looks for a character in an options-describing string        ***/
  77.  
  78. {
  79.    while (*s != r && *s)
  80.       s += 2;  /* le format de la chaîne impose cet incrément de deux
  81.                   the string format needs that increment of two         */
  82.    return s;
  83. }
  84.  
  85. /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
  86.  
  87. char parse_cleanup (void)
  88.    /** sortie                             *** output
  89.       1 ssi quelque chose a été nettoyé      1 if something was cleansed
  90.       0 sinon (appel en faute)               0 else (wrong call)
  91.    **/
  92. {
  93.    if (!Taille)
  94.       return 0;
  95.    if (Arguments)
  96.       FreeMem(Arguments, (--Taille) << 1);
  97.    if (Options)
  98.       FreeMem(Options, Taille >> 1);
  99.    /* un deuxieme appel a parse_cleanup doit etre tolérable
  100.       a second call to parse_cleanup has to be tolerated    */
  101.    Taille = 0;
  102.    return 1;
  103. }
  104.  
  105. /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
  106.  
  107. /* macro pour alléger la suite du programme
  108.    macro to light up the program             */
  109. #define probleme(rap,opt,val,err)  { \
  110.         (rap)->erreur = (val); report_error((rap)->erreur);  \
  111.         (rap)->lettre = (opt); parse_cleanup(); return (err); }
  112.  
  113. char parse (char * descrip, int argc, char ** argv,
  114.       struct rapport * rapport)
  115.    /** entrée                             *** input
  116.       descrip  : descripteur des options   : description of the options
  117.       argc     : nombre de paramètres      : number of parameters
  118.       argv     : vecteurs des paramètres   : parameters vector
  119.    *** sortie                             *** output
  120.       rapport  : indicateur d'activité     : indicates what's happened
  121.    *** valeur                             *** value
  122.       nul ssi il y a eu erreur             : zero only in case of error
  123.    **/
  124.  
  125. /*** parcours la ligne à la recherche des options selon le format indiqué
  126.      parse the command line for options according to the indicated format ***/
  127.  
  128. {
  129.    char *   opt;     /* chaîne des options      ## options string       */
  130.    short    nopt;    /* nombre d'options        ## number of options    */
  131.  
  132.    /* vérification de l'appel
  133.       check the call          */
  134.    if (Taille) {
  135.       rapport->erreur = OPT_WRONG_CALL;
  136.       rapport->lettre = '\0';
  137.       return 0;
  138.    }
  139.    /* préparation du parcours
  140.       parsing preparation     */
  141.    rapport->parg = argv + 1;
  142.    rapport->narg =  argc - 1;
  143.    opt = descrip;
  144.    Taille = 1 + (nopt = strlen(opt) >> 1);
  145. #  ifdef AMIGA
  146.    if (!(Options = rapport->options =
  147.                (char *) AllocMem(nopt, MEMF_PUBLIC | MEMF_CLEAR))
  148.          || !(Arguments = rapport->arguments =
  149.                (char **) AllocMem(nopt << 2, MEMF_PUBLIC | MEMF_CLEAR)))
  150. #  else  /* AMIGA */
  151.    if (!(Options = rapport->options = (char *) calloc(nopt, 1))
  152.          || !(Arguments = rapport->arguments = (char **) calloc(nopt << 2, 1)))
  153. #  endif /* AMIGA */
  154.    {
  155.       /* liberer la memoire et annuler Taille
  156.          free the memory and zero Taille      */
  157.       parse_cleanup();
  158.       probleme(rapport, 0, OPT_LACK_OF_MEMORY, -1);
  159.    }
  160.    nopt = 0;
  161.    rapport->erreur = 0;
  162.    /* vérification qu'il y a des options ou des arguments
  163.       check that there are options or arguments             */
  164.    if (rapport->narg == 0)
  165.       return nopt;
  166.    /* parcours
  167.       parsing */
  168.    do {
  169.       if (**rapport->parg == '-') { /* option décelée ## option detected  */
  170.          char res;
  171.          res = parse_option(descrip, rapport, &nopt);
  172.          switch (res) {
  173.          default :
  174.             continue;
  175.          case 1 :
  176.             break;
  177.          case 2 :
  178.             nopt = -1;
  179.             break;
  180.          }
  181.          break;
  182.       } else
  183.          /* fin des options détectée
  184.             end of options detected   */
  185.          break;
  186.    }while (rapport->narg);
  187.    return nopt;
  188. }
  189.  
  190. /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
  191.  
  192. static char parse_option (char * descrip, struct rapport * rapport, short * nopt)
  193.    /** entrée                                *** input
  194.       descrip  : descripteur des options      : description of the options
  195.    *** sortie                                *** output
  196.       rapport  : indicateur d'activité        : indicates what's happened
  197.       nopt     : nombre d'options validées    : number of validated options
  198.    *** valeur                                *** value
  199.       0 : pas de problème rencontré           : no problem encountered
  200.       1 : pas de problème et traitement fini  : no problem but parse is over
  201.       2 : il y a eu un problème               : there was a problem
  202.    **/
  203. {
  204.    int      narg;    /* nombre de paramètres    ## number of parameters */
  205.  
  206.    char *   ana;  /* analyse           ## analyse           */
  207.    char *   grop; /* groupe d'options  ## group of options  */
  208.    char num;   /* numéro   ## number   */
  209.    char op;    /* option *** option    */
  210.  
  211.    grop = (*(rapport->parg)++) + 1;
  212.    switch (op = *grop++) {
  213.    case '\0' : /* - : entrée standard, premier argument  */
  214.       if (rapport->narg && **rapport->parg == '-')
  215.          probleme(rapport, op, OPT_MISSING_OPTION, 2);
  216.       /* c'était bien le cas et c'est la fin des options
  217.          that was the case and that's the end of options */
  218.       --rapport->parg;
  219.       return 1;
  220.    case '-' :  /* -- : fin des options ## end of options */
  221.       if (*grop)
  222.          probleme(rapport, op, OPT_UNKNOWN_OPTION, 2);  /* --?   */
  223.       --rapport->narg;
  224.       return 1;
  225.    default :   /* -? : une option   */
  226.       /* on a une option, existe-elle pour autant ?
  227.          we have an option but does it exist ?        */
  228.       if (*(ana = strseek(descrip, op)) == '\0')
  229.          probleme(rapport, op, OPT_UNKNOWN_OPTION, 2);
  230.       num = (ana - descrip) >> 1;
  231.       if (rapport->options[num])
  232.          probleme(rapport, op, OPT_REPETITION, 2);
  233.       rapport->options[num] = 1;
  234.       if (ana[1] == ';') {
  235.          /* option à argument
  236.             option needing an argument */
  237.          if (*grop)
  238.             probleme(rapport, op, OPT_STUCK_ARGUMENT, 2);
  239.          if ((rapport->narg -= 2) < 0)
  240.             probleme(rapport, op, OPT_ABSENT_ARGUMENT, 2);
  241.          rapport->arguments[num] = *(rapport->parg)++;
  242.          ++*nopt;
  243.       } else {
  244.          /* recherche d'autres options sans arguments
  245.             looking for other options without arguments */
  246.          while (*grop)
  247.             if (*(ana = strseek(descrip, op = *grop++))) {
  248.                if (ana[1] == ';')
  249.                   probleme(rapport, op, OPT_STUCK_OPTION, 2);
  250.                num = (ana - descrip) >> 1;
  251.                if (rapport->options[num])
  252.                   probleme(rapport, op, OPT_REPETITION, 2);
  253.                rapport->options[num] = 1;
  254.                ++*nopt;
  255.             } else
  256.                probleme(rapport, op, OPT_UNKNOWN_OPTION, 2);
  257.          --rapport->narg;
  258.       }
  259.       return 0;
  260.    }
  261. }
  262.