Subversion Repositories pentevo

Rev

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

  1. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9.  
  10. #include "strutil.h"
  11. #include "stringlists.h"
  12.  
  13. #define ObjExtension ".o"
  14.  
  15. static StringRecPtr inc_path_list = NULL,
  16.                     def_list = NULL;
  17.  
  18. static char *getobj(const char *pSrc)
  19. {
  20.   static char buffer[255];
  21.   int l = strlen(pSrc), bm5 = sizeof(buffer) - 5;
  22.   char *pSearch;
  23.  
  24.   if (l < bm5)
  25.     l = bm5;
  26.   memcpy(buffer, pSrc, l); buffer[l] = '\0';
  27.  
  28.   pSearch = strrchr(buffer, '.');
  29.   if (pSearch)
  30.     strcpy(pSearch, ObjExtension);
  31.  
  32.   return buffer;
  33. }
  34.  
  35. int MayRecurse(const char *pFileName)
  36. {
  37.   int l = strlen(pFileName);
  38.  
  39.   /* .rsc files are autogenerated and do not contain any
  40.      include statements - no need to scan them */
  41.  
  42.   if ((l > 4) && (!strcmp(pFileName + l - 4, ".rsc")))
  43.     return 0;
  44.  
  45.   return 1;
  46. }
  47.  
  48. static Boolean regard_sym(const char *p_name)
  49. {
  50.   return !strcmp(p_name, "_USE_MSH");
  51. }
  52.  
  53. static Boolean def_present(const char *p_name)
  54. {
  55.   StringRec *p_run = def_list;
  56.  
  57.   for (p_run = def_list; p_run; p_run = p_run->Next)
  58.   {
  59.     if (!strcmp(p_name, p_run->Content))
  60.       return True;
  61.   }
  62.   return False;
  63. }
  64.  
  65. static Boolean curr_if = True;
  66.  
  67. typedef struct if_stack
  68. {
  69.   struct if_stack *p_next;
  70.   Boolean condition, save_curr_if;
  71.   Boolean evaluated, else_occured;
  72. } if_stack_t;
  73. static if_stack_t *p_if_stack_tos = NULL;
  74.  
  75. static void push_if(Boolean condition, Boolean evaluated)
  76. {
  77.   if_stack_t *p_new_if = (if_stack_t*)calloc(1, sizeof(*p_new_if));
  78.  
  79.   p_new_if->save_curr_if = curr_if;
  80.   p_new_if->condition = condition;
  81.   p_new_if->evaluated = evaluated;
  82.   p_new_if->else_occured = False;
  83.   p_new_if->p_next = p_if_stack_tos;
  84.   p_if_stack_tos = p_new_if;
  85.   curr_if = evaluated ? curr_if && condition : curr_if;
  86. }
  87.  
  88. static void toggle_if(const char *p_file, int line)
  89. {
  90.   if (!p_if_stack_tos)
  91.   {
  92.     fprintf(stderr, "%s:%d: #else without #ifdef\n", p_file, line);
  93.     exit(1);
  94.   }
  95.   else if (p_if_stack_tos->else_occured)
  96.   {
  97.     fprintf(stderr, "%s:%d: #ifdef with more than one #else\n", p_file, line);
  98.     exit(1);
  99.   }
  100.   if (p_if_stack_tos->evaluated)
  101.     curr_if = p_if_stack_tos->save_curr_if && !p_if_stack_tos->condition;
  102.   p_if_stack_tos->else_occured = True;
  103. }
  104.  
  105. static void pop_if(const char *p_file, int line)
  106. {
  107.   if_stack_t *p_old_if;
  108.  
  109.   if (!p_if_stack_tos)
  110.   {
  111.     fprintf(stderr, "%s:%d: #endif without #ifdef\n", p_file, line);
  112.     exit(1);
  113.   }
  114.   curr_if = p_if_stack_tos->save_curr_if;
  115.   p_old_if = p_if_stack_tos;
  116.   p_if_stack_tos = p_old_if->p_next;
  117.   free(p_old_if);
  118. }
  119.  
  120. static void ParseFile(const char *pFileName, const char *pParentFileName, StringRecPtr *pFileList)
  121. {
  122.   FILE *pFile;
  123.   int l, file_stat, line_num = 0;
  124.   char line[512], *pCmd, *pName, *pValue;
  125.   String raw_name, eff_name;
  126.   struct stat stat_buf;
  127.  
  128.   pFile = fopen(pFileName, "r");
  129.   if (!pFile)
  130.   {
  131.     if (pParentFileName)
  132.       fprintf(stderr, "%s: ", pParentFileName);
  133.     perror(pFileName);
  134.     return;
  135.   }
  136.  
  137.   while (!feof(pFile))
  138.   {
  139.     if (!fgets(line, sizeof(line), pFile))
  140.       break;
  141.     line_num++;
  142.     l = strlen(line);
  143.     if ((l > 0) && (line[l - 1] == '\n'))
  144.       line[l - 1] = '\0';
  145.  
  146.     if (*line != '#')
  147.       continue;
  148.     pCmd = strtok(line + 1, " \t");
  149.  
  150.     if (!strcmp(pCmd, "include") && curr_if)
  151.     {
  152.       pName = strtok(NULL, " \t");
  153.       if (!pName)
  154.         continue;
  155.       l = strlen(pName);
  156.       if ((*pName != '"') || (pName[l - 1] != '"'))
  157.         continue;
  158.  
  159.       if (l - 1 < (int)sizeof(raw_name))
  160.       {
  161.         memcpy(raw_name, pName + 1, l - 2);
  162.         raw_name[l - 2] = '\0';
  163.         strmaxcpy(eff_name, raw_name, sizeof(eff_name));
  164.         file_stat = stat(eff_name, &stat_buf);
  165.         if (file_stat)
  166.         {
  167.           StringRecPtr p_run;
  168.           const char *p_path;
  169.  
  170.           for (p_path = GetStringListFirst(inc_path_list, &p_run);
  171.                p_path; p_path = GetStringListNext(&p_run))
  172.           {
  173.             size_t l = strlen(p_path);
  174.             Boolean term_path = (l > 0) && ((p_path[l -1] == '/') || (p_path[l -1] == '\\'));
  175.             as_snprintf(eff_name, sizeof(eff_name), "%s%s%s", p_path, term_path ? "" : "/", raw_name);
  176.             file_stat = stat(eff_name, &stat_buf);
  177.             if (!file_stat)
  178.               break;
  179.           }
  180.         }
  181.         /* If file is not present, it is created dynamically and expected to appear in the
  182.            object subdirectory, which is passed in as -I path.  Keep last generated eff_name
  183.            for the dependency list: */
  184.         if (!StringListPresent(*pFileList, eff_name))
  185.         {
  186.           AddStringListLast(pFileList, eff_name);
  187.           if (MayRecurse(eff_name))
  188.             ParseFile(eff_name, pFileName, pFileList);
  189.         }
  190.       }
  191.     }
  192.     else if (!strcmp(pCmd, "if"))
  193.     {
  194.       push_if(True, False);
  195.     }
  196.     else if (!strcmp(pCmd, "ifdef"))
  197.     {
  198.       pName = strtok(NULL, " \t");
  199.       if (!curr_if || !regard_sym(pName))
  200.         push_if(True, False);
  201.       else
  202.         push_if(def_present(pName), True);
  203.     }
  204.     else if (!strcmp(pCmd, "ifndef"))
  205.     {
  206.       pName = strtok(NULL, " \t");
  207.       if (!curr_if || !regard_sym(pName))
  208.         push_if(True, False);
  209.       else
  210.         push_if(!def_present(pName), True);
  211.     }
  212.     else if (!strcmp(pCmd, "else"))
  213.     {
  214.       if (curr_if)
  215.         toggle_if(pFileName, line_num);
  216.     }
  217.     else if (!strcmp(pCmd, "endif"))
  218.     {
  219.       pop_if(pFileName, line_num);
  220.     }
  221.     else if (!strcmp(pCmd, "elif"))
  222.     {
  223.       /* TODO */
  224.     }
  225.     else if (!strcmp(pCmd, "define"))
  226.     {
  227.       pName = strtok(NULL, " \t");
  228.       pValue = strtok(NULL, " \t");
  229.  
  230.       if (strchr(pName, '(') || (pValue && *pValue))
  231.         continue;
  232.     }
  233.     else if (!strcmp(pCmd, "undef"))
  234.     {
  235.       pName = strtok(NULL, " \t");
  236.     }
  237.   }
  238.   fclose(pFile);
  239. }
  240.  
  241. int main(int argc, char **argv)
  242. {
  243.   int z, ArgsAreObj = 0;
  244.   FILE *pDepFile;
  245.   const char *pDepFileName = NULL,
  246.              *pOutFileName = NULL,
  247.              *pObjExtension = NULL;
  248.   char used[1024];
  249.   StringRecPtr FileList, SrcList;
  250.  
  251.   if (argc < 2)
  252.   {
  253.     fprintf(stderr, "usage: %s [args] <file(s)>\n", *argv);
  254.     exit(1);
  255.   }
  256.  
  257.   memset(used, 0, sizeof(used));
  258.  
  259.   for (z = 1; z < argc; z++)
  260.     if ((!used[z]) && (*argv[z] == '-'))
  261.     {
  262.       used[z] = 1;
  263.       if (!strcmp(argv[z] + 1, "d"))
  264.       {
  265.         if (z >= argc - 1)
  266.           pDepFileName = NULL;
  267.         else
  268.         {
  269.           pDepFileName = argv[z + 1];
  270.           used[z + 1] = 1;
  271.         }
  272.       }
  273.       else if (!strcmp(argv[z] + 1, "o"))
  274.       {
  275.         if (z >= argc - 1)
  276.           pOutFileName = NULL;
  277.         else
  278.         {
  279.           pOutFileName = argv[z + 1];
  280.           used[z + 1] = 1;
  281.         }
  282.       }
  283.       else if (!strcmp(argv[z] + 1, "c"))
  284.       {
  285.         if (z >= argc - 1)
  286.           pObjExtension = NULL;
  287.         else
  288.         {
  289.           pObjExtension = argv[z + 1];
  290.           used[z + 1] = 1;
  291.         }
  292.       }
  293.       else if (!strcmp(argv[z] + 1, "r"))
  294.       {
  295.         ArgsAreObj = 1;
  296.       }
  297.       else if (argv[z][1] == 'I')
  298.       {
  299.         if (!argv[z][2])
  300.         {
  301.           if (z < argc - 1)
  302.           {
  303.             if (argv[z + 1][0] == '-')
  304.               fprintf(stderr, "%s: taking '%s' as include path, is this correct?\n", argv[0], argv[z + 1]);
  305.             AddStringListLast(&inc_path_list, argv[z + 1]);
  306.             used[z + 1] = 1;
  307.           }
  308.         }
  309.         else
  310.           AddStringListLast(&inc_path_list, argv[z] + 2);
  311.       }
  312.       else if (argv[z][1] == 'D')
  313.       {
  314.         if (!argv[z][2])
  315.         {
  316.           if (z < argc - 1)
  317.           {
  318.             if (argv[z + 1][0] == '-')
  319.               fprintf(stderr, "%s: taking '%s' as macro, is this correct?\n", argv[0], argv[z + 1]);
  320.             AddStringListLast(&def_list, argv[z + 1]);
  321.             used[z + 1] = 1;
  322.           }
  323.         }
  324.         else
  325.           AddStringListLast(&def_list, argv[z] + 2);
  326.       }
  327.       else
  328.       {
  329.         fprintf(stderr, "unknown option: %s\n", argv[z]);
  330.         exit(2);
  331.       }
  332.     }
  333.  
  334.   if (pDepFileName)
  335.   {
  336.     pDepFile = fopen(pDepFileName, "w");
  337.     if (!pDepFile)
  338.     {
  339.       perror(pDepFileName);
  340.       exit(errno);
  341.     }
  342.   }
  343.   else
  344.     pDepFile = stdout;
  345.  
  346.   fprintf(pDepFile, "# auto-generated by %s - do not edit\n\n", *argv);
  347.  
  348.   InitStringList(&FileList);
  349.   InitStringList(&SrcList);
  350.   for (z = 1; z < argc; z++)
  351.   {
  352.     char SrcFileName[512];
  353.     const char *pSrcFileName;
  354.  
  355.     if (used[z])
  356.       continue;
  357.  
  358.     /* object files may be in paths different than root - strip path to deduce associated src file */
  359.  
  360.     if (ArgsAreObj)
  361.     {
  362.       char *pRun;
  363.  
  364.       for (pRun = argv[z] + strlen(argv[z]); pRun > argv[z]; pRun--)
  365.         if ((*(pRun - 1) == '/') || (*(pRun - 1) == '\\'))
  366.           break;
  367.       /* leading h_ in object file name is used for host-side files */
  368.       if (!strncmp(pRun, "h_", 2))
  369.         pRun += 2;
  370.       *SrcFileName = '\0'; strncat(SrcFileName, pRun, sizeof(SrcFileName) - 1);
  371.       if (pObjExtension)
  372.       {
  373.         int l1 = strlen(SrcFileName), l2 = strlen(pObjExtension);
  374.  
  375.         if ((l1 > l2) && !memcmp(SrcFileName + l1 - l2, pObjExtension, l2))
  376.           strcpy(SrcFileName + l1 - l2, ".c");
  377.       }
  378.       pSrcFileName = SrcFileName;
  379.     }
  380.     else
  381.       pSrcFileName = argv[z];
  382.     ClearStringList(&FileList);
  383.     AddStringListLast(&SrcList, pSrcFileName);
  384.     ParseFile(pSrcFileName, NULL, &FileList);
  385.  
  386.     if (!StringListEmpty(FileList))
  387.     {
  388.       fprintf(pDepFile, "%s: %s",
  389.               pOutFileName ? pOutFileName : (ArgsAreObj ? argv[z] : getobj(argv[z])),
  390.               pSrcFileName);
  391.       while (True)
  392.       {
  393.         char *pIncFileName = MoveAndCutStringListFirst(&FileList);
  394.         if (pIncFileName)
  395.         {
  396.           if (*pIncFileName)
  397.             fprintf(pDepFile, " %s", pIncFileName);
  398.           free(pIncFileName); pIncFileName = NULL;
  399.         }
  400.         else
  401.           break;
  402.       }
  403.       fprintf(pDepFile, "\n\n");
  404.     }
  405.   }
  406.  
  407.   if (pDepFileName)
  408.   {
  409.     if (!StringListEmpty(SrcList))
  410.     {
  411.       fprintf(pDepFile, "%s:", pDepFileName);
  412.       while (True)
  413.       {
  414.         char *pIncFileName = MoveAndCutStringListFirst(&SrcList);
  415.         if (pIncFileName)
  416.         {
  417.           if (*pIncFileName)
  418.             fprintf(pDepFile, " %s", pIncFileName);
  419.           free(pIncFileName); pIncFileName = NULL;
  420.         }
  421.         else
  422.           break;
  423.       }
  424.       fprintf(pDepFile, "\n");
  425.     }
  426.     fclose(pDepFile);
  427.   }
  428.  
  429.   ClearStringList(&inc_path_list);
  430.  
  431.   return 0;
  432. }
  433.