]> mj.ucw.cz Git - libucw.git/commitdiff
Two improvements to the configuration language:
authorMartin Mares <mj@ucw.cz>
Sat, 29 Nov 2003 11:25:09 +0000 (11:25 +0000)
committerMartin Mares <mj@ucw.cz>
Sat, 29 Nov 2003 11:25:09 +0000 (11:25 +0000)
o  Floating point item type introduced.
o  Both integer and floating point numbers can be suffixed with a unit.

Also, I've exported parsing of integers and doubles for the convenience
of CT_FUNCTION callbacks.

lib/conf-test.c
lib/conf.c
lib/conf.h

index f8ad4ed736ff0e0039b39322d392fab53fe919c1..719a0cfd35e4ee29a1b132935308a94f8b339c9c 100644 (file)
@@ -10,6 +10,7 @@ static int robert=14;
 static int spalek=-3;
 static char *heslo="prazdne";
 static int nastaveni1=0,nastaveni2=1;
+static double decker = 0;              /* The famous London buses :-) */
 
 static byte *set_nastaveni(struct cfitem *item, byte *value)
 {
@@ -40,6 +41,7 @@ static struct cfitem jmeno[]={
        {"heslo",       CT_STRING,      &heslo},
        {"nastaveni1",  CT_FUNCTION,    &set_nastaveni},
        {"nastaveni2",  CT_FUNCTION,    &set_nastaveni},
+       {"decker",      CT_DOUBLE,      &decker},
        {NULL,          CT_STOP,        NULL}
 };
 
@@ -118,8 +120,8 @@ int main(int argc, char *argv[])
                printf ("\n");
        }
 
-       printf("robert=%d, spalek=%d, heslo=%s, nastaveni1/2=%d/%d\n",
-                       robert,spalek,heslo,nastaveni1,nastaveni2);
+       printf("robert=%d, spalek=%d, heslo=%s, nastaveni1/2=%d/%d decker=%f\n",
+                       robert,spalek,heslo,nastaveni1,nastaveni2,decker);
        printf("vek=%d, vyska=%d, vaha=%d\n",
                        vek,vyska,vaha);
 
index 7e4443bea453a9a2697e0cee85650510e4f8edab..b27745faeea8f90a0c0bab6e3d2cf809adbe42d0 100644 (file)
@@ -1,25 +1,26 @@
 /*
- *     Sherlock Library -- Reading configuration files
+ *     Sherlock Library -- Reading of configuration files
  *
  *     (c) 2001 Robert Spalek <robert@ucw.cz>
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
  */
 
 #include "lib/lib.h"
+#include "lib/chartype.h"
+#include "lib/fastbuf.h"
+#include "lib/pools.h"
+
+#include "lib/conf.h"
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <fcntl.h>
 #include <getopt.h>
-
-#include "lib/chartype.h"
-#include "lib/fastbuf.h"
-#include "lib/pools.h"
-
-#include "lib/conf.h"
+#include <errno.h>
 
 #define        BUFFER          1024
 #define        MAX_LEVEL       8
@@ -44,10 +45,10 @@ cfg_malloc(uns size)
 byte *
 cfg_stralloc(byte *s)
 {
-  uns l = strlen(s);
-  byte *k = cfg_malloc(l + 1);
-  strcpy(k, s);
-  return k;
+       uns l = strlen(s);
+       byte *k = cfg_malloc(l + 1);
+       strcpy(k, s);
+       return k;
 }
 
 void cf_register(struct cfitem *items)
@@ -86,6 +87,89 @@ struct cfitem *cf_get_item(byte *sect, byte *name)
        return item;    /* item->type == 0 if not found */
 }
 
+struct unit {
+       uns name;                       /* One-letter name of the unit */
+       uns num, den;                   /* Fraction */
+};
+
+static const struct unit units[] = {
+       { 'k', 1000, 1 },
+       { 'm', 1000000, 1 },
+       { 'g', 1000000000, 1 },
+       { 'K', 1024, 1 },
+       { 'M', 1048576, 1 },
+       { 'G', 1073741824, 1 },
+       { '%', 1, 100 },
+       { 0, 0, 0 }
+};
+
+static const struct unit *cf_lookup_unit(byte *value, byte *end, char **msg)
+{
+       if (end && *end) {
+               if (end == value || end[1] || *end >= '0' && *end <= '9')
+                       *msg = "Invalid number";
+               else {
+                       for (const struct unit *u=units; u->name; u++)
+                               if (u->name == *end)
+                                       return u;
+                       *msg = "Invalid unit";
+               }
+       }
+       return NULL;
+}
+
+static char cf_rngerr[] = "Number out of range";
+
+byte *cf_parse_int(byte *value, uns *varp)
+{
+       char *msg = NULL;
+       const struct unit *u;
+
+       if (!*value)
+               msg = "Missing number";
+       else {
+               errno = 0;
+               char *end;
+               uns x = strtoul(value, &end, 0);
+               if (errno == ERANGE)
+                       msg = cf_rngerr;
+               else if (u = cf_lookup_unit(value, end, &msg)) {
+                       u64 y = (u64)x * u->num;
+                       if (y % u->den)
+                               msg = "Number is not an integer";
+                       else {
+                               y /= u->den;
+                               if (y > 0xffffffff)
+                                       msg = cf_rngerr;
+                               *varp = y;
+                       }
+               } else
+                       *varp = x;
+       }
+       return msg;
+}
+
+byte *cf_parse_double(byte *value, double *varp)
+{
+       char *msg = NULL;
+       const struct unit *u;
+
+       if (!*value)
+               msg = "Missing number";
+       else {
+               errno = 0;
+               char *end;
+               double x = strtoul(value, &end, 0);
+               if (errno == ERANGE)
+                       msg = cf_rngerr;
+               else if (u = cf_lookup_unit(value, end, &msg))
+                       *varp = x * u->num / u->den;
+               else
+                       *varp = x;
+       }
+       return msg;
+}
+
 byte *cf_set_item(byte *sect, byte *name, byte *value)
 {
        struct cfitem *item;
@@ -99,26 +183,19 @@ byte *cf_set_item(byte *sect, byte *name, byte *value)
 
        switch(item->type){
                case CT_INT:
-                       {
-                               char *end;
-                               if(!*value)
-                                       msg="Missing number";
-                               else{
-                                       *((uns *) item->var) = strtoul(value, &end, 0);
-                                       if (end && *end)
-                                               msg = "Invalid number";
-                               }
-                               break;
-                       }
+                       msg = cf_parse_int(value, (uns *) item->var);
+                       break;
                case CT_STRING:
                        *((byte **) item->var) = cfg_stralloc(value);
                        break;
                case CT_FUNCTION:
                        msg = ((ci_func) item->var)(item, cfg_stralloc(value));
                        break;
+               case CT_DOUBLE:
+                       msg = cf_parse_double(value, (double *) item->var);
+                       break;
                default:
                        msg = "Unknown keyword";
-                       break;
        }
 
        return msg;
index f4ede6699942429c10c1efa29c5521c15f14d32f..774ea1fd838885c83328d0b6e045059902aa2421 100644 (file)
@@ -1,7 +1,8 @@
 /*
- *     Sherlock Library -- Reading configuration files
+ *     Sherlock Library -- Reading of configuration files
  *
  *     (c) 2001 Robert Spalek <robert@ucw.cz>
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -33,7 +34,7 @@ byte *cfg_stralloc(byte *s);
  * function.
  */
 
-enum cftype { CT_STOP, CT_SECTION, CT_INCOMPLETE_SECTION, CT_INT, CT_STRING, CT_FUNCTION };
+enum cftype { CT_STOP, CT_SECTION, CT_INCOMPLETE_SECTION, CT_INT, CT_STRING, CT_FUNCTION, CT_DOUBLE };
 
 struct cfitem {
        byte *name;
@@ -54,6 +55,13 @@ struct cfitem *cf_get_item(byte *sect, byte *name);
 byte *cf_set_item(byte *sect, byte *name, byte *value);
 void cf_read(byte *filename);
 
+/*
+ * Number parsing functions which could be useful in CT_FUNCTION callbacks.
+ */
+
+byte *cf_parse_int(byte *value, uns *varp);
+byte *cf_parse_double(byte *value, double *varp);
+
 /*
  * When using cf_getopt, you must prefix your own short/long options by the
  * CF_(SHORT|LONG)_OPTS.