int fsl_copy(const CC_STRING& src, const CC_STRING& dst) { int fs, fd, last_errno = 0; static char buf[512]; const int chunksize = sizeof(buf); fs = open(src.c_str(), O_RDONLY, 0666); if(fs < 0) { last_errno = errno; goto error; } fd = open(dst.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); if(fd < 0) { last_errno = errno; goto error; } if(fs > 0 && fd > 0) { int n1, n2; do { n1 = read(fs, buf, chunksize); n2 = write(fd, buf, n1); if(n1 != n2) { last_errno = errno; break; } } while(n2 == chunksize); close(fs); close(fd); } error: return - last_errno; }
CC_STRING CMaExpander::TryExpand() { CToken token; CC_STRING outs; static int debug_level; CC_STRING saved_inStr = inStr; debug_level++; while(1) { const char *const last_pos = pos; IgnoreSpaces(); if( ! get_token(tc, &pos, &token, for_include) ) break; if( token.attr == CToken::TA_IDENT ) { CMacro *ma; CC_STRING tmp; ma = GetMacro(token.id); if( IS_MACRO(ma) && ! in_defined_context() ) { if( IS_FLM(ma) ) { skip_blanks(pos); if( *pos == '(' ) { tmp = Expand_FLM(ma); } else goto do_cat; } else { tmp = Expand_OLM(ma); } const ssize_t offset = last_pos - inStr.c_str(); CC_STRING newStr; newStr.strcat(inStr.c_str(), last_pos); newStr += tmp; newStr += pos; inStr = newStr; pos = inStr.c_str() + offset; } else goto do_cat; } else { do_cat: outs.strcat(last_pos, pos); } last_ids[0] = last_ids[1]; last_ids[1] = token.id; } // printf("Leave [%u] %s\n", debug_level, outs.c_str()); --debug_level; // fprintf(stderr, "*** %u: %s => %s\n", debug_level, saved_inStr.c_str(), outs.c_str()); return outs; }
void CMaExpander::Trim(CC_STRING& s) { const char *p1, *p2, *end = s.c_str() + s.size(); for(p1 = s.c_str() ; p1 != '\0' && isblank(*p1); p1++ ) ; for(p2 = end - 1 ; p2 >= s.c_str() && isblank(*p2); p2-- ) ; p2++; if(p2 < end && isblank(*p2) ) p2++; CC_STRING ns; while(p1 < p2) ns += *p1++; s = ns; }
int fsl_copy_with_parent(const CC_STRING& src, const CC_STRING& dst) { CC_STRING ddir; const char *pos; int retval; pos = strrchr(dst.c_str(), '/'); if(pos != NULL) { ddir.strcat(dst.c_str(), pos); retval = fsl_mkdir(ddir); if( retval != 0) return retval; } return fsl_copy(src, dst); }
bool Parser::GetCmdLineIncludeFiles(const CC_ARRAY<CC_STRING>& ifiles, size_t np) { if( ifiles.size() == 0) return true; CC_STRING path; bool in_compiler_dir; for(size_t i = 0; i < ifiles.size(); i++) { if(!rtc->get_include_file_path(ifiles[i], CC_STRING(""), true, false, path, &in_compiler_dir)) { errmsg.Format("Can not find include file \"%s\"", ifiles[i].c_str()); return false; } RealFile *file; file = new RealFile; file->SetFileName(path); if( ! file->Open() ) { errmsg.Format("Can not open include file \"%s\"", ifiles[i].c_str()); return false; } PushIncludedFile(file, NULL, np, in_compiler_dir, conditionals.size()); if( ! RunEngine(1) ) return false; if(has_dep_file() && ! in_compiler_dir) AddDependency(" ", path.c_str()); } return true; }
void fsl_mp_append(const CC_STRING& filename, const void *buf, size_t n) { int fd; fd = open(filename.c_str(), O_CREAT|O_BINARY|O_WRONLY|O_APPEND, 0664); fsl_mp_fdappend(fd, buf, n); close(fd); }
// // Get the include file name without surrouding angle brackets or double quoation marks // static CC_STRING GetIncludeFileName(const CC_STRING& line, bool& quoted) { const char *p1, *p2; CC_STRING filename; char style = '\0'; p1 = line.c_str(); skip_blanks(p1); if( *p1 == '"') style = '"'; else if( *p1 == '<' ) style = '>'; else goto error; p1++; skip_blanks(p1); p2 = p1 + strlen(p1) - 1; while( *p2 == '\t' || *p2 == ' ' || *p2 == '\r' || *p2 == '\n') { if(--p2 < p1) goto error; } if( *p2 != style ) goto error; p2--; while( *p2 == '\t' || *p2 == ' ' ) { if(--p2 < p1) goto error; } filename = CC_STRING(p1, p2+1); quoted = (style == '"'); error: return filename; }
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::SaveDepInfo(const CC_STRING& s) { if(writers[VCH_DEP] && !s.isnull()) { ssize_t ret; ret = writers[VCH_DEP]->Write(s.c_str(), s.size()); if(ret < 0) exit(-EPIPE); } }
void fsl_mp_write(const CC_STRING& filename, const void *buf, size_t n) { int fd; fd = open(filename.c_str(), O_CREAT|O_BINARY|O_WRONLY|O_TRUNC, 0664); flock(fd, LOCK_EX); (void) write(fd, buf, n); flock(fd, LOCK_UN); close(fd); }
CC_STRING fsl_dirname(const CC_STRING& path) { char *tmp; CC_STRING dir; tmp = strdup(path.c_str()); dir = dirname(tmp); free(tmp); return dir; }
bool CMaExpander::IsValidToken(const CC_STRING& s) { const char *p = s.c_str(); if(p == NULL) return false; if( ! isalpha(*p) && *p != '_' ) return false; for(p++; *p != '\0'; p++ ) { if( isblank(*p) ) break; if( ! is_id_char(*p) ) return false; } return true; }
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; }
static void __NO_USE__ dump(const XCHAR *xc) { CC_STRING s; char buf[32]; while( *xc != 0) { if( IS_MA_PAR0(*xc) ) snprintf(buf, sizeof(buf), "\\%u", (uint8_t)*xc ); else if( IS_MA_PAR1(*xc) ) snprintf(buf, sizeof(buf), "#\\%u", (uint8_t)*xc ); else if( IS_MA_PAR2(*xc) ) snprintf(buf, sizeof(buf), "##\\%u", (uint8_t)*xc ); else snprintf(buf, sizeof(buf), "%c", *xc); s += buf; xc++; } if( ! s.empty() ) printf("%s\n", s.c_str()); }
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; }
/* 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; }
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; }
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; }