/* * configuration parser unit * * This file is part of the backconn project. http://backconn.sourceforge.net * Copyright (C) 2017, 2018 Mateusz Viste * * ===================== PUBLISHED UNDER THE MIT LICENSE ===================== * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * =========================================================================== */ #include <stdio.h> /* rewind(), fgetc()... */ #include <stdlib.h> /* calloc() */ #include <string.h> /* memmove() */ #include "config.h" /* reads a single line from file, returns length of line on success, or -1 on EOF, or -2 on other errors */ static int freadline(char *buf, int bufsize, FILE *fp) { int c, reslen = 0; if (bufsize < 1) return(0); bufsize -= 1; /* just so it's easier to check later */ for (;;) { c = fgetc(fp); if (c == EOF) { if (reslen == 0) return(-1); return(reslen); } if (c == '\n') { buf[reslen] = 0; return(reslen); } buf[reslen] = c; if (reslen < bufsize) reslen++; } } static void line2ptrs(char *line, char **res, int resz) { int i, r; /* init res array to all NULLs */ for (i = 0; i < resz; i++) res[i] = NULL; /* */ i = 0; r = 0; for (;;) { /* do I have some PTRs left? */ if (r >= resz) break; /* skip to next non-whitespace char */ while ((line[i] == ' ') || (line[i] == '\t')) i++; /* end of line? */ if (line[i] == 0) break; /* EOL */ /* save ptr */ res[r++] = line+i; /* skip to next white-space char */ while ((line[i] != ' ') && (line[i] != '\t') && (line[i] != 0)) i++; /* EOL? */ if (line[i] == 0) break; /* EOL */ /* insert a string terminator */ line[i++] = 0; } } void config_free(struct scfg *cfg) { struct scfg *victim; while (cfg != NULL) { victim = cfg; cfg = cfg->next; free(victim); } } struct scfg *config_read(FILE *fp) { struct scfg *res = NULL; struct scfg *node; char buf[1024]; rewind(fp); for (;;) { int linelen, i; char *ptrs[8]; /* read line to buffer */ linelen = freadline(buf, sizeof(buf), fp); if (linelen < 0) return(res); /* if comment or empty - skip it */ if ((linelen == 0) || (buf[0] == '#')) continue; /* alloc and fill node */ node = calloc(sizeof(struct scfg) + linelen, 1); if (node == NULL) { /* out of memory */ config_free(res); return(NULL); } memmove(node->data, buf, linelen + 1); /* tokenize the line */ line2ptrs(node->data, ptrs, 6); if ((ptrs[0] == NULL) || (ptrs[0][0] == '#')) { /* empty line of comment */ free(node); continue; } node->token = ptrs[0]; for (i = 0; i < 4; i++) node->val[i] = ptrs[i+1]; /* append node to queue */ node->next = res; res = node; } } struct scfg *config_find(struct scfg *cfg, char *token) { while (cfg != NULL) { if (strcasecmp(cfg->token, token) == 0) return(cfg); cfg = cfg->next; } return(NULL); }