/* $Id$ */ /* Copyright (c) 2007-2022 Pierre Pronchery */ /* This file is part of DeforaOS Devel cpp */ /* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* FIXME: * - remove -t? (parse trigraphs by default) */ #include #include #include #include #include #include "CPP.h" #ifndef PROGNAME_CPP # define PROGNAME_CPP "cpp" #endif /* cpp */ /* private */ /* types */ typedef struct _Prefs { int flags; char const * outfile; const char ** paths; size_t paths_cnt; const char ** defines; size_t defines_cnt; const char ** undefines; size_t undefines_cnt; } Prefs; #define PREFS_t 0x1 #define PREFS_w 0x2 /* prototypes */ static int _cpp(Prefs * prefs, int filec, char * filev[]); static int _cpp_error(void); /* functions */ /* cpp */ static int _cpp_do(Prefs * prefs, FILE * fp, char const * filename); static void _do_print_token(FILE * fp, Token * token); static int _cpp(Prefs * prefs, int filec, char * filev[]) { int ret = 0; FILE * fp; int i; if(prefs->outfile == NULL) fp = stdout; else if((fp = fopen(prefs->outfile, "w")) == NULL) return error_set_print(PROGNAME_CPP, 1, "%s: %s", prefs->outfile, strerror(errno)); for(i = 0; i < filec; i++) ret |= _cpp_do(prefs, fp, filev[i]); if(fclose(fp) != 0) return error_set_print(PROGNAME_CPP, 1, "%s: %s", prefs->outfile, strerror(errno)); return ret; } static int _cpp_do(Prefs * prefs, FILE * fp, char const * filename) { int ret; CppPrefs cppprefs; Cpp * cpp; size_t i; size_t j; size_t k; Token * token; memset(&cppprefs, 0, sizeof(cppprefs)); cppprefs.filename = filename; cppprefs.filters = CPP_FILTER_COMMENT; if(prefs->flags & PREFS_t) cppprefs.filters |= CPP_FILTER_TRIGRAPH; if(prefs->flags & PREFS_w) cppprefs.filters |= CPP_FILTER_WHITESPACE; if((cpp = cpp_new(&cppprefs)) == NULL) return _cpp_error(); for(i = 0; i < prefs->paths_cnt; i++) if(cpp_path_add(cpp, prefs->paths[i]) != 0) break; for(j = 0; j < prefs->defines_cnt; j++) if(cpp_define_add(cpp, prefs->defines[j], NULL) != 0) break; for(k = 0; k < prefs->undefines_cnt; k++) if(cpp_define_remove(cpp, prefs->undefines[k]) != 0) break; if(i != prefs->paths_cnt || j != prefs->defines_cnt || k != prefs->undefines_cnt) { cpp_delete(cpp); return 1; } while((ret = cpp_scan(cpp, &token)) == 0) { if(token == NULL) /* end of file */ break; _do_print_token(fp, token); token_delete(token); } if(ret != 0) _cpp_error(); cpp_delete(cpp); return ret; } static void _do_print_token(FILE * fp, Token * token) { CppCode code; code = token_get_code(token); #ifdef DEBUG fprintf(stderr, "DEBUG: \"%s\" (%d)\n", token_get_string(token), code); #else if(code != CPP_CODE_META_ERROR && code != CPP_CODE_META_WARNING) { fputs(token_get_string(token), fp); return; } fprintf(stderr, "%s%s%s%s%u%s%s\n", code == CPP_CODE_META_ERROR ? "Error" : "Warning", " in ", token_get_filename(token), ":", token_get_line(token), ": ", token_get_string(token)); #endif } /* cpp_error */ static int _cpp_error(void) { return error_print(PROGNAME_CPP); } /* usage */ /* FIXME -E prints metadata? */ static int _usage(void) { fputs("Usage: " PROGNAME_CPP " [-D name[=value]]...[-I directory][-o file][-t][-U name]... input...\n" " -D Add a substitution\n" " -I Add a directory to the search path\n" " -o Write output to a file\n" " -t Convert trigraphs\n" " -U Remove a substitution\n" " -w Filter whitespaces\n", stderr); return 1; } /* main */ static int _main_add_define(Prefs * name, char * define); static int _main_add_path(Prefs * prefs, char const * path); static int _main_add_undefine(Prefs * prefs, char const * undefine); int main(int argc, char * argv[]) { int ret; Prefs prefs; int o; memset(&prefs, 0, sizeof(prefs)); while((o = getopt(argc, argv, "D:I:o:tU:w")) != -1) switch(o) { case 'D': if(_main_add_define(&prefs, optarg) != 0) return 2; break; case 'I': if(_main_add_path(&prefs, optarg) != 0) return 2; break; case 'o': prefs.outfile = optarg; break; case 't': prefs.flags |= PREFS_t; break; case 'U': if(_main_add_undefine(&prefs, optarg) != 0) return 2; break; case 'w': prefs.flags |= PREFS_w; break; default: return _usage(); } if(argc - optind < 1) return _usage(); ret = _cpp(&prefs, argc - optind, &argv[optind]) == 0 ? 0 : 2; free(prefs.paths); return ret; } static int _main_add_define(Prefs * prefs, char * define) { const char ** p; char * value; if(strlen(define) == 0) return 1; value = strtok(define, "="); if((p = realloc(prefs->defines, sizeof(*p) * (prefs->defines_cnt + 1))) == NULL) return error_set_print(PROGNAME_CPP, 1, "%s", strerror(errno)); prefs->defines = p; prefs->defines[prefs->defines_cnt++] = define; return 0; } static int _main_add_path(Prefs * prefs, char const * path) { const char ** p; if((p = realloc(prefs->paths, sizeof(*p) * (prefs->paths_cnt + 1))) == NULL) return error_set_print(PROGNAME_CPP, 1, "%s", strerror(errno)); prefs->paths = p; prefs->paths[prefs->paths_cnt++] = path; return 0; } static int _main_add_undefine(Prefs * prefs, char const * undefine) { const char ** p; if(strlen(undefine) == 0) return 1; if((p = realloc(prefs->undefines, sizeof(*p) * (prefs->undefines_cnt + 1))) == NULL) return error_set_print(PROGNAME_CPP, 1, "%s", strerror(errno)); prefs->undefines = p; prefs->undefines[prefs->undefines_cnt++] = undefine; return 0; }