root class is name of package, apc_package_name available to extern
[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
27 #define DEFAULT_PAGESIZE 4096
28 const char** cargs;
29 const char* apc_package_name;
30 long sys_pagesize;
31
32 int main(int, char*[]);
33
34 extern //lexer.c
35 int lexer_init(void);
36 extern //scanner.c
37 int scanner_init(void);
38 extern //scanner.c
39 void scanner_quit(void);
40 extern //scanner.c
41 int scanner_scandir(DIR*);
42 extern //ir.c
43 int ir_init(void);
44 extern //ir.c
45 int ir_linker(void);
46 extern //ir.c
47 int ir_condenser(void);
48 extern
49 void ir_test(void);
50
51 /* Main entry from terminal
52 parses the command line and kicks off recursive scanning
53 */
54 int main
55 ( int argc,
56 char* argv[]
57 )
58 #define $($)#$ //stringifier
59 #define MAXSTR 255
60 #define MAXERR "-%c allows at most " $(MAXSTR) " input characters\n", opt
61 #define OPTS "d:o:h-"
62 #define USAGE "Usage %s [-d dir_root][-o output_file][-h]\n", argv[0]
63 #define USAGE_LONG \
64 "\tOptions:\n" \
65 "\t\t-d\tRoot directory to parse from \t[./]\n" \
66 "\t\t-o\tOutput filename \t\t[a.asspak]\n" \
67 "\t\t-h\tPrint this help\n"
68 #define DONE -1
69 { int opt;
70 const char* scanpath;
71 char* path_iter;
72 char path_buf[APC_NAME_MAX];
73 DIR* dirp;
74 cargs = (const char**) malloc('Z');
75 getopt:
76 switch (opt = getopt(argc, argv, OPTS))
77 { case 'd' :
78 case 'o' :
79 if (strnlen(optarg, MAXSTR) != MAXSTR)
80 { cargs[opt] = optarg;
81 goto getopt;
82 }
83 fprintf(stderr, MAXERR);
84 default :
85 fprintf(stderr, USAGE);
86 exit(EXIT_FAILURE);
87 case 'h' :
88 printf(USAGE);
89 printf(USAGE_LONG);
90 exit(EXIT_SUCCESS);
91 case DONE:
92 break;
93 }
94 if ((sys_pagesize = sysconf(_SC_PAGESIZE)) == 0)
95 sys_pagesize = DEFAULT_PAGESIZE;
96 if (ir_init())
97 { perror("init");
98 free(cargs);
99 exit(EXIT_FAILURE);
100 }
101
102 scanpath = cargs['d'] ? cargs['d'] : "./";
103 errno = 0;
104 dirp = opendir(scanpath);
105 if (dirp == NULL || errno)
106 { fprintf(stderr, "Path %s could not be accessed\n", scanpath);
107 return -1;
108 }
109 if (chdir(scanpath))
110 { fprintf(stderr, "Could not change directory to %s \n", scanpath);
111 return -1;
112 }
113 apc_package_name = path_iter = getcwd(path_buf, APC_NAME_MAX - 1);
114 basename:
115 while (*path_iter != '\0')
116 { if (*path_iter == '/')
117 apc_package_name = path_iter + 1;
118 path_iter++;
119 }
120 if (apc_package_name == path_buf)
121 { fprintf(stderr, "Error resolving package name from path %s\n", path_buf);
122 free(cargs);
123 exit(EXIT_FAILURE);
124 }
125 if (apc_package_name == path_iter)
126 { *--path_iter = '\0';
127 goto basename;
128 }
129 if (scanner_scandir(dirp))
130 { perror("scanner");
131 free(cargs);
132 exit(EXIT_FAILURE);
133 }
134 ir_test();
135 ir_linker();
136 ir_condenser();
137 free(cargs);
138 exit(EXIT_SUCCESS);
139 }