?login_element?

Subversion Repositories NedoOS

Rev

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

  1. /* main.c - main program.
  2.  
  3.    aspp - simple assembler source file preprocessor.
  4.  
  5.    Author: Ivan Tatarinov, <ivan-tat@ya.ru>, 2019-2020.
  6.  
  7.    This is free and unencumbered software released into the public domain.
  8.    For more information, please refer to <http://unlicense.org>.
  9.  
  10.    Home page: <https://gitlab.com/ivan-tat/aspp> */
  11.  
  12. #include "defs.h"
  13.  
  14. #include <stdbool.h>
  15. #include <stdarg.h>
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <errno.h>
  20. #include <locale.h>
  21. #include <ctype.h>
  22. #include "asmfile.h"
  23. #include "debug.h"
  24. #include "l_err.h"
  25. #include "l_ifile.h"
  26. #include "l_inc.h"
  27. #include "l_isrc.h"
  28. #include "l_list.h"
  29. #include "l_pre.h"
  30. #include "l_src.h"
  31. #include "l_tgt.h"
  32. #include "parser.h"
  33. #include "platform.h"
  34.  
  35. #define PROGRAM_NAME "aspp"
  36.  
  37. #define PROGRAM_VERSION "0.1" PROGRAM_VERSION_SUFFIX
  38.  
  39. #define PROGRAM_DESCRIPTION "Simple assembler source file preprocessor."
  40.  
  41. #define PROGRAM_LICENSE \
  42. "License: public domain, <http://unlicense.org>" NL \
  43. "This is free software; you are free to change and redistribute it." NL \
  44. "There is NO WARRANTY, to the extent permitted by law."
  45.  
  46. #define PROGRAM_AUTHORS \
  47. "Author: Ivan Tatarinov, <ivan-tat@ya.ru>, 2019-2020."
  48.  
  49. #define PROGRAM_CONTACTS \
  50. "Home page: <https://gitlab.com/ivan-tat/aspp>"
  51.  
  52. #define HELP_HINT \
  53. "Use '-h' or '--help' to get help."
  54.  
  55. // Acts
  56.  
  57. #define ACT_NONE       0
  58. #define ACT_SHOW_HELP  1
  59. #define ACT_PREPROCESS 2
  60. #define ACT_MAKE_RULE  3
  61.  
  62. // Variables
  63.  
  64. struct errors_t
  65.           errors           = { { .first = NULL, .last = NULL, .count = 0 } };
  66. unsigned  v_syntax         = SYNTAX_TASM;
  67. unsigned  v_act            = ACT_NONE;
  68. char      v_act_show_help  = 0;
  69. char      v_act_preprocess = 0;
  70. char      v_act_make_rule  = 0;
  71. char     *v_base_path_real = NULL;
  72. struct include_paths_t
  73.           v_include_paths  = { { .first = NULL, .last = NULL, .count = 0 } };
  74. struct input_sources_t
  75.           v_input_sources  = { { .first = NULL, .last = NULL, .count = 0 } };
  76. struct sources_t
  77.           v_sources        = { { .first = NULL, .last = NULL, .count = 0 } };
  78. struct target_names_t
  79.           v_target_names   = { { .first = NULL, .last = NULL, .count = 0 } };
  80. char     *v_output_name;
  81. struct prerequisites_t
  82.           v_prerequisites  = { { .first = NULL, .last = NULL, .count = 0 } };
  83.  
  84. #if DEBUG == 1
  85. void _DBG_dump_vars (void)
  86. {
  87.     const char *s;
  88.     _DBG_ ("Input files syntax = '%s'", _syntax_to_str (v_syntax, &s) ? s : "unknown");
  89.     _DBG_include_paths_dump (&v_include_paths);
  90.     _DBG_input_sources_dump (&v_input_sources);
  91.     _DBG_target_names_dump (&v_target_names);
  92.     _DBG_ ("Output file name = '%s'", v_output_name);
  93.  
  94. }
  95. #else   // DEBUG != 1
  96. #define _DBG_dump_vars(x)
  97. #endif  // DEBUG != 1
  98.  
  99. // Returns "false" on success.
  100. bool add_error (const char *format, ...)
  101. {
  102.     va_list ap;
  103.     bool status;
  104.  
  105.     va_start (ap, format);
  106.     status = errors_add_vfmt (&errors, NULL, 1024, format, ap);
  107.     va_end (ap);
  108.     return status;
  109. }
  110.  
  111. // Returns "false" on success.
  112. bool add_missing_arg_error (const char *name, unsigned index)
  113. {
  114.     return add_error ("Missing parameter for %s (argument #%u).", name, index);
  115. }
  116.  
  117. void show_errors (void)
  118. {
  119.     const struct error_entry_t *p;
  120.  
  121.     for (p = (struct error_entry_t *) errors.list.first; p;
  122.          p = (struct error_entry_t *) p->list_entry.next)
  123.         fprintf (stderr, "%s" NL, p->msg);
  124. }
  125.  
  126. void exit_on_errors (void)
  127. {
  128.     if (errors.list.count)
  129.     {
  130.         fprintf (stderr, "Errors: %u. Stopped." NL, errors.list.count);
  131.         exit (EXIT_FAILURE);
  132.     }
  133. }
  134.  
  135. void error_exit (const char *format, ...)
  136. {
  137.     va_list ap;
  138.  
  139.     va_start (ap, format);
  140.     vfprintf (stderr, format, ap);
  141.     va_end (ap);
  142.     exit (EXIT_FAILURE);
  143. }
  144.  
  145. void show_title (void)
  146. {
  147.     fprintf (stdout,
  148.         "%s (version %s) - %s" NL
  149.         "%s" NL
  150.         "%s" NL
  151.         "%s" NL,
  152.         PROGRAM_NAME,
  153.         PROGRAM_VERSION,
  154.         PROGRAM_DESCRIPTION,
  155.         PROGRAM_LICENSE,
  156.         PROGRAM_AUTHORS,
  157.         PROGRAM_CONTACTS
  158.     );
  159. }
  160.  
  161. void show_help (void)
  162. {
  163.     fprintf (stdout,
  164. NL
  165. "Usage:" NL
  166. "    %s [options] [filename ...] [options]" NL
  167. NL
  168. "Options (GCC-compatible):" NL
  169. "-h, --help      show this help and exit" NL
  170. "-E              preprocess" NL
  171. "-I <path>       include directory" NL
  172. "-M[M]           output autodepend make rule" NL
  173. "-MF <file>      autodepend output name" NL
  174. "-MT <target>    autodepend target name (can be specified multiple times)" NL
  175. NL
  176. "Other options:" NL
  177. "--syntax <syntax>   select source file syntax (tasm, sjasm)" NL,
  178.         PROGRAM_NAME
  179.     );
  180. }
  181.  
  182. // Result must be freed by caller.
  183. char *_make_path (const char *a, const char *b)
  184. {
  185.     char *result;
  186.  
  187.     result = malloc (strlen (a) + 1 + strlen (b) + 1);  // including terminating zero
  188.     if (result)
  189.         sprintf (result, "%s" PATHSEPSTR "%s", a, b);
  190.     else
  191.     {
  192.         _perror ("malloc");
  193.     }
  194.     return result;
  195. }
  196.  
  197. // Returns "true" on success.
  198. bool process_included_file (struct source_entry_t *src, char *f_loc, unsigned inc_flags)
  199. {
  200.     bool ok;
  201.     char *tmp;
  202.     char *src_base;
  203.     char *src_base_tmp;
  204.     char *inc_real, *inc_base, *inc_user;
  205.     char *inc_real_tmp, *inc_base_tmp, *inc_user_tmp;
  206.     char *inc_real_res;
  207.     struct include_path_entry_t *resolved;
  208.  
  209.     _DBG_ ("Source user file = '%s'", src->user);
  210.     _DBG_ ("Source base path = '%s'", src->base);
  211.     _DBG_ ("Source real file = '%s'", src->real);
  212.     _DBG_ ("Include file = '%s'", f_loc);
  213.     _DBG_ ("Include flags = 0x%X", inc_flags);
  214.  
  215.     ok = false;
  216.     src_base_tmp = (char *) NULL;
  217.     inc_real_tmp = (char *) NULL;
  218.     inc_base_tmp = (char *) NULL;
  219.     inc_user_tmp = (char *) NULL;
  220.     inc_real_res = (char *) NULL;
  221.  
  222.     inc_user = f_loc;
  223.     if (check_path_abs (f_loc))
  224.     {
  225.         // absolute source's path - use it as is
  226.         inc_real = f_loc;
  227.         inc_base_tmp = get_dir_name (f_loc);
  228.         if (!inc_base_tmp)
  229.         {
  230.             // Fail
  231.             _perror ("get_dir_name");
  232.             goto _local_exit;
  233.         }
  234.         inc_base = inc_base_tmp;
  235.         if (!check_file_exists (f_loc))
  236.             inc_flags &= ~SRCFL_PARSE;
  237.         if (sources_add (&v_sources, inc_real, inc_base, inc_user, inc_flags, NULL))
  238.         {
  239.             // Fail
  240.             _perror ("sources_add");
  241.             goto _local_exit;
  242.         }
  243.         // Success
  244.         ok = true;
  245.     }
  246.     else
  247.     {
  248.         // relative source's path - try to resolve real name
  249.         src_base_tmp = get_dir_name (src->user);
  250.         if (!src_base_tmp)
  251.         {
  252.             // Fail
  253.             _perror ("get_dir_name");
  254.             goto _local_exit;
  255.         }
  256.         src_base = src_base_tmp;
  257.         if (check_path_abs (src->user))
  258.         {
  259.             // Absolute path of primary source file
  260.             tmp = _make_path (src_base, src->user);
  261.             if (!tmp)
  262.             {
  263.                 // Fail
  264.                 _perror ("_make_path");
  265.                 goto _local_exit;
  266.             }
  267.             inc_real_tmp = resolve_full_path (tmp);
  268.             free (tmp);
  269.             if (!inc_real_tmp)
  270.             {
  271.                 // Fail
  272.                 _perror ("resolve_full_path");
  273.                 goto _local_exit;
  274.             }
  275.             inc_real = inc_real_tmp;
  276.             inc_base = src_base;
  277.         }
  278.         else
  279.         {
  280.             // Relative path of primary source file
  281.             tmp = get_dir_name (src->real);
  282.             if (!tmp)
  283.             {
  284.                 // Fail
  285.                 _perror ("get_dir_name");
  286.                 goto _local_exit;
  287.             }
  288.             inc_real_tmp = _make_path (tmp, f_loc);
  289.             free (tmp);
  290.             if (!inc_real_tmp)
  291.             {
  292.                 // Fail
  293.                 _perror ("_make_path");
  294.                 goto _local_exit;
  295.             }
  296.             tmp = inc_real_tmp;
  297.             inc_real_tmp = resolve_full_path (tmp);
  298.             free (tmp);
  299.             if (!inc_real_tmp)
  300.             {
  301.                 // Fail
  302.                 _perror ("resolve_full_path");
  303.                 goto _local_exit;
  304.             }
  305.             inc_real = inc_real_tmp;
  306.             inc_base = src->base;
  307.             if (strcmp (src_base, ".") != 0)
  308.             {
  309.                 inc_user_tmp = _make_path (src_base, inc_user);
  310.                 if (!inc_user_tmp)
  311.                 {
  312.                     // Fail
  313.                     _perror ("_make_path");
  314.                     goto _local_exit;
  315.                 }
  316.                 inc_user = inc_user_tmp;
  317.             }
  318.         }
  319.         if (check_file_exists (inc_real))
  320.         {
  321.             if (sources_add (&v_sources, inc_real, inc_base, inc_user, inc_flags, NULL))
  322.             {
  323.                 // Fail
  324.                 _perror ("sources_add");
  325.                 goto _local_exit;
  326.             }
  327.             // Success
  328.         }
  329.         else
  330.         {
  331.             _DBG_ ("'%s' not found, resolving...", f_loc);
  332.             if (!include_paths_resolve_file (&v_include_paths, f_loc, &resolved))
  333.             {
  334.                 tmp = _make_path (resolved->real, f_loc);
  335.                 if (!tmp)
  336.                 {
  337.                     // Fail
  338.                     _perror ("_make_path");
  339.                     goto _local_exit;
  340.                 }
  341.                 inc_real_res = resolve_full_path (tmp);
  342.                 free (tmp);
  343.                 if (!inc_real_res)
  344.                 {
  345.                     // Fail
  346.                     _perror ("resolve_full_path");
  347.                     goto _local_exit;
  348.                 }
  349.                 inc_real = inc_real_res;
  350.                 inc_base = resolved->real;
  351.                 inc_user = f_loc;
  352.             }
  353.             else
  354.             {
  355.                 inc_flags = 0;
  356.             }
  357.             if (sources_add (&v_sources, inc_real, inc_base, inc_user, 0, NULL))
  358.             {
  359.                 // Fail
  360.                 _perror ("sources_add");
  361.                 goto _local_exit;
  362.             }
  363.             // Success
  364.         }
  365.         // Success
  366.         ok = true;
  367.     }
  368. _local_exit:
  369.     if (src_base_tmp)
  370.         free (src_base_tmp);
  371.     if (inc_real_tmp)
  372.         free (inc_real_tmp);
  373.     if (inc_base_tmp)
  374.         free (inc_base_tmp);
  375.     if (inc_user_tmp)
  376.         free (inc_user_tmp);
  377.     if (inc_real_res)
  378.         free (inc_real_res);
  379.  
  380.     _DBG_ ("Done checking '%s' (%s).", f_loc, ok ? "success" : "failed");
  381.     return ok;
  382. }
  383.  
  384. // Returns "false" on success.
  385. bool collect_included_files (struct source_entry_t *src)
  386. {
  387.     bool ok;
  388.     struct asm_file_t file;
  389.     char *t;
  390.     const char *s;
  391.     unsigned tl, len;
  392.     unsigned inc_flags;
  393.     char *inc_name;
  394.     get_include_proc_t *getincl;
  395.     char st;
  396.     struct included_file_entry_t *incl;
  397.  
  398.     _DBG_ ("Source user file = '%s'", src->user);
  399.     _DBG_ ("Source base path = '%s'", src->base);
  400.     _DBG_ ("Source real file = '%s'", src->real);
  401.  
  402.     ok = false;
  403.  
  404.     // Free on exit (_local_exit):
  405.     asm_file_clear (&file);
  406.     t = (char *) NULL;
  407.  
  408.     if (!_find_get_include_proc (v_syntax, &getincl))
  409.     {
  410.         // Fail
  411.         _DBG ("Unknown syntax specified.");
  412.         goto _local_exit;
  413.     }
  414.  
  415.     if (!asm_file_load (&file, src->user))
  416.     {
  417.         // Fail
  418.         goto _local_exit;
  419.     }
  420.  
  421.     tl = 0;
  422.     while (asm_file_next_line (&file, &s, &len))
  423.     {
  424.         // Free on exit (_loop_exit):
  425.         inc_name = (char *) NULL;
  426.  
  427.         if (tl < len + 1)
  428.         {
  429.             tl = len + 1;       // + terminating zero
  430.             if (t)
  431.                 free (t);
  432.             t = malloc (tl);
  433.             if (!t)
  434.             {
  435.                 // Fail
  436.                 _perror ("malloc");
  437.                 goto _loop_exit;
  438.             }
  439.         }
  440.         memcpy (t, s, len);
  441.         t[len] = '\0';
  442.  
  443.         st = getincl (t, &inc_flags, &inc_name);
  444.  
  445.         switch (st)
  446.         {
  447.         case PARST_OK:
  448.             if (included_files_find (&src->included, inc_name, &incl))
  449.             {
  450.                 if (included_files_add (&src->included, file.line, inc_flags, inc_name, NULL))
  451.                 {
  452.                     // Fail
  453.                     goto _loop_exit;
  454.                 }
  455.             }
  456.             else
  457.             {
  458.                 // HINT: This is weird if we included this file as binary but now we want to parse it
  459.                 if ((inc_flags & SRCFL_PARSE) && !(incl->flags & SRCFL_PARSE))
  460.                     incl->flags |= SRCFL_PARSE;
  461.             }
  462.  
  463.             if (inc_name)
  464.                 free (inc_name);
  465.             inc_name = (char *) NULL;
  466.             break;
  467.         case PARST_SKIP:
  468.             goto _skip_line;
  469.         default:
  470.             // Error
  471.             goto _loop_exit;
  472.         }
  473.     _skip_line:;
  474.     }
  475.  
  476.     ok = true;
  477.     goto _local_exit;
  478.  
  479. _loop_exit:
  480.     if (inc_name)
  481.         free (inc_name);
  482. _local_exit:
  483.     asm_file_free (&file);
  484.     if (t)
  485.         free (t);
  486.     _DBG_ ("Done collecting included files of '%s' (%s).", src->user, ok ? "success" : "failed");
  487.     return !ok;
  488. }
  489.  
  490. // Returns "false" on success.
  491. bool process_included_files_list (struct source_entry_t *src)
  492. {
  493.     bool ok;
  494.     struct included_file_entry_t *p;
  495.  
  496.     ok = false;
  497.  
  498.     p = (struct included_file_entry_t *) src->included.list.first;
  499.     while (p)
  500.     {
  501.         if (!process_included_file (src, p->name, p->flags))
  502.         {
  503.             // Fail
  504.             goto _local_exit;
  505.         }
  506.         p = (struct included_file_entry_t *) p->list_entry.next;
  507.     }
  508.  
  509.     ok = true;
  510.  
  511. _local_exit:
  512.     _DBG_ ("Done parsing included files of '%s' (%s).", src->user, ok ? "success" : "failed");
  513.     return !ok;
  514. }
  515.  
  516. // Returns "false" on success.
  517. bool parse_source (struct source_entry_t *src)
  518. {
  519.     bool ok;
  520.  
  521.     ok = false;
  522.  
  523.     if (collect_included_files (src))
  524.     {
  525.         // Fail
  526.         goto _local_exit;
  527.     }
  528.  
  529.     _DBG_ ("Found %u included files.", src->included.list.count);
  530.  
  531.     if (src->included.list.count && process_included_files_list (src))
  532.     {
  533.         // Fail
  534.         goto _local_exit;
  535.     }
  536.  
  537.     ok = true;
  538.  
  539. _local_exit:
  540.     _DBG_ ("Done parsing '%s' (%s).", src->user, ok ? "success" : "failed");
  541.     return !ok;
  542. }
  543.  
  544. // Returns "false" on success.
  545. bool make_rule (void)
  546. {
  547.     struct input_source_entry_t *isrc;
  548.     struct source_entry_t *src, *last;
  549.  
  550.     for (isrc = (struct input_source_entry_t *) v_input_sources.list.first; isrc;
  551.          isrc = (struct input_source_entry_t *) isrc->list_entry.next)
  552.     {
  553.         if (sources_add (&v_sources, isrc->real, isrc->base, isrc->user, SRCFL_PARSE, NULL))
  554.             return true;        // Fail
  555.     }
  556.  
  557.     if (v_sources.list.count)
  558.     {
  559.         src  = (struct source_entry_t *) v_sources.list.first;
  560.         last = (struct source_entry_t *) v_sources.list.last;
  561.         while (src != (struct source_entry_t *) last->list_entry.next)
  562.         {
  563.             while (src != (struct source_entry_t *) last->list_entry.next)
  564.             {
  565.                 if (src->flags & SRCFL_PARSE)
  566.                 {
  567.                     if (!parse_source (src))
  568.                     {
  569.                         if (prerequisites_add (&v_prerequisites, src->user, NULL))
  570.                             return true;        // Fail
  571.                     }
  572.                     else
  573.                     {
  574.                         show_errors ();
  575.                         exit_on_errors ();
  576.                     }
  577.                 }
  578.                 else
  579.                 {
  580.                     if (prerequisites_add (&v_prerequisites, src->user, NULL))
  581.                         return true;    // Fail
  582.                 }
  583.                 src = (struct source_entry_t *) src->list_entry.next;
  584.             }
  585.             src = (struct source_entry_t *) last->list_entry.next;
  586.             last = (struct source_entry_t *) v_sources.list.last;
  587.         }
  588.     }
  589.  
  590.     return false;       // Success
  591. }
  592.  
  593. // Returns "false" on success.
  594. bool write_rule (const char *name)
  595. {
  596.     FILE *f;
  597.  
  598.     f = fopen (name, "w");
  599.     if (!f)
  600.     {
  601.         // Fail
  602.         _perror ("fopen");
  603.         return true;
  604.     }
  605.  
  606.     if (target_names_print (&v_target_names, f))
  607.         return true;    // Fail
  608.  
  609.     if (fprintf (f, ": ") < 0)
  610.         return true;    // Fail
  611.  
  612.     if (prerequisites_print (&v_prerequisites, f))
  613.         return true;    // Fail
  614.  
  615.     if (fprintf (f, NL) < 0)
  616.         return true;    // Fail
  617.  
  618.     fclose (f);
  619.  
  620.     return false;       // Success
  621. }
  622.  
  623. int main (int argc, char **argv)
  624. {
  625.     unsigned i;
  626.  
  627.     setlocale (LC_CTYPE, "C");
  628.  
  629.     if (argc == 1)
  630.         error_exit ("No parameters. %s" NL, HELP_HINT);
  631.  
  632.     v_base_path_real = get_current_dir ();
  633.     if (!v_base_path_real)
  634.         error_exit ("Failed to get current directory." NL);
  635.     _DBG_ ("Base path = '%s'", v_base_path_real);
  636.  
  637.     i = 1;
  638.     while (i < argc)
  639.     {
  640.         if (strcmp (argv[i], "-h") == 0
  641.         ||  strcmp (argv[i], "--help") == 0)
  642.         {
  643.             v_act_show_help = 1;
  644.             i++;
  645.         }
  646.         else if (strcmp (argv[i], "-E") == 0)
  647.         {
  648.             v_act_preprocess = 1;
  649.             i++;
  650.         }
  651.         else if (strcmp (argv[i], "-I") == 0)
  652.         {
  653.             i++;
  654.             if (i == argc)
  655.             {
  656.                 if (add_missing_arg_error ("-I", i))
  657.                     exit (EXIT_FAILURE);
  658.                 break;
  659.             }
  660.             if (include_paths_add_with_check (&v_include_paths, argv[i], v_base_path_real, NULL))
  661.                 exit (EXIT_FAILURE);
  662.             i++;
  663.         }
  664.         else if (strcmp (argv[i], "-M") == 0
  665.              ||  strcmp (argv[i], "-MM") == 0)
  666.         {
  667.             v_act_make_rule = 1;
  668.             i++;
  669.         }
  670.         else if (strcmp (argv[i], "-MF") == 0)
  671.         {
  672.             i++;
  673.             if (i == argc)
  674.             {
  675.                 if (add_missing_arg_error ("-MF", i))
  676.                     exit (EXIT_FAILURE);
  677.                 break;
  678.             }
  679.             v_output_name = argv[i];
  680.             i++;
  681.         }
  682.         else if (strcmp (argv[i], "-MT") == 0)
  683.         {
  684.             i++;
  685.             if (i == argc)
  686.             {
  687.                 if (add_missing_arg_error ("-MT", i))
  688.                     exit (EXIT_FAILURE);
  689.                 break;
  690.             }
  691.             if (target_names_add (&v_target_names, argv[i], NULL))
  692.                 exit (EXIT_FAILURE);
  693.             i++;
  694.         }
  695.         else if (strcmp (argv[i], "--syntax") == 0)
  696.         {
  697.             i++;
  698.             if (i == argc)
  699.             {
  700.                 if (add_missing_arg_error ("--syntax", i))
  701.                     exit (EXIT_FAILURE);
  702.                 break;
  703.             }
  704.             if (!_str_to_syntax (argv[i], &v_syntax))
  705.                 if (add_error ("Unknown syntax '%s' (#%u).", argv[i], i))
  706.                     exit (EXIT_FAILURE);
  707.             i++;
  708.         }
  709.         else if (argv[i][0] == '-')
  710.         {
  711.             if (add_error ("Unknown option '%s' (#%u).", argv[i], i))
  712.                 exit (EXIT_FAILURE);
  713.             i++;
  714.         }
  715.         else
  716.         {
  717.             if (v_input_sources.list.count >= 1)
  718.             {
  719.                 if (add_error ("Don't know what to do with input file '%s' (#%u).", argv[i], i))
  720.                     exit (EXIT_FAILURE);
  721.             }
  722.             else
  723.             {
  724.                 if (input_sources_add_with_check (&v_input_sources, argv[i], v_base_path_real, NULL))
  725.                     error_exit ("Input source file '%s' was not found." NL, argv[i]);
  726.             }
  727.             i++;
  728.         }
  729.     }
  730.  
  731.     if (v_act_show_help)
  732.     {
  733.         if (v_act_preprocess + v_act_make_rule + v_include_paths.list.count + v_sources.list.count)
  734.         {
  735.             if (add_error ("Other arguments were ignored."))
  736.                 exit (EXIT_FAILURE);
  737.         }
  738.         v_act = ACT_SHOW_HELP;
  739.     }
  740.     else
  741.     {
  742.         if (v_act_preprocess + v_act_make_rule != 2)
  743.         {
  744.             if (add_error ("The only supported mode is when both options -E and -M are specified."))
  745.                 exit (EXIT_FAILURE);
  746.         }
  747.         v_act = ACT_MAKE_RULE;
  748.     }
  749.  
  750.     if (errors.list.count)
  751.     {
  752.         if (v_act_show_help)
  753.             show_title ();
  754.         show_errors ();
  755.         if (v_act_show_help)
  756.         {
  757.             show_help ();
  758.             exit (EXIT_SUCCESS);
  759.         }
  760.         else
  761.             exit_on_errors ();
  762.     }
  763.  
  764.     switch (v_act)
  765.     {
  766.     case ACT_SHOW_HELP:
  767.         show_title ();
  768.         show_help ();
  769.         break;
  770.     case ACT_MAKE_RULE:
  771.         if (!v_target_names.list.count)
  772.         {
  773.             if (add_error ("No target name was specified."))
  774.                 exit (EXIT_FAILURE);
  775.         }
  776.         if (!v_output_name || !strcmp (v_output_name, ""))
  777.         {
  778.             if (add_error ("No output name was specified."))
  779.                 exit (EXIT_FAILURE);
  780.         }
  781.         if (!v_input_sources.list.count)
  782.         {
  783.             if (add_error ("No source files were specified."))
  784.                 exit (EXIT_FAILURE);
  785.         }
  786.         if (errors.list.count)
  787.         {
  788.             show_errors ();
  789.             exit_on_errors ();
  790.         }
  791.         if (!v_include_paths.list.count)
  792.         {
  793.             if (include_paths_add_with_check (&v_include_paths, ".", v_base_path_real, NULL))
  794.                 exit (EXIT_FAILURE);
  795.         }
  796.         _DBG_dump_vars ();
  797.         if (make_rule ())
  798.             error_exit ("Failed to parse sources.");
  799.         if (write_rule (v_output_name))
  800.             error_exit ("Failed to write to output file.");
  801.         break;
  802.     default:
  803.         error_exit ("Action %u is not implemented yet.", v_act);
  804.         break;
  805.     }
  806.  
  807.     return EXIT_SUCCESS;
  808. }
  809.