/** * virConfParseString: * @ctxt: the parsing context * * Parse one string * * Returns a pointer to the string or NULL in case of error */ static char * virConfParseString(virConfParserCtxtPtr ctxt) { const char *base; char *ret = NULL; if (CUR == '\'') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR))) NEXT; if (CUR != '\'') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } else if ((ctxt->cur + 6 < ctxt->end) && (STRPREFIX(ctxt->cur, "\"\"\""))) { /* String starts with python-style triple quotes """ */ ctxt->cur += 3; base = ctxt->cur; /* Find the ending triple quotes */ while ((ctxt->cur + 2 < ctxt->end) && !(STRPREFIX(ctxt->cur, "\"\"\""))) { if (CUR == '\n') ctxt->line++; NEXT; } if (!STRPREFIX(ctxt->cur, "\"\"\"")) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; ctxt->cur += 3; } else if (CUR == '"') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR))) NEXT; if (CUR != '"') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } return ret; }
/** * virConfParseStatement: * @ctxt: the parsing context * * Parse one statement in the conf file * * Returns 0 in case of success and -1 in case of error */ static int virConfParseStatement(virConfParserCtxtPtr ctxt) { const char *base; char *name; virConfValuePtr value; char *comm = NULL; SKIP_BLANKS_AND_EOL; if (CUR == '#') { return virConfParseComment(ctxt); } name = virConfParseName(ctxt); if (name == NULL) return -1; SKIP_BLANKS; if (CUR != '=') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment")); VIR_FREE(name); return -1; } NEXT; SKIP_BLANKS; value = virConfParseValue(ctxt); if (value == NULL) { VIR_FREE(name); return -1; } SKIP_BLANKS; if (CUR == '#') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; comm = strndup(base, ctxt->cur - base); if (comm == NULL) { virReportOOMError(); VIR_FREE(name); virConfFreeValue(value); return -1; } } if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) { VIR_FREE(name); virConfFreeValue(value); VIR_FREE(comm); return -1; } return 0; }
/** * virConfParseSeparator: * @ctxt: the parsing context * * Parse one separator between statement if not at the end. * * Returns 0 in case of success and -1 in case of error */ static int virConfParseSeparator(virConfParserCtxtPtr ctxt) { SKIP_BLANKS; if (ctxt->cur >= ctxt->end) return 0; if (IS_EOL(CUR)) { SKIP_BLANKS_AND_EOL; } else if (CUR == ';') { NEXT; SKIP_BLANKS_AND_EOL; } else { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator")); return -1; } return 0; }
/** * virConfParseComment: * @ctxt: the parsing context * * Parse one standalone comment in the configuration file * * Returns 0 in case of success and -1 in case of error */ static int virConfParseComment(virConfParserCtxtPtr ctxt) { const char *base; char *comm; if (CUR != '#') return -1; NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; if (VIR_STRNDUP(comm, base, ctxt->cur - base) < 0) return -1; if (virConfAddEntry(ctxt->conf, NULL, NULL, comm) == NULL) { VIR_FREE(comm); return -1; } return 0; }
/** * virConfParseComment: * @ctxt: the parsing context * * Parse one standalone comment in the configuration file * * Returns 0 in case of success and -1 in case of error */ static int virConfParseComment(virConfParserCtxtPtr ctxt) { const char *base; char *comm; if (CUR != '#') return -1; NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; comm = strndup(base, ctxt->cur - base); if (comm == NULL) { virReportOOMError(); return -1; } virConfAddEntry(ctxt->conf, NULL, NULL, comm); return 0; }
/** * utils_handle_output: * @output: buffer containing vpnc output * @server_message: buffer in which to store a message from the VPN server * @server_message_done: flag which is set to %TRUE when a server message is * complete * @prompt_fn: function to call when vpnc (or the server) sends a request for * passwords or more information * @prompt_fn_data: pointer to pass to @prompt_fn * * Parses new vpnc output to extract server messages and detect prompts for * more information. Since vpnc can print variable numbers of bytes at a time, * not necessarily a complete line or block, this function should be called * multiple times on the same buffer. It will return the number of bytes which * it consumed, and that number of bytes should be removed from the start of * @output. If a request for a password or username is parsed, it will call * @prompt_fn with the prompt message. * * Returns: the number of bytes consumed, which should be removed from the * start of @output. **/ gsize utils_handle_output (GString *output, GString *server_message, gboolean *server_message_done, PromptFn prompt_fn, gpointer prompt_fn_data) { guint32 i; g_return_val_if_fail (output != NULL, 0); g_return_val_if_fail (server_message != NULL, 0); g_return_val_if_fail (server_message_done != NULL, 0); g_return_val_if_fail (prompt_fn != NULL, 0); /* vpnc output is loosely formatted, with "blocks of interest" starting with * no leading whitespace, and separated by double newlines, but unfortunately * it doesn't output both newlines at the same time (one newline is printed * at the end of one block and a second at the start of the next block with * variable time in between) and some input prompts don't print newlines at * all. * * S5.4 xauth type check * [2011-06-03 11:11:13] * * Wait for token to change, (server message line #1) * then enter the new tokencode: (server message line #2) * * S5.5 do xauth authentication * [2011-06-03 11:11:13] * Password for VPN [email protected]: (waits for input without newline) * size = 42, blksz = 16, padding = 6 * * So we can't just listen for '\n\n' or we won't react immediately to * input prompts or correctly process service messages. * * Instead we pay attention to any lines that have no leading whitespace * and do not start with "S[1 - 9]". If the line ends with ":" it is an * input prompt. If it doesn't then we cache it and wait for the next line * or newline, in which case it's a server message. */ if (output->len == 0) return 0; /* Find the end of the line or the end of the string; all lines *except* * prompts will be newline terminated, while prompts stop at the end of the * buffer because vpnc is waiting for the input. */ for (i = 0; i < output->len; i++) { if (!output->str[i] || IS_EOL (output->str[i])) break; } /* Decide whether to stop parsing a server message, which is terminated by * a single empty line or some whitespace; it looks like: * * <stuff> * * Wait for token to change, * then enter the new tokencode: * * <more stuff> */ if (server_message->len) { if (g_ascii_isspace (output->str[0]) || IS_EOL (output->str[0])) *server_message_done = TRUE; } if (i < output->len) { /* Lines starting with whitespace are debug output that we don't care * about. */ if (g_ascii_isspace (output->str[0])) return i + 1; } else if (i == output->len) { /* Check for a prompt; it will not begin with whitespace, and will end * with a ':' and no newline, because vpnc will be waiting for the response. */ if (!g_ascii_isspace (output->str[0]) && (i > 2) && (strncmp ((output->str + (i - 2)), ": ", 2) == 0)) { /* Note: if vpnc sent a server message ending with ':' but we * happened to only read up to the ':' but not the EOL, we'll * confuse the server message with an input prompt. vpnc is not * helpful here. */ prompt_fn (output->str, i, prompt_fn_data); return i; } /* No newline and no ending semicolon; probably a partial read so wait * for more output */ return 0; } else g_assert_not_reached (); /* No newline at the end, wait for one */ if (!IS_EOL (output->str[i])) return 0; /* Ignore vpnc version debug output */ if (i >= strlen (VPNC_VERSION_STR) && strncmp (output->str, VPNC_VERSION_STR, strlen (VPNC_VERSION_STR)) == 0) return i + 1; /* Ignore vpnc debug messages like "S1 init_sockaddr" */ if (i > 2 && output->str[0] == 'S' && g_ascii_isdigit (output->str[1])) return i + 1; /* What's left is probably a server message */ if (*server_message_done) { g_string_truncate (server_message, 0); *server_message_done = FALSE; } g_string_append_len (server_message, output->str, i + 1); return i + 1; }
int AmConfigReader::loadFile(const string& path) { FILE* fp = fopen(path.c_str(),"r"); if(!fp){ WARN("could not open configuration file '%s': %s\n", path.c_str(),strerror(errno)); return -1; } int lc = 0; int ls = 0; char lb[MAX_CONFIG_LINE] = {'\0'}; char *c,*key_beg,*key_end,*val_beg,*val_end,*inc_beg,*inc_end; c=key_beg=key_end=val_beg=val_end=inc_beg=inc_end=0; while(!feof(fp) && ((ls = fifo_get_line(fp, lb, MAX_CONFIG_LINE)) != -1)){ c=key_beg=key_end=val_beg=val_end=0; lc++; c = lb; TRIM(c); if(IS_EOL(*c)) continue; if (*c == '@') { /* process included config file */ c++; TRIM(c); inc_beg = c++; while( !IS_EOL(*c) && !IS_SPACE(*c) ) c++; inc_end = c; string fname = string(inc_beg,inc_end-inc_beg); if (fname.length() && fname[0] != '/') fname = AmConfig::ModConfigPath + fname; if(loadFile(fname)) goto error; continue; } key_beg = c; while( (*c != '=') && !IS_SPACE(*c) ) c++; key_end = c; if(IS_SPACE(*c)) TRIM(c); else if( !(c - key_beg) ) goto syntax_error; if(*c != '=') goto syntax_error; c++; TRIM(c); if(*c == '"'){ char last_c = ' '; val_beg = ++c; while( ((*c != '"') || (last_c == '\\')) && (*c != '\0') ) { last_c = *c; c++; } if(*c == '\0') goto syntax_error; val_end = c; } else { val_beg = c; while( !IS_EOL(*c) && !IS_SPACE(*c) ) c++; val_end = c; } if((key_beg < key_end) && (val_beg <= val_end)) { string keyname = string(key_beg,key_end-key_beg); string val = string(val_beg,val_end-val_beg); if (hasParameter(keyname)) { WARN("while loading '%s': overwriting configuration " "'%s' value '%s' with '%s'\n", path.c_str(), keyname.c_str(), getParameter(keyname).c_str(), val.c_str()); } keys[keyname] = val; // small hack to make include work with right path if (keyname == "plugin_config_path") AmConfig::ModConfigPath = val; } else goto syntax_error; } fclose(fp); return 0; syntax_error: ERROR("syntax error line %i in %s\n",lc,path.c_str()); error: fclose(fp); return -1; }
int AmConfigReader::loadString(const char* cfg_lines, size_t cfg_len) { int lc = 0; int ls = 0; char lb[MAX_CONFIG_LINE] = {'\0'}; char *c,*key_beg,*key_end,*val_beg,*val_end,*inc_beg,*inc_end; const char* cursor = cfg_lines; const char* cfg_end = cursor + cfg_len; c=key_beg=key_end=val_beg=val_end=inc_beg=inc_end=0; while((cursor < cfg_end) && ((ls = str_get_line(&cursor, cfg_end, lb, MAX_CONFIG_LINE)) != -1)){ c=key_beg=key_end=val_beg=val_end=0; lc++; c = lb; TRIM(c); if(IS_EOL(*c)) continue; key_beg = c; while( (*c != '=') && !IS_SPACE(*c) ) c++; key_end = c; if(IS_SPACE(*c)) TRIM(c); else if( !(c - key_beg) ) goto syntax_error; if(*c != '=') goto syntax_error; c++; TRIM(c); if(*c == '"'){ char last_c = ' '; val_beg = ++c; while( ((*c != '"') || (last_c == '\\')) && (*c != '\0') ) { last_c = *c; c++; } if(*c == '\0') goto syntax_error; val_end = c; } else { val_beg = c; while( !IS_EOL(*c) && !IS_SPACE(*c) ) c++; val_end = c; } if((key_beg < key_end) && (val_beg <= val_end)) { string keyname = string(key_beg,key_end-key_beg); string val = string(val_beg,val_end-val_beg); if (hasParameter(keyname)) { WARN("while loading string: overwriting configuration " "'%s' value '%s' with '%s'\n", keyname.c_str(), getParameter(keyname).c_str(), val.c_str()); } keys[keyname] = val; } else goto syntax_error; } return 0; syntax_error: ERROR("syntax error line %i\n",lc); return -1; }
/** * virConfParseString: * @ctxt: the parsing context * * Parse one string * * Returns a pointer to the string or NULL in case of error */ static char * virConfParseString(virConfParserCtxtPtr ctxt) { const char *base; char *ret = NULL; if (CUR == '\'') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR))) NEXT; if (CUR != '\'') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } else if ((ctxt->cur + 6 < ctxt->end) && (STRPREFIX(ctxt->cur, "\"\"\""))) { /* String starts with python-style triple quotes """ */ ctxt->cur += 3; base = ctxt->cur; /* Find the ending triple quotes */ while ((ctxt->cur + 2 < ctxt->end) && !(STRPREFIX(ctxt->cur, "\"\"\""))) { if (CUR == '\n') ctxt->line++; NEXT; } if (!STRPREFIX(ctxt->cur, "\"\"\"")) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; ctxt->cur += 3; } else if (CUR == '"') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR))) NEXT; if (CUR != '"') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } else if (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) { base = ctxt->cur; /* LXC config format doesn't support comments after the value */ while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; /* Reverse to exclude the trailing blanks from the value */ while ((ctxt->cur > base) && (c_isblank(CUR))) ctxt->cur--; if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; } return ret; }
int main(int argc, char *argv[]) { char *uncompressed = (char *)malloc(128 * 1024); char *compressed; char *trace = uncompressed; int i; int compressedSize; int uncompressedSize; char *src, *dst; FILE *f; time_t currentTimeT; struct tm *currentTime; char cleverTime[32]; time(¤tTimeT); currentTime = localtime(¤tTimeT); strftime(cleverTime, sizeof(cleverTime), "%Y/%m/%d %H:%M:%S", currentTime); *trace++ = ' '; for (i = 1; i < argc; i++) { int size; /* ** This ensures there's always whitespace space between files. It *also* ** ensures that src[-1] is always safe in comment detection code below. ** (Any leading whitespace will be thrown away in a later pass.) ** --lch */ *trace++ = ' '; f = fopen(argv[i], "rb"); fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); fread(trace, 1, size, f); fclose(f); trace += size; } *trace = 0; #define IS_EOL(x) ((*x == '\n') || (*x == '\r')) #define IS_EOL_COMMENT(x) (((x[0] == '\\') && isspace(x[1])) || ((x[0] == '/') && (x[1] == '/') && isspace(x[2]))) #define IS_BLOCK_COMMENT(x) ((x[0] == '(') && isspace(x[1]) && isspace(x[-1])) src = dst = uncompressed; while (*src) { /* ignore leading whitespace, or entirely blank lines */ while (isspace(*src)) src++; /* if the line is commented out */ if (IS_EOL_COMMENT(src)) { /* throw away this entire line */ while (*src && !IS_EOL(src)) src++; continue; } /* ** This is where we'd throw away mid-line comments, but ** that's simply unsafe. Things like ** start-prefixes ** : \ postpone \ ; ** : ( postpone ( ; ** get broken that way. ** --lch */ while (*src && !IS_EOL(src)) { *dst++ = *src++; } /* strip trailing whitespace */ dst--; while (isspace(*dst)) dst--; dst++; /* and end the line */ *dst++ = '\n'; } *dst = 0; /* now make a second pass to collapse all contiguous whitespace to a single space. */ src = dst = uncompressed; while (*src) { *dst++ = *src; if (!isspace(*src)) src++; else { while (isspace(*src)) src++; } } *dst = 0; f = fopen("../softcore.c", "wt"); if (f == NULL) { printf("couldn't open ../softcore.c for writing! giving up.\n"); exit(-1); } fprintf(f, "/*\n" "** Ficl softcore\n" "** both uncompressed and Lempel-Ziv compressed versions.\n" "**\n" "** Generated %s\n" "**/\n" "\n" "#include \"ficl.h\"\n" "\n" "\n", cleverTime); uncompressedSize = dst - uncompressed; ficlLzCompress(uncompressed, uncompressedSize, &compressed, &compressedSize); fprintf(f, "static size_t ficlSoftcoreUncompressedSize = %d; /* not including trailing null */\n", uncompressedSize); fprintf(f, "\n"); fprintf(f, "#if !FICL_WANT_LZ_SOFTCORE\n"); fprintf(f, "\n"); fprintf(f, "static char ficlSoftcoreUncompressed[] =\n"); fprintDataAsQuotedString(f, uncompressed); fprintf(f, ";\n"); fprintf(f, "\n"); fprintf(f, "#else /* !FICL_WANT_LZ_SOFTCORE */\n"); fprintf(f, "\n"); fprintf(f, "static unsigned char ficlSoftcoreCompressed[%d] = {\n", compressedSize); fprintDataAsHex(f, compressed, compressedSize); fprintf(f, "\t};\n"); fprintf(f, "\n"); fprintf(f, "#endif /* !FICL_WANT_LZ_SOFTCORE */\n"); fprintf(f, "\n" "\n" "void ficlSystemCompileSoftCore(ficlSystem *system)\n" "{\n" " ficlVm *vm = system->vmList;\n" " int returnValue;\n" " ficlCell oldSourceID = vm->sourceId;\n" " ficlString s;\n" "#if FICL_WANT_LZ_SOFTCORE\n" " char *ficlSoftcoreUncompressed = NULL;\n" " size_t gotUncompressedSize = 0;\n" " returnValue = ficlLzUncompress(ficlSoftcoreCompressed, (unsigned char **)&ficlSoftcoreUncompressed, &gotUncompressedSize);\n" " FICL_VM_ASSERT(vm, returnValue == 0);\n" " FICL_VM_ASSERT(vm, gotUncompressedSize == ficlSoftcoreUncompressedSize);\n" "#endif /* FICL_WANT_LZ_SOFTCORE */\n" " vm->sourceId.i = -1;\n" " FICL_STRING_SET_POINTER(s, (char *)(ficlSoftcoreUncompressed));\n" " FICL_STRING_SET_LENGTH(s, ficlSoftcoreUncompressedSize);\n" " returnValue = ficlVmExecuteString(vm, s);\n" " vm->sourceId = oldSourceID;\n" "#if FICL_WANT_LZ_SOFTCORE\n" " free(ficlSoftcoreUncompressed);\n" "#endif /* FICL_WANT_LZ_SOFTCORE */\n" " FICL_VM_ASSERT(vm, returnValue != FICL_VM_STATUS_ERROR_EXIT);\n" " return;\n" "}\n" "\n" "/* end-of-file */\n" ); free(uncompressed); free(compressed); return 0; }
std::string read_user_format_number(std::ifstream &ifs, UserFormatColumn<DATA_T> &ufc, std::string &line, bool &need_readline, encode_result &encres, char* argv[] = 0) { std::string ret, fm_buffer; DATA_T val = 0; char* c; ret.clear(); while (std::getline(ifs, line)) { encres.line_nr++; encres.line_in_blk++; c = const_cast<char*>(line.c_str()); fm_buffer.clear(); if (IS_COMMENT(line)) continue; /* end of FORMATs of a user block */ if (IS_BLANK(line)) { need_readline = false; break; } while (!IS_EOL(*c) && !IS_EOS(*c)) { /* Meeting the next FORMAT, which means this format is done */ if (IS_LETTER(*c)) { need_readline = false; break; } else if (IS_PLACEHOLD(*c)) { if (!TEMPLATE_MODE) throw E2promValueException("Placehold should be used in template file", to_string<int>(encres.line_nr), usage_allowed_user_format_type); E2promMsg("Reading parameter for user "+to_string<uint16_t>(ufc.uheader.ID)+ " @ line "+to_string<int>(encres.line_nr)); read_user_parameters(fm_buffer, ufc.uheader.ID, encres, argv); break; } else if (IS_DIGIT(*c) || IS_PERIOD(*c)) { fm_buffer += *c++; } else if (IS_SPACE(*c) || (IS_COMMENT_SIGN(*c))) { break; } else { throw E2promValueException( "Unexpected characters found for type", to_string<int>(encres.line_nr), usage_allowed_user_format_type ); } } /* end of read-char while-loop */ // if (TEMPLATE_MODE) // process_fm_buffer(fm_buffer, ufc.uheader.ID); if (!fm_buffer.empty()) { val = to_digits<DATA_T>(fm_buffer); ufc += val; } if (!IS_LETTER(*c) && !IS_BLANK(line)) { need_readline = true; } else { break; } } /* end of read-line while-loop */ // ret += strize_formats<DATA_T>(ufc); std::stringstream ss; // ss.width(decres.GLOBAL_ALIGNMENT); ss << ufc; return ss.str(); }
int cfg_get_token(cfg_token_t* token, cfg_parser_t* st, unsigned int flags) { static int look_ahead = EOF; int c; enum st state; state = ST_S; token->val.s = token->buf; token->val.len = 0; if (look_ahead != EOF) { c = look_ahead; look_ahead = EOF; } else { READ_CHAR; } while(c != EOF) { switch(state) { case ST_S: if (flags & CFG_EXTENDED_ALPHA) { if (IS_WHITESPACE(c)) { /* Do nothing */ } else if (IS_ALPHA(c) || IS_ESCAPE(c) || IS_DELIM(c)) { PUSH(c); state = ST_A; } else if (IS_QUOTE(c)) { state = ST_Q; } else if (IS_COMMENT(c)) { state = ST_C; } else if (IS_EOL(c)) { PUSH(c); RETURN(c); } else { ERR("%s:%d:%d: Invalid character 0x%x\n", st->file, st->line, st->col, c); return -1; } } else { if (IS_WHITESPACE(c)) { /* Do nothing */ } else if (IS_ALPHA(c)) { PUSH(c); state = ST_A; } else if (IS_QUOTE(c)) { state = ST_Q; } else if (IS_COMMENT(c)) { state = ST_C; } else if (IS_ESCAPE(c)) { state = ST_E; } else if (IS_DELIM(c) || IS_EOL(c)) { PUSH(c); RETURN(c); } else { ERR("%s:%d:%d: Invalid character 0x%x\n", st->file, st->line, st->col, c); return -1; } } break; case ST_A: if (flags & CFG_EXTENDED_ALPHA) { if (IS_ALPHA(c) || IS_DELIM(c) || IS_QUOTE(c)) { PUSH(c); } else if (IS_ESCAPE(c)) { state = ST_AE; } else if (IS_COMMENT(c) || IS_EOL(c) || IS_WHITESPACE(c)) { look_ahead = c; RETURN(CFG_TOKEN_ALPHA); } else { ERR("%s:%d:%d: Invalid character 0x%x\n", st->file, st->line, st->col, c); return -1; } } else { if (IS_ALPHA(c)) { PUSH(c); } else if (IS_ESCAPE(c)) { state = ST_AE; } else if (IS_WHITESPACE(c) || IS_DELIM(c) || IS_QUOTE(c) || IS_COMMENT(c) || IS_EOL(c)) { look_ahead = c; RETURN(CFG_TOKEN_ALPHA); } else { ERR("%s:%d:%d: Invalid character 0x%x\n", st->file, st->line, st->col, c); return -1; } } break; case ST_AE: if (IS_COMMENT(c) || IS_QUOTE(c) || IS_ESCAPE(c)) { PUSH(c); } else if (c == 'r') { PUSH('\r'); } else if (c == 'n') { PUSH('\n'); } else if (c == 't') { PUSH('\t'); } else if (c == ' ') { PUSH(' '); } else if (IS_EOL(c)) { /* Do nothing */ } else { ERR("%s:%d:%d: Unsupported escape character 0x%x\n", st->file, st->line, st->col, c); return -1; } state = ST_A; break; case ST_Q: if (IS_QUOTE(c)) { RETURN(CFG_TOKEN_STRING); } else if (IS_ESCAPE(c)) { state = ST_QE; break; } else { PUSH(c); } break; case ST_QE: if (IS_ESCAPE(c) || IS_QUOTE(c)) { PUSH(c); } else if (c == 'n') { PUSH('\n'); } else if (c == 'r') { PUSH('\r'); } else if (c == 't') { PUSH('\t'); } else if (IS_EOL(c)) { /* Do nothing */ } else { ERR("%s:%d:%d: Unsupported escape character 0x%x\n", st->file, st->line, st->col, c); return -1; } state = ST_Q; break; case ST_C: if (IS_ESCAPE(c)) { state = ST_CE; } else if (IS_EOL(c)) { state = ST_S; continue; /* Do not read a new char, return EOL */ } else { /* Do nothing */ } break; case ST_CE: state = ST_C; break; case ST_E: if (IS_COMMENT(c) || IS_QUOTE(c) || IS_ESCAPE(c)) { PUSH(c); RETURN(c); } else if (c == 'r') { PUSH('\r'); RETURN('\r'); } else if (c == 'n') { PUSH('\n'); RETURN('\n'); } else if (c == 't') { PUSH('\t'); RETURN('\t'); } else if (c == ' ') { PUSH(' '); RETURN(' '); } else if (IS_EOL(c)) { /* Escped eol means no eol */ state = ST_S; } else { ERR("%s:%d:%d: Unsupported escape character 0x%x\n", st->file, st->line, st->col, c); return -1; } break; } READ_CHAR; }; switch(state) { case ST_S: case ST_C: case ST_CE: return 1; case ST_A: RETURN(CFG_TOKEN_ALPHA); case ST_Q: ERR("%s:%d:%d: Premature end of file, missing closing quote in" " string constant\n", st->file, st->line, st->col); return -1; case ST_QE: case ST_E: case ST_AE: ERR("%s:%d:%d: Premature end of file, missing escaped character\n", st->file, st->line, st->col); return -1; } BUG("%s:%d:%d: Invalid state %d\n", st->file, st->line, st->col, state); return -1; }
const char* skip_tochar(const char *p, char end) { while (!IS_EOL(p) && (*p != end)) p++; return p; }
const char* skip_toeol(const char* p) { while (*p && !IS_EOL(p)) p++; return p; } // Skip to end of line
const char* skip_token(const char* p) { while (*p && !IS_EOL(p) && !IS_SPACE(p) && (*p != '=')) p++; return p; } // Skip past current token value
static int add_to_variable_list(char *text_line, FORMAT_PTR format) { VARIABLE_PTR var = NULL; char save_char = STR_END; char *token = NULL; char *endptr = NULL; int error = 0; if (!format->variables) { format->variables = dll_init(); if (!format->variables) return(ERR_MEM_LACK); } token = text_line; token = get_token(token, &save_char); if (FF_STRLEN(token)) { var = ff_create_variable(token); if (var == NULL) return ERR_MEM_LACK; #if 0 error = ERR_MEM_LACK; #endif if (var->name[0] == '"' && var->name[strlen(var->name) - 1] == '"') { memmove(var->name, var->name + 1, strlen(var->name) - 2); var->name[strlen(var->name) - 2] = STR_END; } } else { error = err_push(ERR_VARIABLE_DESC, "Expecting a variable name (\"%s\")", format->name); goto add_to_variable_list_exit; } if (!dll_add(format->variables)) { ff_destroy_variable(var); error = ERR_MEM_LACK; goto add_to_variable_list_exit; } dll_assign(var, DLL_VAR, dll_last(format->variables)); token = get_token(token, &save_char); if (FF_STRLEN(token)) { errno = 0; var->start_pos = strtol(token, &endptr, 10); if (errno || FF_STRLEN(endptr)) { error = err_push(errno ? errno : ERR_PARAM_VALUE, "Bad number for variable start position: %s", token); goto add_to_variable_list_exit; } } else { error = err_push(ERR_VARIABLE_DESC, "Expecting a start position for \"%s\"", var->name); goto add_to_variable_list_exit; } token = get_token(token, &save_char); if (FF_STRLEN(token)) { errno = 0; var->end_pos = strtol(token, &endptr, 10); if (errno || FF_STRLEN(endptr)) { error = err_push(errno ? errno : ERR_PARAM_VALUE, "Bad number for variable end position: %s", token); goto add_to_variable_list_exit; } } else { error = err_push(ERR_VARIABLE_DESC, "Expecting an end position for \"%s\"", var->name); goto add_to_variable_list_exit; } token = get_token(token, &save_char); if (FF_STRLEN(token)) { FFV_TYPE(var) = ff_lookup_number(variable_types, token); if (FFV_TYPE(var) == FF_VAR_TYPE_FLAG) { if (os_strncmpi("ARRAY", token, 5) == 0) { RESTORE_CHAR(token, save_char); save_char = STR_END; error = parse_array_variable(&token, var); if (error) goto add_to_variable_list_exit; format->type |= FF_ARRAY; } else { /* Is this a keyworded variable type? If so, remember name of keyword in record_title */ if (IS_KEYWORDED_PARAMETER(token)) { FFV_TYPE(var) = 0; assert(!var->record_title); if (var->record_title) memFree(var->record_title, "var->record_title"); var->record_title = (char *)memStrdup(token, "token"); if (!var->record_title) { error = err_push(ERR_MEM_LACK, ""); goto add_to_variable_list_exit; } } else { error = err_push(ERR_UNKNOWN_VAR_TYPE, token); goto add_to_variable_list_exit; } } } } else { error = err_push(ERR_VARIABLE_DESC, "Expecting a variable type or array description for \"%s\"", var->name); goto add_to_variable_list_exit; } token = get_token(token, &save_char); if (FF_STRLEN(token)) { errno = 0; var->precision = (short)strtol(token, &endptr, 10); if (errno || FF_STRLEN(endptr)) { error = err_push(errno ? errno : ERR_PARAM_VALUE, "Bad number for variable precision: %s", token); goto add_to_variable_list_exit; } } else { if (IS_ARRAY(var)) { error = err_push(ERR_VARIABLE_DESC, "Expecting a precision for \"%s\"", var->name); goto add_to_variable_list_exit; } } if (var->end_pos < var->start_pos) { error = err_push(ERR_VARIABLE_DESC,"End Position < Start Position\n%s", text_line); goto add_to_variable_list_exit; } /* Determine The Variable Type */ if (var->start_pos == 0 && var->end_pos == 0) { if (IS_BINARY(format)) { error = err_push(ERR_UNKNOWN_FORMAT_TYPE, "Illegal to have delimited binary format"); goto add_to_variable_list_exit; } else if (IS_ARRAY(format)) { error = err_push(ERR_UNKNOWN_FORMAT_TYPE, "Illegal to have delimited array format"); goto add_to_variable_list_exit; } format->type |= FFF_VARIED; } if (NEED_TO_CHECK_VARIABLE_SIZE(format, var)) { if (ffv_type_size(var->type) != var->end_pos - var->start_pos + 1) { char save_eol_char = STR_END; char *end_of_line = find_EOL(text_line); if (end_of_line) { save_eol_char = *end_of_line; *end_of_line = STR_END; } error = err_push(ERR_VARIABLE_SIZE,"Expecting ending position for binary field %s to be %d", var->name, var->start_pos + ffv_type_size(var->type) - 1); if (end_of_line) *end_of_line = save_eol_char; goto add_to_variable_list_exit; } } check_old_style_EOL_var(var); /* Does length of CONSTANT variable name equal length of variable? */ if (IS_CONSTANT(var) && !IS_EOL(var)) { if (FF_STRLEN(var->name) > FF_VAR_LENGTH(var)) { error = err_push(ERR_VARIABLE_SIZE, "Constant variable initializer (%s) is too long for field", var->name); goto add_to_variable_list_exit; } else if (FF_STRLEN(var->name) < FF_VAR_LENGTH(var)) error = err_push(ERR_WARNING_ONLY + ERR_VARIABLE_SIZE, "Constant variable initializer (%s) is shorter than field", var->name); } format->num_vars++; format->length = max(format->length, var->end_pos); add_to_variable_list_exit: if (error) { char *cp; char EOL_char = STR_END; /* Don't destroy variable since it will be destroyed in ff_destroy_format */ cp = find_EOL(text_line); if (cp) { EOL_char = *cp; *cp = STR_END; } error = err_push(ERR_VARIABLE_DESC + (error > ERR_WARNING_ONLY ? ERR_WARNING_ONLY : 0),text_line); if (cp) *cp = EOL_char; } RESTORE_CHAR(token, save_char); return(error); }