static void ForExec(void *valuep, void *argp) { char *value = (char *)valuep; For *arg = (For *)argp; BUFFER buf; /* Parse_FromString pushes stuff back, so we need to go over vars in reverse. */ if (arg->var == NULL) { arg->var = Lst_Last(&arg->vars); arg->text = Buf_Retrieve(&arg->buf); arg->freeold = false; } if (DEBUG(FOR)) (void)fprintf(stderr, "--- %s = %s\n", Var_LoopVarName(Lst_Datum(arg->var)), value); Buf_Init(&buf, arg->guess); Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value); if (arg->freeold) free(arg->text); arg->text = Buf_Retrieve(&buf); arg->freeold = true; arg->var = Lst_Rev(arg->var); if (arg->var == NULL) Parse_FromString(arg->text, arg->lineno); }
static WRes MyCreateDir(const UInt16 *name) { #ifdef USE_WINDOWS_FILE return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); #else CBuf buf; WRes res; Buf_Init(&buf); RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); res = #ifdef _WIN32 _mkdir((const char *)buf.data) #else mkdir((const char *)buf.data, 0777) #endif == 0 ? 0 : errno; Buf_Free(&buf, &g_Alloc); return res; #endif }
/* POSIX says that variable assignments passed on the command line should be * propagated to sub makes through MAKEFLAGS. */ void Var_AddCmdline(const char *name) { Var *v; unsigned int i; BUFFER buf; char *s; Buf_Init(&buf, MAKE_BSIZE); for (v = ohash_first(&global_variables, &i); v != NULL; v = ohash_next(&global_variables, &i)) { /* This is not as expensive as it looks: this function is * called before parsing Makefiles, so there are just a * few non cmdling variables in there. */ if (!(v->flags & VAR_FROM_CMD)) { continue; } /* We assume variable names don't need quoting */ Buf_AddString(&buf, v->name); Buf_AddChar(&buf, '='); for (s = var_get_value(v); *s != '\0'; s++) { if (strchr(quotable, *s)) Buf_AddChar(&buf, '\\'); Buf_AddChar(&buf, *s); } Buf_AddSpace(&buf); } Var_Append(name, Buf_Retrieve(&buf)); Buf_Destroy(&buf); }
static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name, char **subdir, Bool *do_save) { #ifdef USE_WINDOWS_FILE return OutFile_OpenW(p, name); #else CBuf buf; WRes res; char *work_name; Buf_Init(&buf); RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); work_name = (char *)buf.data; int is_normal = (*do_save && (*subdir == NULL || strncmp(work_name, *subdir, strlen(*subdir)) == 0)); if (is_normal || FileIsSQL(work_name)) { if (is_normal) { if (*subdir) work_name = &work_name[strlen(*subdir) + 1]; } else { work_name = basename(work_name); } } // @TODO: test this! if (skip_this_file(work_name)) { Buf_Free(&buf, &g_Alloc); return -1; } res = OutFile_Open(p, (const char *)work_name); Buf_Free(&buf, &g_Alloc); return res; #endif }
/* Initial version of var_set_value(), to be called after create_var(). */ static void var_set_initial_value(Var *v, const char *val) { size_t len; len = strlen(val); Buf_Init(&(v->val), len+1); Buf_AddChars(&(v->val), len, val); }
void SzArEx_Init(CSzArEx *p) { SzAr_Init(&p->db); p->FolderStartPackStreamIndex = 0; p->PackStreamStartPositions = 0; p->FolderStartFileIndex = 0; p->FileIndexToFolderIndexMap = 0; p->FileNameOffsets = 0; Buf_Init(&p->FileNames); }
/* * Var_Init * Initialize the module */ void Var_Init(void) { ohash_init(&global_variables, 10, &var_info); set_magic_shell_variable(); errorIsOkay = true; Var_setCheckEnvFirst(false); VarModifiers_Init(); Buf_Init(&subst_buffer, MAKE_BSIZE); }
static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name) { #ifdef USE_WINDOWS_FILE return OutFile_OpenW(p, name); #else CBuf buf; WRes res; Buf_Init(&buf); RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); res = OutFile_Open(p, (const char *)buf.data); Buf_Free(&buf, &g_Alloc); return res; #endif }
static SRes PrintString(const UInt16 *s) { CBuf buf; SRes res; Buf_Init(&buf); res = Utf16_To_Char(&buf, s #ifndef _USE_UTF8 , CP_OEMCP #endif ); if (res == SZ_OK) fputs((const char *)buf.data, stdout); Buf_Free(&buf, &g_Alloc); return res; }
static Token CondHandleString(bool doEval) { char *lhs; const char *begin; BUFFER buf; /* find the extent of the string */ begin = ++condExpr; while (*condExpr && *condExpr != '"') { condExpr++; } Buf_Init(&buf, 0); Buf_Addi(&buf, begin, condExpr); if (*condExpr == '"') condExpr++; lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval); Buf_Destroy(&buf); return CondHandleComparison(lhs, true, doEval); }
static WRes MyCreateDir(const UInt16 *name, char **subdir, Bool *do_save) { #ifdef USE_WINDOWS_FILE return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); #else CBuf buf; WRes res; char *work_name =NULL; Buf_Init(&buf); RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)); work_name = (char *)buf.data; if (*do_save) { if (*subdir && strstr(work_name, *subdir) == work_name) work_name = &work_name[strlen(*subdir) + 1]; } else { if (strcmp(basename(work_name), globaldata.gd_inidata->archive_dir) == 0) { *subdir = strdup(work_name); *do_save = True; } Buf_Free(&buf, &g_Alloc); return 0; } res = #ifdef _WIN32 _mkdir((const char *)work_name) #else mkdir((const char *)work_name, 0755) // orig 0777 #endif == 0 ? 0 : errno; Buf_Free(&buf, &g_Alloc); return res; #endif }
static Token CondHandleVarSpec(bool doEval) { char *lhs; size_t varSpecLen; bool doFree; /* Parse the variable spec and skip over it, saving its * value in lhs. */ lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree); if (lhs == var_Error) /* Even if !doEval, we still report syntax errors, which * is what getting var_Error back with !doEval means. */ return Err; condExpr += varSpecLen; if (!isspace(*condExpr) && strchr("!=><", *condExpr) == NULL) { BUFFER buf; Buf_Init(&buf, 0); Buf_AddString(&buf, lhs); if (doFree) free(lhs); for (;*condExpr && !isspace(*condExpr); condExpr++) Buf_AddChar(&buf, *condExpr); lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval); Buf_Destroy(&buf); doFree = true; } return CondHandleComparison(lhs, doFree, doEval); }
static SRes SzArEx_Open2( CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) { uint8_t header[k7zStartHeaderSize]; int64_t startArcPos; uint64_t nextHeaderOffset, nextHeaderSize; size_t nextHeaderSizeT; uint32_t nextHeaderCRC; CBuf buffer; SRes res; startArcPos = 0; RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); if (!TestSignatureCandidate(header)) return SZ_ERROR_NO_ARCHIVE; if (header[6] != k7zMajorVersion) return SZ_ERROR_UNSUPPORTED; nextHeaderOffset = GetUi64(header + 12); nextHeaderSize = GetUi64(header + 20); nextHeaderCRC = GetUi32(header + 28); p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) return SZ_ERROR_CRC; nextHeaderSizeT = (size_t)nextHeaderSize; if (nextHeaderSizeT != nextHeaderSize) return SZ_ERROR_MEM; if (nextHeaderSizeT == 0) return SZ_OK; if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) return SZ_ERROR_NO_ARCHIVE; { int64_t pos = 0; RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); if ((uint64_t)pos < startArcPos + nextHeaderOffset || (uint64_t)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || (uint64_t)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) return SZ_ERROR_INPUT_EOF; } RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) return SZ_ERROR_MEM; res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); if (res == SZ_OK) { res = SZ_ERROR_ARCHIVE; if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) { CSzData sd; uint64_t type; sd.Data = buffer.data; sd.Size = buffer.size; res = SzReadID(&sd, &type); if (res == SZ_OK) { if (type == k7zIdEncodedHeader) { CBuf outBuffer; Buf_Init(&outBuffer); res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); if (res != SZ_OK) Buf_Free(&outBuffer, allocTemp); else { Buf_Free(&buffer, allocTemp); buffer.data = outBuffer.data; buffer.size = outBuffer.size; sd.Data = buffer.data; sd.Size = buffer.size; res = SzReadID(&sd, &type); } } } if (res == SZ_OK) { if (type == k7zIdHeader) res = SzReadHeader(p, &sd, allocMain, allocTemp); else res = SZ_ERROR_UNSUPPORTED; } } } Buf_Free(&buffer, allocTemp); return res; }
char * Var_Subst(const char *str, /* the string in which to substitute */ SymTable *ctxt, /* the context wherein to find variables */ bool undefErr) /* true if undefineds are an error */ { BUFFER buf; /* Buffer for forming things */ static bool errorReported; Buf_Init(&buf, MAKE_BSIZE); errorReported = false; for (;;) { char *val; /* Value to substitute for a variable */ size_t length; /* Length of the variable invocation */ bool doFree; /* Set true if val should be freed */ const char *cp; /* copy uninteresting stuff */ for (cp = str; *str != '\0' && *str != '$'; str++) ; Buf_Addi(&buf, cp, str); if (*str == '\0') break; if (str[1] == '$') { /* A $ may be escaped with another $. */ Buf_AddChar(&buf, '$'); str += 2; continue; } val = Var_Parse(str, ctxt, undefErr, &length, &doFree); /* When we come down here, val should either point to the * value of this variable, suitably modified, or be NULL. * Length should be the total length of the potential * variable invocation (from $ to end character...) */ if (val == var_Error || val == varNoError) { /* If errors are not an issue, skip over the variable * and continue with the substitution. Otherwise, store * the dollar sign and advance str so we continue with * the string... */ if (errorIsOkay) str += length; else if (undefErr) { /* If variable is undefined, complain and * skip the variable name. The complaint * will stop us from doing anything when * the file is parsed. */ if (!errorReported) Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"", length, str); str += length; errorReported = true; } else { Buf_AddChar(&buf, *str); str++; } } else { /* We've now got a variable structure to store in. * But first, advance the string pointer. */ str += length; /* Copy all the characters from the variable value * straight into the new string. */ Buf_AddString(&buf, val); if (doFree) free(val); } } return Buf_Retrieve(&buf); }
void Cbuf_Init( void ) { printf( "Initializing Command Buffer..\n" ); // Create the command buffer_t Buf_Init( &commandbuf, command_data, sizeof( command_data ) ); }
For * For_Eval(const char *line) { const char *ptr = line; const char *wrd; char *sub; const char *endVar; For *arg; unsigned long n; while (ISSPACE(*ptr)) ptr++; /* Parse loop. */ arg = emalloc(sizeof(*arg)); arg->nvars = 0; Lst_Init(&arg->vars); for (;;) { /* Grab the variables. */ for (wrd = ptr; *ptr && !ISSPACE(*ptr); ptr++) continue; if (ptr - wrd == 0) { Parse_Error(PARSE_FATAL, "Syntax error in for"); return 0; } endVar = ptr++; while (ISSPACE(*ptr)) ptr++; /* End of variable list ? */ if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n') break; Lst_AtEnd(&arg->vars, Var_NewLoopVar(wrd, endVar)); arg->nvars++; } if (arg->nvars == 0) { Parse_Error(PARSE_FATAL, "Missing variable in for"); return 0; } /* Make a list with the remaining words. */ sub = Var_Subst(ptr, NULL, false); if (DEBUG(FOR)) { LstNode ln; (void)fprintf(stderr, "For: Iterator "); for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln)) (void)fprintf(stderr, "%s ", Var_LoopVarName(Lst_Datum(ln))); (void)fprintf(stderr, "List %s\n", sub); } Lst_Init(&arg->lst); n = build_words_list(&arg->lst, sub); free(sub); if (arg->nvars != 1 && n % arg->nvars != 0) { LstNode ln; Parse_Error(PARSE_FATAL, "Wrong number of items in for loop"); (void)fprintf(stderr, "%lu items for %d variables:", n, arg->nvars); for (ln = Lst_First(&arg->lst); ln != NULL; ln = Lst_Adv(ln)) { char *p = Lst_Datum(ln); (void)fprintf(stderr, " %s", p); } (void)fprintf(stderr, "\n"); return 0; } arg->lineno = Parse_Getlineno(); arg->level = 1; Buf_Init(&arg->buf, 0); return arg; }
/*- *----------------------------------------------------------------------- * CondGetArg -- * Find the argument of a built-in function. * * Input: * parens TRUE if arg should be bounded by parens * * Results: * The length of the argument and the address of the argument. * * Side Effects: * The pointer is set to point to the closing parenthesis of the * function call. * *----------------------------------------------------------------------- */ static int CondGetArg(char **linePtr, char **argPtr, const char *func) { char *cp; int argLen; Buffer buf; int paren_depth; char ch; cp = *linePtr; if (func != NULL) /* Skip opening '(' - verfied by caller */ cp++; if (*cp == '\0') { /* * No arguments whatsoever. Because 'make' and 'defined' aren't really * "reserved words", we don't print a message. I think this is better * than hitting the user with a warning message every time s/he uses * the word 'make' or 'defined' at the beginning of a symbol... */ *argPtr = NULL; return (0); } while (*cp == ' ' || *cp == '\t') { cp++; } /* * Create a buffer for the argument and start it out at 16 characters * long. Why 16? Why not? */ Buf_Init(&buf, 16); paren_depth = 0; for (;;) { ch = *cp; if (ch == 0 || ch == ' ' || ch == '\t') break; if ((ch == '&' || ch == '|') && paren_depth == 0) break; if (*cp == '$') { /* * Parse the variable spec and install it as part of the argument * if it's valid. We tell Var_Parse to complain on an undefined * variable, so we don't do it too. Nor do we return an error, * though perhaps we should... */ char *cp2; int len; void *freeIt; cp2 = Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES, &len, &freeIt); Buf_AddBytes(&buf, strlen(cp2), cp2); free(freeIt); cp += len; continue; } if (ch == '(') paren_depth++; else if (ch == ')' && --paren_depth < 0) break; Buf_AddByte(&buf, *cp); cp++; } *argPtr = Buf_GetAll(&buf, &argLen); Buf_Destroy(&buf, FALSE); while (*cp == ' ' || *cp == '\t') { cp++; } if (func != NULL && *cp++ != ')') { Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()", func); return (0); } *linePtr = cp; return (argLen); }
/* coverity:[+alloc : arg-*2] */ static char * CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) { Buffer buf; char *cp; char *str; int len; int qt; char *start; Buf_Init(&buf, 0); str = NULL; *freeIt = NULL; *quoted = qt = *condExpr == '"' ? 1 : 0; if (qt) condExpr++; for (start = condExpr; *condExpr && str == NULL; condExpr++) { switch (*condExpr) { case '\\': if (condExpr[1] != '\0') { condExpr++; Buf_AddByte(&buf, *condExpr); } break; case '"': if (qt) { condExpr++; /* we don't want the quotes */ goto got_str; } else Buf_AddByte(&buf, *condExpr); /* likely? */ break; case ')': case '!': case '=': case '>': case '<': case ' ': case '\t': if (!qt) goto got_str; else Buf_AddByte(&buf, *condExpr); break; case '$': /* if we are in quotes, then an undefined variable is ok */ str = Var_Parse(condExpr, VAR_CMD, ((!qt && doEval) ? VARF_UNDEFERR : 0) | VARF_WANTRES, &len, freeIt); if (str == var_Error) { if (*freeIt) { free(*freeIt); *freeIt = NULL; } /* * Even if !doEval, we still report syntax errors, which * is what getting var_Error back with !doEval means. */ str = NULL; goto cleanup; } condExpr += len; /* * If the '$' was first char (no quotes), and we are * followed by space, the operator or end of expression, * we are done. */ if ((condExpr == start + len) && (*condExpr == '\0' || isspace((unsigned char) *condExpr) || strchr("!=><)", *condExpr))) { goto cleanup; } /* * Nope, we better copy str to buf */ for (cp = str; *cp; cp++) { Buf_AddByte(&buf, *cp); } if (*freeIt) { free(*freeIt); *freeIt = NULL; } str = NULL; /* not finished yet */ condExpr--; /* don't skip over next char */ break; default: if (strictLHS && !qt && *start != '$' && !isdigit((unsigned char) *start)) { /* lhs must be quoted, a variable reference or number */ if (*freeIt) { free(*freeIt); *freeIt = NULL; } str = NULL; goto cleanup; } Buf_AddByte(&buf, *condExpr); break; } } got_str: str = Buf_GetAll(&buf, NULL); *freeIt = str; cleanup: Buf_Destroy(&buf, FALSE); return str; }
void Make_DoAllVar(GNode *gn) { GNode *child; LstNode ln; BUFFER allsrc, oodate; char *target; bool do_oodate; int oodate_count, allsrc_count = 0; oodate_count = 0; allsrc_count = 0; for (ln = Lst_First(&gn->children); ln != NULL; ln = Lst_Adv(ln)) { child = (GNode *)Lst_Datum(ln); if ((child->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) != 0) continue; if (OP_NOP(child->type) || (target = Var(TARGET_INDEX, child)) == NULL) { /* * this node is only source; use the specific pathname * for it */ target = child->path != NULL ? child->path : child->name; } /* * It goes in the OODATE variable if the parent is younger than * the child or if the child has been modified more recently * than the start of the make. This is to keep make from * getting confused if something else updates the parent after * the make starts (shouldn't happen, I know, but sometimes it * does). In such a case, if we've updated the kid, the parent * is likely to have a modification time later than that of the * kid and anything that relies on the OODATE variable will be * hosed. */ do_oodate = false; if (gn->type & OP_JOIN) { if (child->built_status == MADE) do_oodate = true; } else if (is_strictly_before(gn->mtime, child->mtime) || (!is_strictly_before(child->mtime, now) && child->built_status == MADE)) do_oodate = true; if (do_oodate) { oodate_count++; if (oodate_count == 1) Var(OODATE_INDEX, gn) = target; else { if (oodate_count == 2) { Buf_Init(&oodate, 0); Buf_AddString(&oodate, Var(OODATE_INDEX, gn)); } Buf_AddSpace(&oodate); Buf_AddString(&oodate, target); } } allsrc_count++; if (allsrc_count == 1) Var(ALLSRC_INDEX, gn) = target; else { if (allsrc_count == 2) { Buf_Init(&allsrc, 0); Buf_AddString(&allsrc, Var(ALLSRC_INDEX, gn)); } Buf_AddSpace(&allsrc); Buf_AddString(&allsrc, target); } } if (allsrc_count > 1) Var(ALLSRC_INDEX, gn) = Buf_Retrieve(&allsrc); if (oodate_count > 1) Var(OODATE_INDEX, gn) = Buf_Retrieve(&oodate); if (gn->impliedsrc) Var(IMPSRC_INDEX, gn) = Var(TARGET_INDEX, gn->impliedsrc); if (gn->type & OP_JOIN) Var(TARGET_INDEX, gn) = Var(ALLSRC_INDEX, gn); }
void SzCoderInfo_Init(CSzCoderInfo *p) { Buf_Init(&p->Props); }
static Token CondHandleComparison(char *lhs, bool doFree, bool doEval) { Token t; const char *rhs; const char *op; t = Err; /* Skip whitespace to get to the operator. */ while (isspace(*condExpr)) condExpr++; /* Make sure the operator is a valid one. If it isn't a * known relational operator, pretend we got a * != 0 comparison. */ op = condExpr; switch (*condExpr) { case '!': case '=': case '<': case '>': if (condExpr[1] == '=') condExpr += 2; else condExpr += 1; break; default: op = "!="; rhs = "0"; goto do_compare; } while (isspace(*condExpr)) condExpr++; if (*condExpr == '\0') { Parse_Error(PARSE_WARNING, "Missing right-hand-side of operator"); goto error; } rhs = condExpr; do_compare: if (*rhs == '"') { /* Doing a string comparison. Only allow == and != for * operators. */ char *string; const char *cp; int qt; BUFFER buf; do_string_compare: if ((*op != '!' && *op != '=') || op[1] != '=') { Parse_Error(PARSE_WARNING, "String comparison operator should be either == or !="); goto error; } Buf_Init(&buf, 0); qt = *rhs == '"' ? 1 : 0; for (cp = &rhs[qt]; ((qt && *cp != '"') || (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) { if (*cp == '$') { size_t len; if (Var_ParseBuffer(&buf, cp, NULL, doEval, &len)) { cp += len; continue; } } else if (*cp == '\\' && cp[1] != '\0') /* Backslash escapes things -- skip over next * character, if it exists. */ cp++; Buf_AddChar(&buf, *cp++); } string = Buf_Retrieve(&buf); if (DEBUG(COND)) printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", lhs, string, op); /* Null-terminate rhs and perform the comparison. * t is set to the result. */ if (*op == '=') t = strcmp(lhs, string) ? False : True; else t = strcmp(lhs, string) ? True : False; free(string); if (rhs == condExpr) { if (!qt && *cp == ')') condExpr = cp; else if (*cp == '\0') condExpr = cp; else condExpr = cp + 1; } } else { /* rhs is either a float or an integer. Convert both the * lhs and the rhs to a double and compare the two. */ double left, right; char *string; if (!CondCvtArg(lhs, &left)) goto do_string_compare; if (*rhs == '$') { size_t len; bool freeIt; string = Var_Parse(rhs, NULL, doEval,&len,&freeIt); if (string == var_Error) right = 0.0; else { if (!CondCvtArg(string, &right)) { if (freeIt) free(string); goto do_string_compare; } if (freeIt) free(string); if (rhs == condExpr) condExpr += len; } } else { if (!CondCvtArg(rhs, &right)) goto do_string_compare; if (rhs == condExpr) { /* Skip over the right-hand side. */ while (!isspace(*condExpr) && *condExpr != '\0') condExpr++; } } if (DEBUG(COND)) printf("left = %f, right = %f, op = %.2s\n", left, right, op); switch (op[0]) { case '!': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto error; } t = left != right ? True : False; break; case '=': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto error; } t = left == right ? True : False; break; case '<': if (op[1] == '=') t = left <= right ? True : False; else t = left < right ? True : False; break; case '>': if (op[1] == '=') t = left >= right ? True : False; else t = left > right ? True : False; break; } } error: if (doFree) free(lhs); return t; }