/* * load a configuration file into memory, allocating structures as required */ struct config_sect *config_load (char *filename) { FILE *fp; char line[MAX_CONF_LEN]; struct config_sect *sects = NULL; struct config_sect *cur_sect = NULL; struct config_token *cur_token = NULL; char *token; char *value; fp = fopen (filename, "r"); if (!fp) { perror ("config file"); return NULL; } while (fgets(line, MAX_CONF_LEN, fp)) { if (line[0] == '#') continue; /* skip lines with comment */ if (strlen (line) <= 1) continue; line[strlen (line) - 1] = 0; /* remove trailing '\n' */ if (line[0] == '[') { /* section header */ token = strtok (line + 1, "]"); if (token != NULL) { struct config_sect *new_sect = config_new_section (token); if (new_sect) { if (cur_sect) { cur_sect->next = new_sect; } else { sects = new_sect; } cur_sect = new_sect; cur_token = NULL; } } } else { token = strtok_r (line, " \t=", &value); if (token != NULL) { struct config_token *new_token; value = strtok (value, " =#\t"); if (!cur_sect) { cur_sect = config_new_section ("default"); sects = cur_sect; } new_token = config_new_token (token, value); if (new_token) { if (cur_token) { cur_token->next = new_token; } else { cur_sect->tokens = new_token; } cur_token = new_token; } } } } fclose(fp); return sects; } /* config_load () */
/* * load a configuration file into memory, allocating structures as required */ struct config_sect * config_load(char *filename) { FILE *fp; char line[MAX_CONF_LEN]; struct config_sect *sects = NULL; struct config_sect *cur_sect = NULL; struct config_token *cur_token = NULL; char *token; char *value; fp = fopen(filename, "r"); check(fp != NULL, "Cannot open the specified configuration file."); while (fgets(line, MAX_CONF_LEN, fp) != NULL) { /* * Skip linear white space at the beginning of the line. */ char *p; for (p = line; *p == ' ' || *p == '\t'; p++); if (p != line) /** * The original implementation uses strcpy(3), which is acceptable * in most cases. However, in this case, `s1` and `s2` overlap. * According to POSIX.1-2008, "If copying takes place between * objects that overlap, the behavior is undefined." Hence, I * replace it with memmove(3), which "copy bytes in memory with * overlapping areas". */ memmove(line, p, strlen(p) + 1); if (line[0] == '#') continue; /* skip lines with comment */ if (strlen(line) <= 1) continue; line[strlen(line) - 1] = 0; /* remove trailing '\n' */ if (line[0] == '[') { /* section header */ token = strtok(line + 1, "]"); if (token != NULL) { struct config_sect *new_sect = config_new_section(token); if (new_sect != NULL) { if (cur_sect != NULL) { cur_sect->next = new_sect; } else { sects = new_sect; } cur_sect = new_sect; cur_token = NULL; } } } else { token = strtok_r(line, " \t=", &value); if (token != NULL) { struct config_token *new_token; value = strtok(value, " =#\t"); if (cur_sect == NULL) { cur_sect = config_new_section("default"); sects = cur_sect; } new_token = config_new_token(token, value); if (new_token != NULL) { if (cur_token) { cur_token->next = new_token; } else { cur_sect->tokens = new_token; } cur_token = new_token; } } } } fclose(fp); return sects; error: if (fp != NULL) fclose(fp); return NULL; } /* config_load () */