X-Git-Url: https://www.kengrimes.com/gitweb/?p=henge%2Fapc.git;a=blobdiff_plain;f=src%2Fscanner.c;h=d01be156a96d2812beeaef6ab635c0a8501bb109;hp=5c06a4e2b7cdcac951c1ce9ea3b2cb00fece15ab;hb=25a23e5134b1d9649f0279a4028b887c9deb9987;hpb=59c61dc6411254681b81571dd580336a75c0100d diff --git a/src/scanner.c b/src/scanner.c index 5c06a4e..d01be15 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -13,234 +13,102 @@ ----------------------------------------------------------------------------*/ /* Standard */ #include //print -#include //strncmp #include //errno -#include //tolower /* Posix */ #include //warnx #include //exit #include //chdir #include //opendir #include //unicode strings +#include //strlen /* Internal */ #include "parser.tab.h" /* Public */ -int scanner_init(void); void scanner_quit(void); -int scanner(void); -int scanner_scanpixels(int*,int); +int scanner_scanpath(char const*); +int scanner_scandir(DIR*); /* Private */ -extern //lexer.c -int lexer_lexstring(const char*); -extern //lexer.c -void lexer_pushtok(int, int); static -int dredge_current_depth(void); -/* Mem */ -extern //lexer.c -struct dirent* lexer_direntpa[], **lexer_direntpp; -extern //SRC_DIR/bin/tools/apc.c -const char* cargs['Z']; -#define DL_STACKSIZE 64 -#define DL_CD_STACKSIZE DL_STACKSIZE //square tree - -static -struct dirlist -{ DIR* dirp; - struct dirent* child_directory_stack[DL_CD_STACKSIZE],** cds; -} directory_list_stack[DL_STACKSIZE + 1],* dls; //+1 for the root dir -static -FILE* current_open_file = NULL; - -/* Directory Listing Stack - FILO Stack for keeping an open DIR* at each directory depth for treewalk. - This stack is depth-safe, checking its depth during push operations, but not - during pop operations, to ensure the thread doesn't open too many files at - once (512 in c runtime), or traverse too far through symbolic links. - A directory listing includes a DIR* and all DIR-typed entity in the directory - as recognized by dirent, populated externally (and optionally). - This stack behaves abnormally by incrementing its PUSH operation prior to - evaluation, and the POP operations after evaluation. This behavior allows - the 'DL_CURDEPTH' operation to map to the current element in the 'dl_stack' - array, and it is always treated as the "current depth". This also allows us - to init the root directory to 'directory_list_stack'[0] and pop it in a safe - and explicit manner. -*/ -#define DL_STACK (directory_list_stack) -#define DL_STACKP (dls) -#define DL_CD_STACK ((*DL_STACKP).child_directory_stack) -#define DL_CD_STACKP ((*DL_STACKP).cds) -#define DL_CURDIR() ((*DL_STACKP).dirp) -#define DL_LEN() ((int)(DL_STACKP - DL_STACK)) -#define DL_CD_LEN() ((int)(DL_CD_STACKP - DL_CD_STACK)) -#define DL_INIT() (DL_STACKP = DL_STACK) -#define DL_CD_INIT() (DL_CD_STACKP = DL_CD_STACK) -#define DL_POP() ((*DL_STACKP--).dirp) -#define DL_CD() (*DL_CD_STACKP) -#define DL_CD_CURNAME() (DL_CD()->d_name) -#define DL_CD_POP() (*--DL_CD_STACKP) -#define DL_PUSH(D) ((*++DL_STACKP).dirp = D) -#define DL_CD_PUSH(E) (*DL_CD_STACKP++ = E) - - -/* Initializer - Initializer expects a function pointer to its lexical analysis function. - Sets up stack pointers and returns boolean true if 'opendir' encounters an - error, or if dredge_current_depth returns boolean true. -*/ -int scanner_init -#define CWDSTR "./" -#define ROOTDIR (cargs['d'] ? cargs['d'] : CWDSTR) -() -{ DL_INIT(); - DL_STACK[0].dirp = opendir(ROOTDIR); - if (current_open_file != NULL) - { fclose(current_open_file); - current_open_file = NULL; - } - printf("Root dir %s\n",ROOTDIR); - return !chdir(ROOTDIR) && (DL_STACK[0].dirp == NULL || dredge_current_depth() == -1); -} - -/* Quit */ -void scanner_quit -() -{ if (DL_CURDIR()) - closedir(DL_CURDIR()); -} - -/* Scanner - The main driver of the scanner will advance the current treewalk state and - tokenize tree-based push/pop operations. It will call 'lexer_lex' to - tokenize directory names prior to making a push operation. safe checking for - all returns from the filesystem handler will exit on serious system errors. - - after pushing a new directory to the directory list, the scanner will dredge - the directory and alphabetically sort all file entries into the lexer's file - array, while placing all subdirectory entries in the current depth's child - directory stack to be scanned later. - - Returns the number of tokens generated on success, -1 on error. +int scanner_scandir_r(DIR*); +extern //lexer.rl +int lexer_init(void); +extern //lexer.rl +void lexer_quit(void); +extern //lexer.rl +int lexer_lexfile(uint8_t*); +extern //lexer.rl +int lexer_lexdir(uint8_t*); +extern //lexer.rl +void lexer_closedir(void); +/* Scan the provided path + Changes working directory to the provided pathname and, if successful, sends + a directory stream of the provided path to scanner_scandir */ -int scanner -#define $($)#$ //stringifier -#define ERR_CHILD "Fatal: Maximum of " $(DL_CD_STACKSIZE) " child " \ - "directories exceeded for directory at depth %i\n",DL_LEN() -#define ERR_DEPTH "Fatal: Maximum directory depth of " $(DL_STACKSIZE) \ - " exceeded during directory scan\n" -#define ERR_DL "Fatal: Directory List Stack Corruption %i\n", DL_LEN() -() -{ int ntok = 0; - scan: - if (DL_CD_LEN() >= DL_CD_STACKSIZE)//fail if maxchildren exceeded - { fprintf(stderr, ERR_CHILD); - goto fail; +int scanner_scanpath +( char const* pathname ) +{ DIR* dirp; + errno = 0; + if ((dirp = opendir(pathname)) == NULL || errno) + { fprintf(stderr, "Path %s could not be accessed\n", pathname); + return -1; } - if (DL_CD_LEN() > 0) //There are entities to process - { if (DL_CD_POP() == NULL) //If the dirent is null, then the - goto libfail; //lib function in dirent has failed - ntok += lexer_lexstring(DL_CD_CURNAME());//lex the directory name - if (DL_LEN() >= DL_STACKSIZE) //fail if maxdepth exceeded - { fprintf(stderr, ERR_DEPTH); - goto fail; - } - if (chdir(DL_CD_CURNAME())) //move into the new directory - goto libfail; - if (DL_CURDIR() == NULL) //open the cwd - goto libfail; - lexer_pushtok(CLOPEN, 0); //Push "Open Directory" token - ntok++; - return dredge_current_depth(); //Filter and sort the current depth - } - else if (DL_LEN() >= 0) //Any dirs left? (Including root) - { if (closedir(DL_POP())) //close the directory we just left - goto libfail; - if (DL_LEN() == -1) //If we just popped root, - goto done; //we're done - lexer_pushtok(CLCLOSE, 0); //Else push "Close Directory" token, - ntok++; - if (!chdir("..")) //move up a directory and - goto scan; //start over - } - fprintf(stderr, ERR_DL); - libfail: - perror("scanner: "); - fail: - return -1; - done: - return ntok; + if (chdir(pathname)) + return -1; + return scanner_scandir(dirp); } -/* Scan Pixels - Scans up to 'len' pixels from the current file into 'buf'. - Returns the number of pixels scanned from the file, or -1 on error +/* Scan directory stream + Recursively scans the provided directory, sending CLOPEN and CLCLOSE tokens + to the parser when entering new directories (classes) */ -int scanner_scanpixels -( int* buf, - int max_len -) -{ static int /*col_len,*/ row_len = 0, row; - //Open the current file if not yet open - if (current_open_file == NULL) - { if ((current_open_file = fopen(DL_CD_CURNAME(),"rb")) == NULL) - { perror("fopen: "); - return -1; - } - //Verify file header, get row_len/col_len - //if (read_img_header(&row_len, &col_len)) - //return -1; - row = 0; - } - //Read pixels into the buffer if there are rows left in the image - if (row++ < row_len) - //TODO: return read_img_pixels(buf, col_len); - printf("SCANPIXELS NOT IMPLEMENTED\n."); - //Close the file and return 0 - fclose(current_open_file); - current_open_file = NULL; - return 0; +int scanner_scandir +( DIR* dirp ) +{ int scandir_status; + if (lexer_init()) + return -1; + scandir_status = scanner_scandir_r(dirp); + lexer_quit(); + return scandir_status; } -/* Directory Entity Sort and Filter (Dredge) - This filter removes all unhandled file types, and places any 'DT_DIR' type - files in the current Directory List's directory stack. Upon finishing, - the 'CE_STACK' is sorted alphabetically, and the current 'DL_CD_STACK' is - populated. Prints warnings for unhandled files. - - Returns -1 if 'readdir' encounters an error, otherwise returns the number of - directory entries sent to the external 'lexer_direntpa' array. -*/ -typedef //so we can typecast dirent's 'alphasort()' to take const void*s -int (*qcomp)(const void*, const void*); -static inline -int dredge_current_depth -#define READDIR_ERROR (-1) -#define READDIR_DONE (0) -#define DPS_LEN() (lexer_direntpp - lexer_direntpa) -#define DPS_PUSH(E) (*lexer_direntpp++ = E) -() -{ DIR* cwd = DL_CURDIR(); +static +int scanner_scandir_r +( DIR* dirp ) +{ DIR* cdirp; struct dirent* direntp; - DL_CD_INIT(); - scan_next: - if ((direntp = readdir(cwd)) != NULL) - { switch (direntp->d_type) - { case DT_REG: - DPS_PUSH(direntp); - goto scan_next; - case DT_DIR: - if (*(direntp->d_name) == '.') //skip hidden files and relative dirs - goto scan_next; - DL_CD_PUSH(direntp); - goto scan_next; + scan_next_dirent: + errno = 0; + direntp = readdir(dirp); + if (errno) + goto libfail; + if (direntp != NULL) + { if (*(direntp->d_name) == '.') //skip hidden or relative files + goto scan_next_dirent; + switch (direntp->d_type) + { case DT_REG: + lexer_lexfile((uint8_t*)direntp->d_name); + goto scan_next_dirent; + case DT_DIR: + lexer_lexdir((uint8_t*)direntp->d_name); //lex the dirname + if (chdir(direntp->d_name)) //change to the specified dir + goto libfail; + errno = 0; + if ((cdirp = opendir(".")) == NULL || errno) //open it + goto libfail; + if(scanner_scandir_r(cdirp)) //scan the directory + goto libfail; + if (chdir("..")) //return to the parent dir + goto libfail; + lexer_closedir(); //push "Close Directory" token + goto scan_next_dirent; //continue scan case DT_UNKNOWN: - warnx("unknown file %s: ignoring", direntp->d_name); + warnx("unknown file %s: ignoring", direntp->d_name); default: - goto scan_next; - } + goto scan_next_dirent; + } } - if (errno) - return -1; - qsort(lexer_direntpa, DPS_LEN(), sizeof direntp, (qcomp)alphasort); - return DPS_LEN(); + return closedir(dirp); + libfail: + perror("scanner_scandir"); + return -1; }