----------------------------------------------------------------------------*/
/* Standard */
#include <stdio.h> //print
-#include <string.h> //strncmp
#include <errno.h> //errno
-#include <ctype.h> //tolower
/* Posix */
#include <err.h> //warnx
#include <stdlib.h> //exit
#include <unistd.h> //chdir
#include <dirent.h> //opendir
#include <unistr.h> //unicode strings
+#include <string.h> //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 uint8_t*);
-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'];
-#ifndef DL_STACKSIZE
-#define DL_STACKSIZE 64
-#endif
-#ifndef DL_CD_STACKSIZE
-#define DL_CD_STACKSIZE DL_STACKSIZE //square tree
-#endif
-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() (DL_STACKP - DL_STACK)
-#define DL_CD_LEN() (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_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_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
-#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 %x\n", DL_LEN()
-()
-{ int ntok = 0;
- scan:
- if (DL_CD_LEN() >= DL_CD_STACKSIZE)//fail if maxchildren exceeded
- { fprintf(stderr, ERR_CHILD);
- goto fail;
- }
- 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
-<<<<<<< HEAD
- ntok += lexer_lexstring(DL_CD_CURNAME());//lex the directory name
-=======
- ntok += lexer_lexstring(DL_CD_CURNAME()); //lex the directory name
->>>>>>> 15d3ab5e7871ff459af13089b82bf5f17f731ebd
- 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
+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;
}
- 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, 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)
-()
-{ struct dirent** direntpp = lexer_direntpa;
- DIR* cwd = DL_CURDIR();
- 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;
+static
+int scanner_scandir_r
+( DIR* dirp )
+{ DIR* cdirp;
+ struct dirent* direntp;
+ 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;
}