Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* cmdarg.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS-Portierung                                                             */
  6. /*                                                                           */
  7. /* Verarbeitung Kommandozeilenparameter                                      */
  8. /*                                                                           */
  9. /* Historie:  4. 5.1996 Grundsteinlegung                                     */
  10. /*            1. 6.1996 Empty-Funktion                                       */
  11. /*           17. 4.1999 Key-Files in Kommandozeile                           */
  12. /*            3. 8.2000 added command line args as slashes                   */
  13. /*                                                                           */
  14. /*****************************************************************************/
  15.  
  16. #include "stdinc.h"
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #include "strutil.h"
  21. #include "stringlists.h"
  22. #include "nls.h"
  23. #include "nlmessages.h"
  24. #include "cmdarg.rsc"
  25. #ifdef _USE_MSH
  26. # include "cmdarg.msh"
  27. #endif
  28. #include "cmdarg.h"
  29.  
  30. /* --------------------------------------------------------------- */
  31.  
  32. TMsgCat MsgCat;
  33.  
  34. static as_cmd_rec_t *sum_cmd_recs = NULL;
  35. static size_t sum_cmd_rec_cnt = 0;
  36.  
  37. /* --------------------------------------------------------------- */
  38.  
  39. static as_cmd_result_t ProcessFile(const char *Name_O,
  40.                                    const as_cmd_rec_t *p_cmd_recs, size_t cmd_rec_cnt,
  41.                                    as_cmd_results_t *p_results);
  42.  
  43. static as_cmd_result_t cmd_write_help(Boolean negate, const char *p_arg, as_cmd_results_t *p_results)
  44. {
  45.   UNUSED(p_arg);
  46.  
  47.   if (negate)
  48.     return e_cmd_err;
  49.  
  50.   p_results->write_help_exit = True;
  51.   return e_cmd_ok;
  52. }
  53.  
  54. static as_cmd_result_t cmd_write_version(Boolean negate, const char *p_arg, as_cmd_results_t *p_results)
  55. {
  56.   UNUSED(p_arg);
  57.  
  58.   if (negate)
  59.     return e_cmd_err;
  60.  
  61.   p_results->write_version_exit = True;
  62.   return e_cmd_ok;
  63. }
  64.  
  65. static Boolean is_arg_leadin(char p)
  66. {
  67.   return (p == '-')
  68. #ifdef SLASHARGS
  69.       || (p == '/')
  70. #endif
  71.       || (p == '+');
  72. }
  73.  
  74. static as_cmd_result_t ProcessParam(const as_cmd_rec_t *p_cmd_recs, size_t cmd_rec_cnt, const char *p_param,
  75.                                     const char *p_next, Boolean AllowLink,
  76.                                     as_cmd_results_t *p_results)
  77. {
  78.   Boolean Negate;
  79.   as_cmd_result_t TempRes;
  80.   const char *p_act_next;
  81.  
  82.   if (as_strcasecmp(p_param, "-intsyntax"))
  83.     p_act_next = (is_arg_leadin(*p_next) || (*p_next == '@')) ? "" : p_next;
  84.   else
  85.     p_act_next = p_next;
  86.   if (*p_param == '@')
  87.   {
  88.     if (AllowLink)
  89.     {
  90.       return ProcessFile(p_param + 1, p_cmd_recs, cmd_rec_cnt, p_results);
  91.     }
  92.     else
  93.     {
  94.       fprintf(stderr, "%s\n", catgetmessage(&MsgCat, Num_ErrMsgNoKeyInFile));
  95.       strmaxcpy(p_results->error_arg, p_param, sizeof(p_results->error_arg));
  96.       return e_cmd_err;
  97.     }
  98.   }
  99.   if (is_arg_leadin(*p_param))
  100.   {
  101.     size_t Search;
  102.     int cnv_up_lo = 0;
  103.  
  104.     Negate = (*p_param == '+');
  105.     p_param++;
  106.     if (*p_param == '#')
  107.     {
  108.       cnv_up_lo = 1;
  109.       p_param++;
  110.     }
  111.     else if (*p_param == '~')
  112.     {
  113.       cnv_up_lo = -1;
  114.       p_param++;
  115.     }
  116.  
  117.     for (Search = 0; Search < cmd_rec_cnt; Search++)
  118.       if ((strlen(p_cmd_recs[Search].p_ident) > 1) && (!as_strcasecmp(p_param, p_cmd_recs[Search].p_ident)))
  119.         break;
  120.     if (Search < cmd_rec_cnt)
  121.       TempRes = p_cmd_recs[Search].callback(Negate, p_act_next);
  122.     else if (!as_strcasecmp(p_param, "help"))
  123.       TempRes = cmd_write_help(Negate, p_act_next, p_results);
  124.     else if (!as_strcasecmp(p_param, "version"))
  125.       TempRes = cmd_write_version(Negate, p_act_next, p_results);
  126.  
  127.     else
  128.     {
  129.       TempRes = e_cmd_ok;
  130.       for (; *p_param; p_param++)
  131.       {
  132.         char p = *p_param;
  133.  
  134.         if (cnv_up_lo)
  135.           p = (cnv_up_lo > 0) ? as_toupper(p) : as_tolower(p);
  136.         Search = 0;
  137.         for (Search = 0; Search < cmd_rec_cnt; Search++)
  138.           if ((strlen(p_cmd_recs[Search].p_ident) == 1) && (p_cmd_recs[Search].p_ident[0] == p))
  139.             break;
  140.         if (Search >= cmd_rec_cnt)
  141.           TempRes = e_cmd_err;
  142.         else
  143.           switch (p_cmd_recs[Search].callback(Negate, p_act_next))
  144.           {
  145.             case e_cmd_err:
  146.               TempRes = e_cmd_err;
  147.               break;
  148.             case e_cmd_arg:
  149.               TempRes = e_cmd_arg;
  150.               p_act_next = "";
  151.               break;
  152.             case e_cmd_ok:
  153.               break;
  154.             case e_cmd_file:
  155.               break; /** **/
  156.           }
  157.         if (TempRes == e_cmd_err)
  158.           break;
  159.       }
  160.     }
  161.     if (TempRes == e_cmd_err)
  162.       strmaxcpy(p_results->error_arg, p_param, sizeof(p_results->error_arg));
  163.     return TempRes;
  164.   }
  165.   else
  166.     return e_cmd_file;
  167. }
  168.  
  169. static as_cmd_result_t DecodeLine(const as_cmd_rec_t *p_cmd_recs, int cmd_rec_cnt, char *OneLine,
  170.                                   as_cmd_results_t *p_results)
  171. {
  172.   int z;
  173.   char *EnvStr[256], *start, *p;
  174.   int EnvCnt = 0;
  175.  
  176.   KillPrefBlanks(OneLine);
  177.   if ((*OneLine != '\0') && (*OneLine != ';'))
  178.   {
  179.     start = OneLine;
  180.     while (*start != '\0')
  181.     {
  182.       EnvStr[EnvCnt++] = start;
  183.       p = strchr(start, ' ');
  184.       if (!p)
  185.         p = strchr(start, '\t');
  186.       if (p)
  187.       {
  188.         *p = '\0';
  189.         start = p + 1;
  190.         while (as_isspace(*start))
  191.            start++;
  192.       }
  193.       else
  194.         start += strlen(start);
  195.     }
  196.     EnvStr[EnvCnt] = start;
  197.  
  198.     for (z = 0; z < EnvCnt; z++)
  199.     {
  200.       switch (ProcessParam(p_cmd_recs, cmd_rec_cnt, EnvStr[z], EnvStr[z + 1], False, p_results))
  201.       {
  202.         case e_cmd_file:
  203.           AddStringListLast(&p_results->file_arg_list, EnvStr[z]);
  204.           break;
  205.         case e_cmd_err:
  206.           strmaxcpy(p_results->error_arg, EnvStr[z], sizeof(p_results->error_arg));
  207.           p_results->error_arg_in_env = True;
  208.           return e_cmd_err;
  209.         case e_cmd_arg:
  210.           z++;
  211.           break;
  212.         case e_cmd_ok:
  213.           break;
  214.       }
  215.     }
  216.   }
  217.   return e_cmd_ok;
  218. }
  219.  
  220. /*!------------------------------------------------------------------------
  221.  * \fn     ProcessFile(const char *Name_O,
  222.                        const as_cmd_rec_t *p_cmd_recs, size_t cmd_rec_cnt,
  223.                        as_cmd_results_t *p_results)
  224.  * \brief  process arguments from file
  225.  * \param  Name_O file's name
  226.  * \param  p_cmd_recs, cmd_rec_cnt argument defintions
  227.  * \param  p_results result buffer
  228.  * \return e_cmd_ok or e_cmd_err
  229.  * ------------------------------------------------------------------------ */
  230.  
  231. static as_cmd_result_t ProcessFile(const char *Name_O,
  232.                                    const as_cmd_rec_t *p_cmd_recs, size_t cmd_rec_cnt,
  233.                                    as_cmd_results_t *p_results)
  234. {
  235.   FILE *KeyFile;
  236.   String Name, OneLine;
  237.   as_cmd_result_t ret = e_cmd_ok;
  238.  
  239.   strmaxcpy(Name, Name_O, STRINGSIZE);
  240.   KillPrefBlanks(OneLine);
  241.  
  242.   KeyFile = fopen(Name, "r");
  243.   if (!KeyFile)
  244.   {
  245.     strmaxcpy(p_results->error_arg, catgetmessage(&MsgCat, Num_ErrMsgKeyFileNotFound), sizeof(p_results->error_arg));
  246.     ret = e_cmd_err;
  247.   }
  248.   while (!feof(KeyFile) && (ret == e_cmd_ok))
  249.   {
  250.     errno = 0;
  251.     ReadLn(KeyFile, OneLine);
  252.     if ((errno != 0) && !feof(KeyFile))
  253.     {
  254.       strmaxcpy(p_results->error_arg, catgetmessage(&MsgCat, Num_ErrMsgKeyFileError), sizeof(p_results->error_arg));
  255.       ret = e_cmd_err;
  256.     }
  257.     ret = DecodeLine(p_cmd_recs, cmd_rec_cnt, OneLine, p_results);
  258.   }
  259.   fclose(KeyFile);
  260.   return ret;
  261. }
  262.  
  263. static int cmd_compare(const void *p1, const void *p2)
  264. {
  265.   const as_cmd_rec_t *p_rec1 = (const as_cmd_rec_t*)p1,
  266.                      *p_rec2 = (const as_cmd_rec_t*)p2;
  267.   int cmp_res = strcmp(p_rec1->p_ident, p_rec2->p_ident);
  268.  
  269.   if (!cmp_res && (p_rec1 != p_rec2))
  270.     fprintf(stderr, "cmd_arg: option '%s' present twice\n", p_rec1->p_ident);
  271.   return cmp_res;
  272. }
  273.  
  274. /*!------------------------------------------------------------------------
  275.  * \fn     as_cmd_register(const as_cmd_rec_t *p_add_recs, size_t add_rec_cnt)
  276.  * \brief  extend command record list
  277.  * \param  p_add_recs, add_rec_cnt records to add
  278.  * ------------------------------------------------------------------------ */
  279.  
  280. void as_cmd_register(const as_cmd_rec_t *p_add_recs, size_t add_rec_cnt)
  281. {
  282.   as_cmd_rec_t *p_new_sum_recs;
  283.  
  284.   if (sum_cmd_recs)
  285.     p_new_sum_recs = (as_cmd_rec_t*)realloc(sum_cmd_recs, sizeof(*p_new_sum_recs) * (sum_cmd_rec_cnt + add_rec_cnt));
  286.   else
  287.     p_new_sum_recs = (as_cmd_rec_t*)malloc(sizeof(*p_new_sum_recs) * (sum_cmd_rec_cnt + add_rec_cnt));
  288.   if (p_new_sum_recs)
  289.   {
  290.     memcpy(&p_new_sum_recs[sum_cmd_rec_cnt], p_add_recs, sizeof(*p_new_sum_recs) * add_rec_cnt);
  291.     sum_cmd_rec_cnt += add_rec_cnt;
  292.     sum_cmd_recs = p_new_sum_recs;
  293.     qsort(p_new_sum_recs, sum_cmd_rec_cnt, sizeof(*p_new_sum_recs), cmd_compare);
  294.   }
  295. }
  296.  
  297. /*!------------------------------------------------------------------------
  298.  * \fn     as_cmd_process(int argc, char **argv,
  299.                           const char *p_env_name, as_cmd_results_t *p_results)
  300.  * \brief  arguments from command line and environment
  301.  * \param  argc command line arg count as handed to main()
  302.  * \param  argv command line args as handed to main()
  303.  * \param  p_env_name environment variable to draw additional args from
  304.  * \param  p_file_arg_list gets populated with file arguments
  305.  * \return e_cmd_ok, or e_cmd_err on faulty arg
  306.  * ------------------------------------------------------------------------ */
  307.  
  308. const char *argv0;
  309.  
  310. as_cmd_result_t as_cmd_process(int argc, char **argv,
  311.                                const char *p_env_name, as_cmd_results_t *p_results)
  312. {
  313.   int z;
  314.   String EnvLine;
  315.   char *pEnv;
  316.   Boolean skip_next;
  317.  
  318.   p_results->file_arg_list = NULL;
  319.   p_results->write_help_exit =
  320.   p_results->write_version_exit = False;
  321.   p_results->error_arg_in_env = False;
  322.   p_results->error_arg[0] = '\0';
  323.  
  324.   pEnv = getenv(p_env_name);
  325.   strmaxcpy(EnvLine, pEnv ? pEnv : "", STRINGSIZE);
  326.  
  327.   if (EnvLine[0] == '@')
  328.   {
  329.     if (e_cmd_err == ProcessFile(EnvLine + 1, sum_cmd_recs, sum_cmd_rec_cnt, p_results))
  330.       return e_cmd_err;
  331.   }
  332.   else
  333.   {
  334.     if (e_cmd_err == DecodeLine(sum_cmd_recs, sum_cmd_rec_cnt, EnvLine, p_results))
  335.       return e_cmd_err;
  336.   }
  337.  
  338.   argv0 = argv[0];
  339.  
  340.   skip_next = False;
  341.   for (z = 1; z < argc; z++)
  342.   {
  343.     if (skip_next)
  344.     {
  345.       skip_next = False;
  346.       continue;
  347.     }
  348.     switch (ProcessParam(sum_cmd_recs, sum_cmd_rec_cnt, argv[z], (z + 1 < argc) ? argv[z + 1] : "",
  349.                          True, p_results))
  350.     {
  351.       case e_cmd_err:
  352.         p_results->error_arg_in_env = False;
  353.         strmaxcpy(p_results->error_arg, argv[z], sizeof(p_results->error_arg));
  354.         return e_cmd_err;
  355.       case e_cmd_ok:
  356.         break;
  357.       case e_cmd_arg:
  358.         skip_next = True;
  359.         break;
  360.       case e_cmd_file:
  361.         AddStringListLast(&p_results->file_arg_list, argv[z]);
  362.         break;
  363.     }
  364.   }
  365.   return e_cmd_ok;
  366. }
  367.  
  368. const char *as_cmdarg_get_executable_name(void)
  369. {
  370.   const char *pos;
  371.  
  372.   pos = strrchr(argv0, '/');
  373.   return (pos) ? pos + 1 : argv0;
  374. }
  375.  
  376. void as_cmdarg_init(char *ProgPath)
  377. {
  378. #ifdef _USE_MSH
  379.   msg_catalog_open_buffer(&MsgCat, cmdarg_msh_data, sizeof(cmdarg_msh_data), MsgId1, MsgId2);
  380.   UNUSED(ProgPath);
  381. #else
  382.   msg_catalog_open_file(&MsgCat, "cmdarg.msg", ProgPath, MsgId1, MsgId2);
  383. #endif
  384. }
  385.  
  386.