Subversion Repositories pentevo

Rev

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

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