comments updated
[henge/apc.git] / src / apc.c
1 /*!@file
2 \brief APC main driver
3 \details The driver assumes the existence of a bison-generated parser,
4 referenced by the external function 'yyparse'.
5 It also assumes the existence of a lexer which must be initialized
6 before parsing, referenced by the external function 'lexer_init'
7 which assumes standard error handling.
8 All input arguments are made available through the exposed (that is,
9 non-static) array of character pointers 'cargs', which point
10 to the non-duplicated strings in 'argv' directly from the system.
11 \author Jordan Lavatai
12 \date Aug 2016
13 ----------------------------------------------------------------------------*/
14 /* Standard */
15 #include <stdio.h> //print
16 #include <errno.h> //errors
17 #include <string.h> //strndupa
18 /* Posix */
19 #include <stdlib.h> //exit
20 #include <unistd.h> //getopt, sysconf
21 #include <dirent.h> //opendir
22 /* Internal */
23 #include "apc.h"
24 #include "parser.tab.h" //bison
25 #include "ir.h"
26 #include "print.h"
27
28 #define DEFAULT_PAGESIZE 4096
29 const char** cargs;
30 const uint8_t* apc_package_name;
31 long sys_pagesize;
32
33 int main(int, char*[]);
34
35 extern //lexer.c
36 int lexer_init(void);
37 extern //scanner.c
38 int scanner_init(void);
39 extern //scanner.c
40 void scanner_quit(void);
41 extern //scanner.c
42 int scanner_scandir(DIR*);
43 extern //ir.c
44 int ir_init(void);
45 extern //ir.c
46 int ir_linker(void);
47 extern //ir.c
48 int ir_condenser(void);
49 extern
50 void ir_test(void);
51
52 static
53 char* getcwd_basename(void);
54
55 #define $($)#$ //stringifier
56 #define MAXSTR 4096
57 #define MAXERR "-%c allows at most " $(MAXSTR) " input characters\n", opt
58 #define OPTS "d:o:h-"
59 #define USAGE "Usage %s [-d dir_root][-o output_file][-h]\n", argv[0]
60 #define USAGE_LONG \
61 "\tOptions:\n" \
62 "\t\t-d\tRoot directory to parse from \t[./]\n" \
63 "\t\t-o\tOutput filename \t\t[a.asspak]\n" \
64 "\t\t-h\tPrint this help\n"
65 #define DONE -1
66 #undef eprintf_callback
67 #define free_and_exit(ecode) do { \
68 free(cargs); \
69 exit(ecode); \
70 } while(0)
71 #define eprintf_callback(...) free_and_exit(EXIT_FAILURE)
72 /* Main entry from terminal
73 parses the command line and kicks off recursive scanning
74 */
75 int main
76 ( int argc,
77 char* argv[]
78 )
79 { int opt;
80 DIR* dirp;
81 const char* scanpath;
82 char* path_iter;
83 cargs = (const char**) malloc('Z');
84 getopt:
85 switch (opt = getopt(argc, argv, OPTS))
86 { case 'd' :
87 path_iter = optarg;
88 while (*path_iter++ != '\0');
89 path_iter -= 2;
90 if (*path_iter == '/')
91 *path_iter = '\0';
92 case 'o' :
93 if (strnlen(optarg, MAXSTR) != MAXSTR)
94 { cargs[opt] = optarg;
95 goto getopt;
96 }
97 fprintf(stderr, MAXERR);
98 default :
99 eprintf(USAGE);
100 case 'h' :
101 printf(USAGE);
102 printf(USAGE_LONG);
103 free_and_exit(EXIT_SUCCESS);
104 case DONE:
105 break;
106 }
107 if ((sys_pagesize = sysconf(_SC_PAGESIZE)) == 0)
108 sys_pagesize = DEFAULT_PAGESIZE;
109 if (ir_init())
110 { perror("init");
111 free_and_exit(EXIT_FAILURE);
112 }
113 scanpath = cargs['d'] ? cargs['d'] : "./";
114 errno = 0;
115 dirp = opendir(scanpath);
116 if (dirp == NULL || errno)
117 eprintf("Path %s could not be accessed: %s\n", scanpath, strerror(errno));
118 errno = 0;
119 if (chdir(scanpath) || errno)
120 eprintf("Could not change directory to %s: %s\n", scanpath, strerror(errno));
121 apc_package_name = (uint8_t*) getcwd_basename();
122 if (scanner_scandir(dirp))
123 eprintf(strerror(errno));
124 ir_test();
125 ir_linker();
126 ir_condenser();
127 free_and_exit(EXIT_SUCCESS);
128 }
129
130 static
131 char* getcwd_basename
132 ( void )
133 { char* path_iter,* path_buf,* path;
134 int pages;
135 path = NULL;
136 pages = 1;
137 try_cwd:
138 path_buf = (char*) malloc(MAXSTR * pages);
139 errno = 0;
140 getcwd(path_buf, MAXSTR * pages);
141 if (errno == ERANGE)
142 { pages++;
143 free(path_buf);
144 goto try_cwd;
145 }
146 else if (errno)
147 { perror(NULL);
148 free(path_buf);
149 return NULL;
150 }
151 path = path_iter = path_buf;
152 while (*path_iter != '\0')
153 { if (*path_iter == '/')
154 path = path_iter + 1;
155 path_iter++;
156 }
157 return path;
158 }