/*!@file \brief APC main driver \details The driver assumes the existence of a bison-generated parser, referenced by the external function 'yyparse'. It also assumes the existence of a lexer which must be initialized before parsing, referenced by the external function 'lexer_init' which assumes standard error handling. All input arguments are made available through the exposed (that is, non-static) array of character pointers 'cargs', which point to the non-duplicated strings in 'argv' directly from the system. \author Jordan Lavatai \date Aug 2016 ----------------------------------------------------------------------------*/ /* Standard */ #include //print #include //errors #include //strndupa /* Posix */ #include //exit #include //getopt, sysconf #include //opendir /* Internal */ #include "apc.h" #include "parser.tab.h" //bison #include "ir.h" #include "print.h" #define DEFAULT_PAGESIZE 4096 const char** cargs; const uint8_t* apc_package_name; long sys_pagesize; int main(int, char*[]); extern //lexer.c int lexer_init(void); extern //scanner.c int scanner_init(void); extern //scanner.c void scanner_quit(void); extern //scanner.c int scanner_scandir(DIR*); extern //ir.c int ir_init(void); extern //ir.c int ir_linker(void); extern //ir.c int ir_condenser(void); extern void ir_test(void); static char* getcwd_basename(void); #define $($)#$ //stringifier #define MAXSTR 4096 #define MAXERR "-%c allows at most " $(MAXSTR) " input characters\n", opt #define OPTS "d:o:h-" #define USAGE "Usage %s [-d dir_root][-o output_file][-h]\n", argv[0] #define USAGE_LONG \ "\tOptions:\n" \ "\t\t-d\tRoot directory to parse from \t[./]\n" \ "\t\t-o\tOutput filename \t\t[a.asspak]\n" \ "\t\t-h\tPrint this help\n" #define DONE -1 #undef eprintf_callback #define free_and_exit(ecode) do { \ free(cargs); \ exit(ecode); \ } while(0) #define eprintf_callback(...) free_and_exit(EXIT_FAILURE) /* Main entry from terminal parses the command line and kicks off recursive scanning */ int main ( int argc, char* argv[] ) { int opt; DIR* dirp; const char* scanpath; char* path_iter; cargs = (const char**) malloc('Z'); getopt: switch (opt = getopt(argc, argv, OPTS)) { case 'd' : path_iter = optarg; while (*path_iter++ != '\0'); path_iter -= 2; if (*path_iter == '/') *path_iter = '\0'; case 'o' : if (strnlen(optarg, MAXSTR) != MAXSTR) { cargs[opt] = optarg; goto getopt; } fprintf(stderr, MAXERR); default : eprintf(USAGE); case 'h' : printf(USAGE); printf(USAGE_LONG); free_and_exit(EXIT_SUCCESS); case DONE: break; } if ((sys_pagesize = sysconf(_SC_PAGESIZE)) == 0) sys_pagesize = DEFAULT_PAGESIZE; if (ir_init()) { perror("init"); free_and_exit(EXIT_FAILURE); } scanpath = cargs['d'] ? cargs['d'] : "./"; errno = 0; dirp = opendir(scanpath); if (dirp == NULL || errno) eprintf("Path %s could not be accessed: %s\n", scanpath, strerror(errno)); errno = 0; if (chdir(scanpath) || errno) eprintf("Could not change directory to %s: %s\n", scanpath, strerror(errno)); apc_package_name = (uint8_t*) getcwd_basename(); if (scanner_scandir(dirp)) eprintf(strerror(errno)); ir_test(); ir_linker(); ir_condenser(); free_and_exit(EXIT_SUCCESS); } static char* getcwd_basename ( void ) { char* path_iter,* path_buf,* path; int pages; path = NULL; pages = 1; try_cwd: path_buf = (char*) malloc(MAXSTR * pages); errno = 0; getcwd(path_buf, MAXSTR * pages); if (errno == ERANGE) { pages++; free(path_buf); goto try_cwd; } else if (errno) { perror(NULL); free(path_buf); return NULL; } path = path_iter = path_buf; while (*path_iter != '\0') { if (*path_iter == '/') path = path_iter + 1; path_iter++; } return path; }