| 1 | /* |
| 2 | * include [-i "{string}"] [ {FILE} ] |
| 3 | * recursively expands files included in {FILE}, where "inclusion" |
| 4 | * is specified by |
| 5 | * ^{include_cmd} "file", or |
| 6 | * ^{include_cmd} <file> |
| 7 | * {include_cmd} is {string} if -i option used, or |
| 8 | * is default to '#include'. |
| 9 | * |
| 10 | */ |
| 11 | |
| 12 | char *Version= "$Id: include.c,v 1.1 2008/04/18 06:19:50 nhussain Exp $"; |
| 13 | |
| 14 | #include <stdio.h> |
| 15 | |
| 16 | #define YES 1 |
| 17 | #define NO 0 |
| 18 | #define streq(a,b) !strcmp(a,b) |
| 19 | #define strleq(a,b) !strncmp(a,b, strlen(a)) |
| 20 | #define skip_to_eoln(in) while(getc(in) != '\n') |
| 21 | |
| 22 | typedef enum { |
| 23 | M_NORMAL, |
| 24 | M_PAL, |
| 25 | M_last |
| 26 | } MODE; |
| 27 | MODE mode= M_NORMAL; |
| 28 | |
| 29 | char ABSOLUTE_PATH= 1; |
| 30 | char ignore=NO; /*ignore missing file, continue to process*/ |
| 31 | char *incCmd= "#include"; |
| 32 | char *comment= "//"; |
| 33 | int len_incCmd; |
| 34 | char *incDir[80]={"."}; /*first to search is current dir*/ |
| 35 | int last_incDir= 0; /*incDir[0] is .*/ |
| 36 | char *directory(); |
| 37 | /* char *directory(char *name, char *dir); */ |
| 38 | |
| 39 | usage_and_exit(msg1, msg2) |
| 40 | char *msg1, *msg2; |
| 41 | { |
| 42 | if(msg1 != NULL) { |
| 43 | char format[256]; |
| 44 | if(msg2 && *msg2) { sprintf(format, "%s\n", msg1); |
| 45 | fprintf(stderr, format, msg2); |
| 46 | }else { fprintf(stderr, "%s\n", msg1); |
| 47 | } |
| 48 | } |
| 49 | fprintf(stderr, "usage: include [{options}] [{FILE}]\n"); |
| 50 | fprintf(stderr, "options: [default]\n"); |
| 51 | fprintf(stderr, "\t -i {string}: use {string} as include_cmd. [#include]\n"); |
| 52 | fprintf(stderr, "\t where include_cmd is used as follows: \n"); |
| 53 | fprintf(stderr, "\t ^{include_cmd} \"{file}\",or \n"); |
| 54 | fprintf(stderr, "\t ^{include_cmd} <{file}> \n"); |
| 55 | fprintf(stderr, "\t ^{include_cmd} {file} \n"); |
| 56 | fprintf(stderr, "\t -pal: print line number and file name for pal.\n"); |
| 57 | fprintf(stderr, "\t -I {directory}: include files directory for search after .\n"); |
| 58 | fprintf(stderr, "\t -o {outFile}: output to file {outFile}. [stdout]\n"); |
| 59 | fprintf(stderr, "\t -abs|-rel: include file uses absolute or relative paths. [absolute=%d]\n", |
| 60 | ABSOLUTE_PATH); |
| 61 | exit(0); |
| 62 | } |
| 63 | |
| 64 | main(argc, argv) |
| 65 | int argc; |
| 66 | char *argv[]; |
| 67 | { |
| 68 | FILE *in, *out; |
| 69 | int idx=1; |
| 70 | char *outfile=0, *infile; |
| 71 | char dir[100]; /*prefix to a relative path*/ |
| 72 | |
| 73 | if(argc <= 1) usage_and_exit(""); |
| 74 | |
| 75 | while(argv[idx][0] == '-') { |
| 76 | if(streq(argv[idx], "-h") ) { |
| 77 | usage_and_exit(""); |
| 78 | }else if(streq(argv[idx], "-c") && argc>=idx+2) { //comment prefix |
| 79 | comment= argv[idx+1]; |
| 80 | idx+= 2; |
| 81 | }else if(streq(argv[idx], "-I") ) { //include dir |
| 82 | incDir[++last_incDir]= argv[idx+1]; |
| 83 | idx+= 2; |
| 84 | }else if(streq(argv[idx], "-i") && argc>=idx+2) { //include prefix |
| 85 | incCmd= argv[idx+1]; |
| 86 | idx+= 2; |
| 87 | }else if(streq(argv[idx], "-o") && argc>=idx+2) { |
| 88 | outfile= argv[idx+1]; |
| 89 | idx+= 2; |
| 90 | }else if(streq(argv[idx], "-pal") ) { |
| 91 | mode= M_PAL; |
| 92 | idx+= 1; |
| 93 | }else if(streq(argv[idx], "-abs")) { |
| 94 | ABSOLUTE_PATH= 1; |
| 95 | idx+= 1; |
| 96 | }else if(streq(argv[idx], "-rel")) { |
| 97 | ABSOLUTE_PATH= 0; |
| 98 | idx+= 1; |
| 99 | }else{ usage_and_exit("illegal arguments:%s", argv[idx]); |
| 100 | } |
| 101 | } |
| 102 | if(argc == idx) { |
| 103 | infile= (char*) strdup("stdin"); |
| 104 | in=stdin; |
| 105 | incDir[0]= "."; |
| 106 | }else{ |
| 107 | infile= (char*) strdup(argv[idx]); |
| 108 | in= fopen(argv[idx], "r"); |
| 109 | if(in == NULL) usage_and_exit("in file '%s' not found!", argv[idx]); |
| 110 | directory(argv[idx], dir); |
| 111 | incDir[0]= dir; |
| 112 | } |
| 113 | if(outfile == NULL) { out= stdout; |
| 114 | }else{ out= fopen(outfile, "w"); |
| 115 | if(out == NULL) usage_and_exit("can't open output file: %s!", outfile); |
| 116 | } |
| 117 | len_incCmd= strlen(incCmd); |
| 118 | include(infile, in, out, 1); |
| 119 | |
| 120 | print_NOT_FOUND(); |
| 121 | exit(0); |
| 122 | } |
| 123 | |
| 124 | void |
| 125 | DirName(path, dirname) //path: in; dirname: out |
| 126 | char *path, *dirname; |
| 127 | { |
| 128 | int i; |
| 129 | strcpy(dirname, path); |
| 130 | for(i= strlen(dirname); i>=0; --i) { |
| 131 | if(dirname[i] == '/') { |
| 132 | dirname[i+1]= 0; |
| 133 | return; |
| 134 | } |
| 135 | } |
| 136 | dirname[0]= 0; |
| 137 | } |
| 138 | |
| 139 | |
| 140 | int |
| 141 | include(currFile, in, out, depth) |
| 142 | char *currFile; |
| 143 | FILE *in; |
| 144 | FILE *out; |
| 145 | int depth; |
| 146 | { |
| 147 | char *oldDir; |
| 148 | char newDir[100]; /*directory for the include file X, which is needed*/ |
| 149 | /* for files included in X using relative path*/ |
| 150 | char dirname[100]; |
| 151 | |
| 152 | #define FNAME_LEN 200 |
| 153 | char line[256], incFile[FNAME_LEN], closing; |
| 154 | FILE *inc_fd, *find_and_open_file(); |
| 155 | int linenum=0, return_from_include=0, missingFile; |
| 156 | |
| 157 | if(mode==M_PAL) |
| 158 | fprintf(out, "# line 1 %s\n", currFile); |
| 159 | DirName(currFile, dirname); |
| 160 | |
| 161 | while( fgets(line, 256, in) ) { |
| 162 | int i, j=0; |
| 163 | ++ linenum; |
| 164 | if( !strncmp(incCmd, line, len_incCmd) && /*match starting 1st column*/ |
| 165 | (line[i=len_incCmd]==' ' || line[i]=='\t') ) { |
| 166 | while(line[++i]== ' ' || line[i]=='\t') ; /*skip more ws*/ |
| 167 | /* |
| 168 | * if(line[i] != '"' && line[i]!='<') |
| 169 | * usage_and_exit("illegal syntax of 'include_cmd': %s !!", line); |
| 170 | * closing= line[i] == '"' ? '"' : '>'; |
| 171 | */ |
| 172 | if(ABSOLUTE_PATH==0) { //relative path in include file |
| 173 | strcpy(incFile, dirname); |
| 174 | j= strlen(incFile); |
| 175 | } |
| 176 | if(line[i] != '"' && line[i]!='<') incFile[j++]= line[i]; |
| 177 | while(line[++i] != '"' && line[i] != '>' && !isspace(line[i]) && line[i]) { |
| 178 | if(i>=FNAME_LEN) |
| 179 | usage_and_exit("include file name too long (>FNAME_LEN): %s!", line); |
| 180 | incFile[j++]= line[i]; |
| 181 | } |
| 182 | |
| 183 | if(mode != M_PAL) { |
| 184 | fprintf(out, "###depth=%d include ==> %s", depth, line); |
| 185 | } |
| 186 | /*ignore the rest of the line*/ |
| 187 | incFile[j]= 0; |
| 188 | inc_fd= find_and_open_file(incFile, newDir); |
| 189 | if(inc_fd==0 && mode==M_PAL) { |
| 190 | fprintf(stderr, "\t %s\n", incFile); |
| 191 | fprintf(stderr, "\t ^-- %s\n", currFile); |
| 192 | return(1); |
| 193 | } |
| 194 | |
| 195 | oldDir= incDir[0]; /*save current directory before*/ |
| 196 | incDir[0]= newDir; /* move to newDir*/ |
| 197 | missingFile= include(incFile, inc_fd, out, depth+1); /*recursively include*/ |
| 198 | if(missingFile && mode==M_PAL) { |
| 199 | fprintf(stderr, "\t ^-- %s\n", currFile); |
| 200 | return(1); |
| 201 | } |
| 202 | |
| 203 | incDir[0]= oldDir; |
| 204 | |
| 205 | return_from_include= 1; |
| 206 | }else{ |
| 207 | if(mode==M_PAL && return_from_include) |
| 208 | fprintf(out, "# line %d %s\n", linenum, currFile); |
| 209 | return_from_include= 0; |
| 210 | fprintf(out, "%s%s", strleq(comment,line)? "" : |
| 211 | ABSOLUTE_PATH? "": dirname, line); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | return(0); /*OK*/ |
| 216 | } |
| 217 | |
| 218 | #include <stdio.h> |
| 219 | #include <sys/types.h> |
| 220 | #include <sys/stat.h> |
| 221 | |
| 222 | #define MAX_NOT_FOUND 100 |
| 223 | char *NOT_FOUND[MAX_NOT_FOUND]; |
| 224 | int last_NOT_FOUND= -1; |
| 225 | |
| 226 | int |
| 227 | print_NOT_FOUND() |
| 228 | { |
| 229 | int i; |
| 230 | if(last_NOT_FOUND < 0) return; |
| 231 | for(i=0; i<=last_NOT_FOUND; ++i) { |
| 232 | fprintf(stderr, "file not found: %s.\n", NOT_FOUND[i]); |
| 233 | } |
| 234 | usage_and_exit(""); |
| 235 | } |
| 236 | |
| 237 | |
| 238 | FILE |
| 239 | *find_and_open_file(file, newDir) |
| 240 | char *file, *newDir; |
| 241 | { |
| 242 | int i; |
| 243 | FILE *fd; |
| 244 | char incFile[100]; |
| 245 | |
| 246 | //if(file[0] == '/') { /*absolute path, use no parent dirInfo*/ |
| 247 | fd= fopen(file, "r"); |
| 248 | if(fd){ directory(file, newDir); /*obtain dir info from file*/ |
| 249 | return(fd); /*found, done*/ |
| 250 | } |
| 251 | //}else |
| 252 | for(i=0; i<=last_incDir; ++i) { /*include file has a relative path*/ |
| 253 | sprintf(incFile, "%s/%s", incDir[i], file); |
| 254 | fd= fopen(incFile, "r"); |
| 255 | if(fd){ directory(incFile, newDir); |
| 256 | return(fd); /*found, done*/ |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | fprintf(stderr, "include ERR: file not found: %s.\n", file); |
| 261 | exit(1); |
| 262 | |
| 263 | if(0) { |
| 264 | if(++ last_NOT_FOUND >= MAX_NOT_FOUND) { |
| 265 | print_NOT_FOUND(); |
| 266 | } else { |
| 267 | NOT_FOUND[last_NOT_FOUND]= (char*) malloc( strlen(file)+ 1); |
| 268 | strcpy(NOT_FOUND[last_NOT_FOUND], file); |
| 269 | } |
| 270 | } |
| 271 | return(NULL); |
| 272 | } |
| 273 | |
| 274 | |
| 275 | char |
| 276 | *directory(name, dir) /*return directory part of a path*/ |
| 277 | char *name; |
| 278 | char *dir; |
| 279 | { /* and write '*dir'*/ |
| 280 | extern char *strchr(); |
| 281 | char *ptr, *q; /*ptr points to next '/', q char after*/ |
| 282 | strcpy(dir, name); |
| 283 | q= dir; |
| 284 | while( ptr=strchr(q,'/') ) { q= ptr+1; } |
| 285 | if(q == dir) { /*not moved at all, i.e. no '/' in path*/ |
| 286 | strcpy(dir, "."); /*directory of root file is . */ |
| 287 | }else{ *(q-1)= 0; /*cut dir from last '/'*/ |
| 288 | } |
| 289 | return(dir); |
| 290 | } |
| 291 | |