d01be156a96d2812beeaef6ab635c0a8501bb109
2 \brief APC Directory Scanner
3 \details This hand-written parser/scanner traverses a directory tree and
4 tokenizes elements of the structure which correspond to APC grammar.
5 The parser is implemented as a 2D stack which populates a list of
6 child directories at each depth, handling only the leaf nodes
7 (regular files) of the directory open at the current depth to
8 conserve memory and speed up traversal.
9 The scanner works with the lexer to lexically analyze text, and
10 assumes the existence of an external 'lex' function
11 \author Jordan Lavatai
13 ----------------------------------------------------------------------------*/
15 #include <stdio.h> //print
16 #include <errno.h> //errno
18 #include <err.h> //warnx
19 #include <stdlib.h> //exit
20 #include <unistd.h> //chdir
21 #include <dirent.h> //opendir
22 #include <unistr.h> //unicode strings
23 #include <string.h> //strlen
25 #include "parser.tab.h"
27 void scanner_quit(void);
28 int scanner_scanpath(char const*);
29 int scanner_scandir(DIR*);
32 int scanner_scandir_r(DIR*);
36 void lexer_quit(void);
38 int lexer_lexfile(uint8_t*);
40 int lexer_lexdir(uint8_t*);
42 void lexer_closedir(void);
43 /* Scan the provided path
44 Changes working directory to the provided pathname and, if successful, sends
45 a directory stream of the provided path to scanner_scandir
48 ( char const* pathname
)
51 if ((dirp
= opendir(pathname
)) == NULL
|| errno
)
52 { fprintf(stderr
, "Path %s could not be accessed\n", pathname
);
57 return scanner_scandir(dirp
);
60 /* Scan directory stream
61 Recursively scans the provided directory, sending CLOPEN and CLCLOSE tokens
62 to the parser when entering new directories (classes)
69 scandir_status
= scanner_scandir_r(dirp
);
71 return scandir_status
;
78 struct dirent
* direntp
;
81 direntp
= readdir(dirp
);
85 { if (*(direntp
->d_name
) == '.') //skip hidden or relative files
86 goto scan_next_dirent
;
87 switch (direntp
->d_type
)
89 lexer_lexfile((uint8_t*)direntp
->d_name
);
90 goto scan_next_dirent
;
92 lexer_lexdir((uint8_t*)direntp
->d_name
); //lex the dirname
93 if (chdir(direntp
->d_name
)) //change to the specified dir
96 if ((cdirp
= opendir(".")) == NULL
|| errno
) //open it
98 if(scanner_scandir_r(cdirp
)) //scan the directory
100 if (chdir("..")) //return to the parent dir
102 lexer_closedir(); //push "Close Directory" token
103 goto scan_next_dirent
; //continue scan
105 warnx("unknown file %s: ignoring", direntp
->d_name
);
107 goto scan_next_dirent
;
110 return closedir(dirp
);
112 perror("scanner_scandir");