static CC_STRING MakeSemaName(const CC_STRING& filename) { CC_STRING sname; const char *p; char c; for(p = filename.c_str(); (c = *p) != 0; p++) { if(c == '/' || c == '\\') sname += '-'; else if(c == '.') c += '@'; else sname += c; } return sname; }
int fsl_mkdir(const CC_STRING& dirname) { CC_STRING newdir; char *p, *dir; struct stat stb; int retval = 0; if( dirname[0] != '/' ) { newdir = fsl_realpath(dirname); if( newdir.isnull() ) { retval = -EINVAL; goto fail; } } else newdir = dirname.c_str(); dir = (char*)newdir.c_str(); if(newdir[0] == '/') p = (char*)newdir.c_str() + 1; else p = (char*)newdir.c_str(); while(1) { char c = *p; if(c == 0 || c == '/') { const char saved_char = *p; *p = '\0'; if(stat(dir, &stb) != 0) { if ( mkdir(dir, 0775) != 0 ) { retval = -errno; goto fail; } } else if( ! S_ISDIR(stb.st_mode) ) { retval = -EEXIST; goto fail; } if(c == '\0') break; *p = saved_char; } p ++; } fail: return retval; }
void Parser::IncludedFile::save_conditional(Cond *c, int rh) { CC_STRING tmp; static const char *directives[] = {NULL, "if", "elif", "else"}; assert(c->type <= Cond::CT_ELSE); if(directives[c->type]) { tmp.Format(" %-4u %s %s ", rh, directives[c->type], (c->value ? "true" : "false")); cr_text += tmp; if(c->boff) tmp.Format("%u,%d ", c->begin, c->boff); else tmp.Format("%u ", c->begin); cr_text += tmp; if(c->eoff) tmp.Format("%u,%d\n", c->end, c->eoff); else tmp.Format("%u\n", c->end); cr_text += tmp; } }
CC_STRING fsl_realpath(const CC_STRING& src) { char dest[4096]; const char *s; char *d; int state = 0; if( src[0] != '/' ) { (void) getcwd(dest, sizeof(dest)); d = dest + strlen(dest); *d ++ = '/'; } else d = dest; s = src.c_str(); while(1) { const char c = *s++; switch(state) { case 0: switch(c) { case '\0': *d = c; state = 1; break; case UNIX_DD: case DOS_DD: *d++ = c; state = 3; break; case '.': *d++ = c; state = 4; break; default: *d++ = c; break; } break; case 1: #if !HAVE_TRAILING_SPLASH if( *(d-1) == UNIX_DD ) *--d = '\0'; #else if( *(d-1) != UNIX_DD ) *d++ = UNIX_DD, *d = '\0'; #endif goto done; case 2: goto fail; case 3: switch(c) { case '\0': *d = c; state = 1; break; case UNIX_DD: case DOS_DD: break; case '.': *d++ = c; state = 4; break; default: *d++ = c; state = 0; break; } break; case 4: switch(c) { case '\0': *d = c; state = 1; break; case UNIX_DD: case DOS_DD: state = 3; d -= 1; break; case '.': *d++ = c; state = 5; break; default: *d++ = c; state = 0; break; } break; case 5: switch(c) { case '\0': state = 1; goto uplevel; case UNIX_DD: case DOS_DD: state = 3; { char *t; uplevel: t = __stdpath_uplevel(dest, d); if(t == NULL) goto fail; d = t; if(c == '\0') *d = '\0'; break; } default: state = 2; break; } break; } } done: return dest; fail: return NULL; }
CC_STRING CMaExpander::Expand_FLM(CMacro *ma) { CC_STRING outs; CC_ARRAY<CC_STRING> margs; CC_STRING carg; const char *p = pos; int level; skip_blanks(p); if( iseol(*p) ) { gex.format("Macro \"%s\" expects arguments", TR(tc,ma->id)); throw &gex; } if( *p != '(' ) { gex = "Macro expects '('"; throw &gex; } p++; skip_blanks(p); level = 1; while( 1 ) { if( iseol(*p) ) break; if( *p == ',' ) { if( level == 1 && ( ! ma->va_args || (margs.size() + 1 < ma->nr_args) ) ) { Trim(carg); margs.push_back(carg); carg.clear(); } else { carg += ','; skip_blanks(p); } } else if(*p == '(') { level ++; carg += '('; } else if(*p == ')') { level --; if(level == 0) { p++; Trim(carg); margs.push_back(carg); carg.clear(); break; } else carg += ')'; } else { carg += *p; } p++; } pos = p; XCHAR *xc; CC_STRING s; size_t n; n = ma->nr_args; assert(n != CMacro::OL_M); if(n != margs.size()) { if( ma->va_args && margs.size() + 1 == n ) { margs.push_back(CC_STRING("")); } else { gex.format("Macro \"%s\" requires %u arguments, but %u given", TR(tc,ma->id), n, margs.size() ); throw &gex; } } for(xc = ma->parsed; *xc != 0; xc++) { if(IS_MA_PAR2(*xc) || IS_MA_PAR0(*xc)) { const CC_STRING& carg = margs[(uint8_t)*xc]; CMaExpander expander2(tc, carg.c_str(), for_include); CC_STRING tmp; tmp = expander2.TryExpand(); s += tmp; } else if(IS_MA_PAR1(*xc)) { const CC_STRING& carg = margs[(uint8_t)*xc]; s += '"'; s += carg; s += '"'; } else { s += (char) *xc; } } outs += s; return outs; }
static bool GetRealPath(const CC_STRING& name, CC_STRING& opath) { /* Use my own function rather than realpath since realpath will expand symblic links */ opath = fol_realpath(name); return ! opath.isnull() ; }
int Parser::Compute(const char *line) { static const char opp[] = { '<', '=', '>', 'X'}; enum { STAT_INIT, STAT_OPR1, STAT_OPR2, STAT_OPND, STAT_DEFINED, /* defined */ STAT_DEFINED1, /* defined( */ STAT_DEFINED2, /* defined(X */ } state; CC_STACK<sym_t> opr_stack; CC_STACK<SynToken> opnd_stack; sym_t last_opr = SSID_SHARP; SynToken last_token; char sign; const char *symbol = NULL; LOG_VERB dml = LOGV_DEBUG; CC_STRING expansion; if(!gvar_preprocess_mode) { /* * Keep `#if 0' blocks which are usually user comments. */ char *copied_line = strdup(line); const char *first = strtok(copied_line, " \t"); int ignore = 0; /* Simple code and work properly in most cases */ if(first && first[0] == '0') ignore = 1; free(copied_line); if(ignore) return TSV_X; } expansion = ExpandLine(intab, false, line, errmsg); if( !errmsg.isnull() ) { return TSV_X; } ReadReq req(expansion.c_str()); SynToken& token = req.token; opr_stack.push(SSID_SHARP); log(dml, "PUSH OPR: #\n"); sign = 0; state = STAT_OPR1; while(1) { sym_t opr; const char *last_pos = req.cp; int ret; ret = ReadToken(intab, &req, false); if( ret == 0 ) break; else if( ret < 0 ) goto error; if( token.attr == SynToken::TA_CHAR ) token.attr = SynToken::TA_INT; if( sign != 0 ) { if(token.attr != SynToken::TA_UINT && token.id != SSID_DEFINED) { errmsg.Format("%s following %c", TR(intab,token.id), sign); goto error; } if(sign == '-') { token.attr = SynToken::TA_INT; token.i32_val = -token.i32_val; } sign = 0; } else if( (token.id == SSID_ADDITION || token.id == SSID_SUBTRACTION) && CheckPrevOperator(last_opr)) { sign = token.id == SSID_ADDITION ? '+' : '-'; goto next; } switch(state) { case STAT_INIT: if(IsOperator(token.id)) state = STAT_OPR1; else if(token.id == SSID_DEFINED) state = STAT_DEFINED; else if(token.attr == SynToken::TA_IDENT) state = STAT_OPND; break; case STAT_OPND: if(IsOperator(token.id)) state = STAT_OPR1; else { errmsg = "Adjacent operands"; goto error; } break; case STAT_OPR1: if(IsOperator(token.id)) state = STAT_OPR2; else if(token.id == SSID_DEFINED) state = STAT_DEFINED; else state= STAT_INIT; break; case STAT_OPR2: if(IsOperator(token.id)) { } else if(token.id == SSID_DEFINED) state = STAT_DEFINED; else state = STAT_INIT; break; case STAT_DEFINED: if(token.id == SSID_LEFT_PARENTHESIS) state = STAT_DEFINED1; else if(token.attr == SynToken::TA_IDENT) { CheckSymbolDefined(last_pos, false, &token); if(!errmsg.isnull()) goto error; state = STAT_INIT; } break; case STAT_DEFINED1: if(token.attr == SynToken::TA_IDENT) { state = STAT_DEFINED2; symbol = last_pos; } else { errmsg = "Syntax error: "; goto error; } break; case STAT_DEFINED2: if(token.id == SSID_RIGHT_PARENTHESIS) { CheckSymbolDefined(symbol, false, &token); if(!errmsg.isnull()) goto error; state = STAT_INIT; opnd_stack.push(token); opr = token.id; goto next; } else { errmsg = "Unmatched ("; goto error; } break; } if(state == STAT_DEFINED || state == STAT_DEFINED1 || state == STAT_DEFINED2) goto next; if( token.id == SynToken::TA_UINT || token.id == SynToken::TA_INT ) log(dml, "Current: %u\n", token.u32_val); else log(dml, "Current: %s\n", TR(intab,token.id)); // log(dml, "OPR Stack: \n", opr_stack); // log(dml, "OPND Stack: \n", opnd_stack); opr = token.id; if( IsOperator(opr) ) { sym_t opr0; int result; again: opr0 = opr_stack.top(); result = intab->opMat.Compare(opr0, opr); log(dml, "Compare: %s %c %s\n", TR(intab,opr0),opp[1+result],TR(intab,opr)); switch(result) { case _EQ: opr_stack.pop(opr0); break; case _GT: opr_stack.pop(opr0); if( ! CalculateOnStackTop(opr0, opnd_stack, opr_stack) ) { goto error; } goto again; case _LT: opr_stack.push(opr); break; case _XX: errmsg.Format("Cannot compare \"%s\" and \"%s\"", TR(intab,opr0), TR(intab,opr)); log(LOGV_ERROR, "*ERROR* %s\n", errmsg.c_str()); goto error; } } else { opnd_stack.push(token); } next: last_opr = opr; } do { sym_t opr0; int result; if( ! opr_stack.pop(opr0) ) goto error; result = intab->opMat.Compare(opr0, SSID_SHARP); log(dml, "Compare: %s %c #\n", TR(intab,opr0),opp[result]); switch(result) { case _EQ: break; case _GT: if( ! CalculateOnStackTop(opr0, opnd_stack, opr_stack) ) { goto error; } break; default: log(LOGV_ERROR, "%s:%u: Bad expression\n", __func__, __LINE__); errmsg = "[1] Bad expression"; goto error; } } while( opr_stack.size() != 0 ); if( opnd_stack.size() != 1 ) { log(LOGV_ERROR, "%s:%u: Bad expression\n", __func__, __LINE__); errmsg = "[2] Bad expression"; goto error; } if( opnd_stack.top().attr == SynToken::TA_IDENT ) { if( gvar_preprocess_mode ) { return TSV_0; } return TSV_X; } log(dml, "Numberic Value: %u\n", opnd_stack.top().i32_val);; return !!opnd_stack.top().i32_val; error: log(LOGV_ERROR, "*Error* %s\n", errmsg.c_str()); return gvar_preprocess_mode ? TSV_0 : TSV_X; }
/* Parse the input file and update the global symbol table and macro table, * output the stripped file contents to devices if OUTFILE is not nil. * * Returns a pointer to the error messages on failure, or nil on success. */ bool Parser::DoFile(InternalTables *intab, size_t num_preprocessors, File *infile, ParserContext *ctx) { bool ignored; FILE *out_fp; bool retval = false; CC_STRING bak_fname, out_fname; struct stat stb; struct utimbuf utb; if(ctx) { ignored = ctx->check_ignore(infile->name); if( ignored && ! has_dep_file() ) return true; } else ignored = false; if( stat(infile->name, &stb) == 0 ) { utb.actime = stb.st_atime; utb.modtime = stb.st_mtime; } if( ! infile->Open() ) { errmsg.Format("Cannot open \"%s\" for reading\n"); return false; } out_fp = NULL; if(ctx != NULL && ctx->outfile != ParserContext::OF_NULL ) { if( ctx->outfile == ParserContext::OF_STDOUT ) out_fp = stdout; else { #if SANITY_CHECK assert( ! ctx->baksuffix.isnull() ); #endif if( ctx->baksuffix[0] != ParserContext::MAGIC_CHAR ) bak_fname = infile->name + ctx->baksuffix; else out_fname = infile->name; int fd; char tmp_outfile[32]; strcpy(tmp_outfile, "@cl@-XXXXXX"); fd = mkstemp(tmp_outfile); if( fd < 0 ) { errmsg.Format("Cannot open \"%s\" for writing\n", tmp_outfile); infile->Close(); return false; } out_fp = fdopen(fd, "wb"); out_fname = tmp_outfile; } } if(ctx == NULL) memset(writers, 0, sizeof(writers)); else { writers[VCH_CL] = NULL; if(!ctx->of_array[VCH_DEP].isnull()) writers[VCH_DEP] = gvar_file_writers[VCH_DEP]; if(!ctx->of_array[VCH_CV].isnull()) writers[VCH_CV] = gvar_file_writers[VCH_CV]; } if( num_preprocessors >= COUNT_OF(Parser::preprocessors) ) num_preprocessors = COUNT_OF(Parser::preprocessors); Reset(intab, num_preprocessors, ctx); if(has_dep_file()) AddDependency("", infile->name); PushIncludedFile(infile, out_fp, COUNT_OF(Parser::preprocessors), false, conditionals.size()); if(ctx != NULL) { GetCmdLineIncludeFiles(ctx->imacro_files, 2); GetCmdLineIncludeFiles(ctx->include_files, COUNT_OF(preprocessors)); } if( ! RunEngine(0) ) goto error; SaveDepInfo(deptext); if( conditionals.size() != 0 ) errmsg = "Unmatched #if"; else retval = true; error: if(!retval) { if(included_files.size() > 0) { CC_STRING tmp; tmp.Format("%s:%u: %s\n%s\n", GetCurrentFileName().c_str(), GetCurrentLineNumber(), pline.from.c_str(), GetError()); errmsg = tmp; } #if 0 IncludedFile *ilevel; while(included_files.size() > 0) { ilevel = PopIncludedFile(); if(infile != ilevel->ifile) delete ilevel; } #endif } if(out_fp != NULL && out_fp != stdout) fclose(out_fp); if( retval && ctx != NULL && ! ignored ) { CC_STRING semname; sem_t *sem; semname = MakeSemaName(infile->name); sem = sem_open(semname.c_str(), O_CREAT, 0666, 1); sem_wait(sem); if( ! bak_fname.isnull() ) rename(infile->name, bak_fname); if( ! out_fname.isnull() ) { rename(out_fname, infile->name); utime(infile->name.c_str(), &utb); } sem_post(sem); sem_unlink(semname.c_str()); } else if( ! out_fname.isnull() ) unlink(out_fname.c_str()); return retval; }