diff options
Diffstat (limited to 'src/miav_config.cc')
-rw-r--r-- | src/miav_config.cc | 489 |
1 files changed, 364 insertions, 125 deletions
diff --git a/src/miav_config.cc b/src/miav_config.cc index f7d56ce..f59b6b3 100644 --- a/src/miav_config.cc +++ b/src/miav_config.cc @@ -31,6 +31,10 @@ /* * $Log$ + * Revision 1.11 2005/07/02 11:39:51 deva + * Added some audiocode. + * Moved libfame code out of mov_encoder + * * Revision 1.10 2005/06/14 12:29:40 deva * Incorporated the use of the Info object everywhere... also using the log functionality. * @@ -65,7 +69,7 @@ MiavConfig::MiavConfig(char *file, Info *i) return; } fseek(fp, 0, SEEK_END); - int fsz = ftell(fp); + int fsz = ftell(fp) + 1; fseek(fp, 0, SEEK_SET); char *raw = (char*)calloc(fsz, 1); @@ -73,7 +77,8 @@ MiavConfig::MiavConfig(char *file, Info *i) fclose(fp); - parse(raw); + configs = parse(raw); + free(raw); } @@ -93,173 +98,384 @@ MiavConfig::~MiavConfig() /** * Prints a reasonable error message when a parse error occurres. */ -_cfg *MiavConfig::parseError(char* msg, char* line) +void MiavConfig::parseError(char* msg, _cfg* cfg) { - if(info) info->error("Error parsing file %s at line:\n\t%s\n\t%s\n", filename.c_str(), line, msg); - else fprintf(stderr, "Error parsing file %s at line:\n\t%s\n\t%s\n", filename.c_str(), line, msg); - return NULL; + if(info) info->error("Error parsing file %s at line %d:\n\t%s\n\t%s\n", + filename.c_str(), + cfg->line, + cfg->orig, + msg); + else fprintf(stderr, "Error parsing file %s at line %d:\n\t%s\n\t%s\n", + filename.c_str(), + cfg->line, + cfg->orig, + msg); } -/** - * Adds one configuration entry, from a single zero terminated line. - */ -_cfg *MiavConfig::addConfig(_cfg *parent, char* conf) +_cfg* MiavConfig::readLines(char* raw) { - // Check for wellformed input: - // Check for = - if(strstr(conf, "=") == 0) return parseError("Missing '='", conf); - /* - if(strstr(conf, "\"")) { - if(strstr(conf, "=") > strstr(conf, "\"")) - return parseError("Missing '=', first occurrence inside string", conf); - } - */ + int line = 1; + + _cfg *first = (_cfg*)calloc(1, sizeof(_cfg)); + _cfg *current = first; + _cfg *next = NULL; - // Check for nonempty left side - if(strstr(conf, "=") == conf) return parseError("Empty left side", conf); + char *nl = strchr(raw, '\n'); - // Check for nonempty right side - if(strstr(conf, "=") == conf + strlen(conf) - 1) return parseError("Empty right side.", conf); + while(nl != NULL) { + int len = nl - raw; - // Parse this wellformed input. - _cfg *cfg; + current->line = line; - cfg = (_cfg*) malloc(sizeof(_cfg)); - if(!parent) configs = cfg; + current->orig = (char*) calloc(len + 1, 1); + strncpy(current->orig, raw, len); - int namelen = strchr(conf, '=') - conf; - char* name = (char*)calloc(namelen + 1, 1); - strncpy(name, conf, namelen); + // Find next newline + raw = nl+1; + nl = strchr(raw, '\n'); - int vallen = conf + strlen(conf) - (strchr(conf, '=') + 1); - char* val = (char*)calloc(vallen + 1, 1); - strncpy(val, conf + strlen(conf) - vallen, vallen); + line++; - // TODO: Check valid rightside (true, false, number or "..") + // Add _cfg + if(nl != NULL) { + next = (_cfg*)calloc(1, sizeof(_cfg)); + current->next = next; + current = next; + } else { + current->next = NULL; + } + } - cfg->name = new string((const char*)name); - free(name); + return first; +} - cfg->stringval = new string((const char*)val); - cfg->intval = atoi(val); - cfg->floatval = atof(val); - cfg->boolval = atoi(val) != 0; - free(val); +_cfg* MiavConfig::parseLines(_cfg *cfg) +{ + if(cfg == NULL) return NULL; - cfg->next = NULL; + char *l = cfg->left = (char*)calloc(1, strlen(cfg->orig)); + char *r = cfg->right = (char*)calloc(1, strlen(cfg->orig)); - if(parent) parent->next = cfg; - return cfg; -} + char *p = cfg->orig; -/** - * Main parse function, iterates the lines of the file. - */ -int MiavConfig::parse(char* raw) -{ - // Strip the string - char *conf = strip(raw); - char *conf_end = conf + strlen(conf); - char *start = conf; - char *p; - - _cfg *cfg = NULL; - - // Iterate the lines in the string - for(p = conf; p < conf_end; p++) { - if(*p == '\n') { - *p = '\0'; - if(!(cfg = addConfig(cfg, start))) return 1; - start = p+1; + // Skip leftmost whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + // Empty line, with whitespaces + if(p == cfg->orig + strlen(cfg->orig)) { + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Parse left side + while(p < cfg->orig + strlen(cfg->orig) && !strchr("\t ", *p)) { + if(strchr("#", *p)) { + if(l != cfg->left) parseError("Incomplete line.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + if(strchr("=", *p)) break; + + if(strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_", *p)) { + *l = *p; + l++; + } else { + char buf[256]; + sprintf(buf, "Invalid left hand side character at [%s].", p); + parseError(buf, cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); } + + p++; } - // Allocated in strip - free(conf); - return 0; -} -/** - * Strip all unwanted data from the string, initial to parsing. - */ -char* MiavConfig::strip(char* conf) -{ - // Freed in parse!!! - char *stripped = (char*)calloc(strlen(conf) + 2, 1); - char *r; - char *w = stripped; - - bool instring = false; - bool incomment = false; - - // Iterate over the characters in the input string. - for(r = conf; r < conf + strlen(conf); r++) { - if(strchr("#", *r)) incomment = true; - if(strchr("\n", *r)) incomment = false; - - if(!incomment) { - if(instring) { - // When in a string, accept anything, except ". - if(*r != '\"') { - *w = *r; - w++; - } - } else { - // Only copy valid characters - if(strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_,.=", *r)) { - // Change comma into dot - if(*r == ',') *r = '.'; - *w = *r; - w++; - } - // We don't want double newlines and initial newline! - if((*r == '\n') && (*(w-1) != '\n') && (w != stripped)) { - *w = *r; - w++; - } + // Skip whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + if(*p != '=') { + parseError("Expected '='.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + p++; // Get past the '=' + + // Skip whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + // Parse right hand side + int instring = 0; + while(p < cfg->orig + strlen(cfg->orig) && !(strchr("\t ", *p) && instring != 1)) { + if(*p == '\"') instring++; + if(instring > 2) { + parseError("Too many '\"'.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + if(instring == 1) { + // Accept all chars + *r= *p; + r++; + } else { + // Accept only those chars valid for the data types. + if(strchr("truefalseyesnoTRUEFALSEYESNO1234567890\",.-", *p)) { + if(*p == ',') *r= '.'; + *r = *p; + r++; + } else if(!strchr("\n", *p)) { + char buf[256]; + sprintf(buf, "Invalid right hand side character at [%s].", p); + parseError(buf, cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); } + if(*p == '#') break; } - if(strchr("\"", *r)) instring = !instring; + p++; + } + + // Skip whitespace + while(p < cfg->orig + strlen(cfg->orig) && strchr("\t ", *p)) { + p++; + } + + // Detect if whitespace ocurred inside righthand value. + if(p != cfg->orig + strlen(cfg->orig)) { + parseError("Invalid use of whitespace.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Check for instring (string not ended) + if(instring == 1) { + parseError("String not closed.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Check for empty line + if(l == cfg->left && r == cfg->right) { + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); + } + + // Check for empty left side. + if(l == cfg->left) { + parseError("Empty left side.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); } - // If we are not ending on a newline, we better append one - if(*(w-1) != '\n') { - *w = '\n'; - w++; + // Check for empty right side. + if(r == cfg->right) { + parseError("Empty right side.", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return parseLines(next); } - // Make sure we are nullterminated. - *w = '\0'; + cfg->next = parseLines(cfg->next); + return cfg; +} + + +_cfg *MiavConfig::createSemantics(_cfg *cfg) { + if(cfg == NULL) return NULL; + + cfg->type = CONFIG_UNKNOWN; + + // Boolean - true + if(strcasecmp(cfg->right, "yes") == 0 || + strcasecmp(cfg->right, "true") == 0) { + cfg->type = CONFIG_BOOL; + cfg->boolval = true; + } + + // Boolean - false + if(strcasecmp(cfg->right, "no") == 0 || + strcasecmp(cfg->right, "false") == 0) { + cfg->type = CONFIG_BOOL; + cfg->boolval = false; + } - return stripped; + // String + if(cfg->right[0] == '\"') { + cfg->type = CONFIG_STRING; + cfg->right[strlen(cfg->right) - 1] = '\0'; + cfg->stringval = new string(cfg->right + 1); + + } + + // Number + bool number = true; + char *p = cfg->right; + while(p < cfg->right + strlen(cfg->right)) { + if(!strchr("01234567890.-", *p)) number = false; + p++; + } + + // Integer + if(number && strstr(cfg->right, ".") == NULL ) { + cfg->type = CONFIG_INT; + cfg->intval = atoi(cfg->right); + } + + // Float + if(number && strstr(cfg->right, ".") != NULL) { + cfg->type = CONFIG_FLOAT; + cfg->floatval = atof(cfg->right); + } + + if(cfg->type == CONFIG_UNKNOWN) { + parseError("Unknown type (see 'man miav.conf' for valid right hand sides).", cfg); + _cfg* next = cfg->next; + free(cfg->orig); + free(cfg->left); + free(cfg->right); + free(cfg); + return createSemantics(next); + } + + // Create name + cfg->name = new string(cfg->left); + + cfg->next = createSemantics(cfg->next); + return cfg; +} + + +_cfg* MiavConfig::parse(char* raw) +{ + _cfg *first = readLines(raw); + first = parseLines(first); + + first = createSemantics(first); + + /* + _cfg* cfg = first; + while(cfg) { + printf("Node:\n"); + printf("\tLine: [%d]\n", cfg->line); + printf("\tOrig: [%s]\n", cfg->orig); + printf("\tLeft: [%s]\n", cfg->left); + printf("\tRight: [%s]\n", cfg->right); + + switch(cfg->type) { + case CONFIG_INT: + printf("\tInt value: %d\n", cfg->intval); + break; + case CONFIG_BOOL: + printf("\tBool value: %d\n", cfg->boolval); + break; + case CONFIG_FLOAT: + printf("\tFloat value: %f\n", cfg->floatval); + break; + case CONFIG_STRING: + printf("\tString value: %s\n", cfg->stringval->c_str()); + break; + case CONFIG_UNKNOWN: + printf("\tUnknown type: %s\n", cfg->right); + break; + } + + cfg= cfg->next; + } + */ + return first; } int MiavConfig::readInt(char *node) { _cfg* n = findNode(node); - if(n) return n->intval; - else return 0; + if(n) { + if(n->type == CONFIG_INT) return n->intval; + parseError("Expected integer.", n); + } + return 0; } bool MiavConfig::readBool(char *node) { - _cfg* n = findNode(node); - if(n) return n->boolval; - else return false; + _cfg* n = findNode(node); + if(n) { + if(n->type == CONFIG_BOOL) return n->boolval; + if(n->type == CONFIG_INT) return (n->intval != 0); + parseError("Expected boolean.", n); + } + return false; } string *MiavConfig::readString(char *node) { _cfg* n = findNode(node); - if(n) return n->stringval; - else return &emptyString; + if(n) { + if(n->type == CONFIG_STRING) return n->stringval; + parseError("Expected string.", n); + } + return &emptyString; } float MiavConfig::readFloat(char *node) { _cfg* n = findNode(node); - if(n) return n->floatval; - else return 0.0f; + if(n) { + if(n->type == CONFIG_FLOAT) return n->floatval; + if(n->type == CONFIG_INT) return (float)n->intval; + parseError("Expected float.", n); + } + return 0.0f; } _cfg *MiavConfig::findNode(char* node) @@ -270,8 +486,31 @@ _cfg *MiavConfig::findNode(char* node) if(!strcmp(node, cfg->name->c_str())) return cfg; cfg = cfg->next; } - if(info) info->error("Request for nonexisting node \"%s\"!\n", node); - else fprintf(stderr, "Request for nonexisting node \"%s\"!\n", node); + if(info) info->error("Missing line in configuration file: \"%s\"!\n", node); + else fprintf(stderr, "Missing line in configuration file: \"%s\"!\n", node); return NULL; } + +#ifdef __TEST_MIAV_CONFIG + +int main(int argc, char *argv[]) { + if(argc < 2) { + fprintf(stderr, "usage:\n\tmiav_config [filename]\n"); + return 1; + } + + MiavConfig cfg(argv[1]); + printf("Server user: [%s]\n", cfg.readString("server_user")->c_str()); + printf("Resolution: [%f]\n", cfg.readFloat("screensize")); + printf("Resolution (as int): [%d]\n", cfg.readInt("screensize")); + printf("Width: [%d]\n", cfg.readInt("pixel_width")); + printf("Width (as float): [%f]\n", cfg.readFloat("pixel_width")); + printf("Frame quality: [%d]\n", cfg.readInt("frame_quality")); + printf("Skip frames: [%d]\n", cfg.readBool("player_skip_frames")); + printf("Skip frames (as int): [%d]\n", cfg.readInt("player_skip_frames")); + printf("Frame quality (as bool): [%d]\n", cfg.readBool("frame_quality")); + +} + +#endif/* __TEST_MIAV_CONFIG*/ |