💾 Archived View for gmi.noulin.net › gitRepositories › ini › file › src › ini.c.gmi captured on 2023-01-29 at 13:20:27. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

ini

Log

Files

Refs

LICENSE

ini.c (4425B)

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <ctype.h>
     4 #include <string.h>
     5 #include "ini.h"
     6 
     7 internal int read_until(FILE* fp, char* buffer, int size, int delim);
     8 
     9 internal int callback(char* section, char* config, char* value, smallDictt *r)
    10 {
    11         //printf("[%s] \"%s\" == \"%s\"\n", section, config, value);
    12         if (isBlankG(section)) {
    13                 setG(r, config, value);
    14         }
    15         else {
    16                 smallDictt *sect = getG(r, rtSmallDictt, section);
    17                 if (sect) {
    18                         setG(sect, config, value);
    19                         setPG(r, section, sect);
    20                 }
    21                 else {
    22                         sect = allocG(rtSmallDictt);
    23                         setG(sect, config, value);
    24                         setNFreeG(r, section, sect);
    25                 }
    26         }
    27         return 0;
    28 }
    29 
    30 /**
    31  * @brief Parse an ini file.
    32  * @details Parse an ini file. Passes values to a callback function.
    33  * No dynamic memory is allocated.
    34  *
    35  * @param fp Open file pointer to read INI file from
    36  * @param callback Callback function accepting three arguments:
    37  * section, variable, and value strings.
    38  * @return 0 on success, error code on failure
    39  */
    40 internal int iniParseFile(FILE* fp, int (*callback)(char*, char*, char*, smallDictt *), smallDictt *r)
    41 {
    42         if ((fp == NULL) || (callback == NULL))
    43                 return -1;
    44 
    45         char section [BUFFER_SIZE] = "";
    46         char config  [BUFFER_SIZE] = "";
    47         char value   [BUFFER_SIZE] = "";
    48         int c;
    49         int err;
    50         while((c = getc(fp)) != EOF) {
    51                 switch(c) {
    52                         case '#': {
    53                                 while ((c = getc(fp)) != '\n')
    54                                         ;
    55                                 break;
    56                         }
    57                         case '[': {
    58                                 err = read_until(fp, section, BUFFER_SIZE, ']');
    59                                 if (err)
    60                                         return err;
    61                                 break;
    62                         }
    63                         case '=': {
    64                                 err = read_until(fp, value, BUFFER_SIZE, '\n');
    65                                 if (err)
    66                                         return err;
    67                                 err = callback(section, config, value, r);
    68                                 if (err)
    69                                         return err;
    70                                 break;
    71                         }
    72                         case '\n': case ' ': case '\t':
    73                                 break;
    74                         default:
    75                                 ungetc(c, fp);
    76                                 err = read_until(fp, config, BUFFER_SIZE, '=');
    77                                 if (err)
    78                                         return err;
    79                                 break;
    80                 }
    81         }
    82         return -1;
    83 }
    84 
    85 smallDictt *parseIni(const char *filename)
    86 {
    87         FILE* fp = fopen(filename, "r");
    88         pTestErrorCmd(fp == NULL, return NULL);
    89 
    90         createAllocateSmallDict(r);
    91         iniParseFile(fp, callback, r);
    92         fclose(fp);
    93         return r;
    94 }
    95 
    96 internal int read_until(FILE* fp, char* buffer, int size, int delim)
    97 {
    98         char c;
    99         int i = 0;
   100         memset(buffer, 0, size);
   101         int string = 0;
   102         while (i < size) {
   103                 c = getc(fp);
   104                 if(isblank(c) && string == 0) {
   105                         continue;
   106                 } else if (c == '\"') {
   107                         string = 1;
   108                 } else if (c == delim) {
   109                         buffer[i] = '\0';
   110                         if (delim == '=')
   111                                 ungetc(c, fp);
   112                         return 0;
   113                 } else if (c == EOF) {
   114                         return 0;
   115                 }
   116                 buffer[i++] = c;
   117         }
   118         buffer[i] = '\0';
   119         return -1;
   120 }
   121 
   122 /**
   123  * @brief Parse an ini file.
   124  * @details Parse an ini file. Passes values to a callback function.
   125  * No dynamic memory is allocated.
   126  *
   127  * @param fp Open file pointer to read INI file from
   128  * @param callback Callback function accepting three arguments:
   129  * section, variable, and value strings.
   130  * @return 0 on success, error code on failure
   131  */
   132 int ini_parse_file(FILE* fp, int (*callback)(char*, char*, char*))
   133 {
   134         if ((fp == NULL) || (callback == NULL))
   135                 return -1;
   136 
   137         char section [BUFFER_SIZE] = "";
   138         char config  [BUFFER_SIZE] = "";
   139         char value   [BUFFER_SIZE] = "";
   140         int c;
   141         int err;
   142         while((c = getc(fp)) != EOF) {
   143                 switch(c) {
   144                         case '#': {
   145                                 while ((c = getc(fp)) != '\n')
   146                                         ;
   147                                 break;
   148                         }
   149                         case '[': {
   150                                 err = read_until(fp, section, BUFFER_SIZE, ']');
   151                                 if (err)
   152                                         return err;
   153                                 break;
   154                         }
   155                         case '=': {
   156                                 err = read_until(fp, value, BUFFER_SIZE, '\n');
   157                                 if (err)
   158                                         return err;
   159                                 err = callback(section, config, value);
   160                                 if (err)
   161                                         return err;
   162                                 break;
   163                         }
   164                         case '\n': case ' ': case '\t':
   165                                 break;
   166                         default:
   167                                 ungetc(c, fp);
   168                                 err = read_until(fp, config, BUFFER_SIZE, '=');
   169                                 if (err)
   170                                         return err;
   171                                 break;
   172                 }
   173         }
   174         return -1;
   175 }
   176 
   177 bool saveIni(smallDictt *ini, const char *path) {
   178         if (!ini || !path) {
   179                 return false;
   180         }
   181         createAllocateSmallArray(r);
   182         forEachSmallDict(ini, k, D) {
   183                 cast(smallDictt*, d, D);
   184                 pushNFreeG(r, catS("[", k, "]"));
   185                 {forEachSmallDict(d, k2, S) {
   186                         castS(s, S);
   187                         if (isBlankG(s)) {
   188                                 pushNFreeG(r, catS(k2, " ="));
   189                         }
   190                         else {
   191                                 pushNFreeG(r, catS(k2, " = ", ssGet(s)));
   192                         }
   193                         finishG(s);
   194                 }
   195                 listFreeS(libsheepyInternalKeys);
   196                 }
   197                 pushG(r, "");
   198                 finishG(d);
   199         }
   200         listFreeS(libsheepyInternalKeys);
   201         writeFileG(r, path);
   202         return true;
   203 }
   204 
   205 
   206 bool checkLibsheepyVersionIni(const char *currentLibsheepyVersion) {
   207   return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION);
   208 }
   209