]> git.sur5r.net Git - i3/i3/commitdiff
Allow the commands parser to use "number" arguments by making the stack typed.
authorIngo Bürk <ingo.buerk@tngtech.com>
Sun, 27 Sep 2015 14:32:40 +0000 (16:32 +0200)
committerIngo Bürk <ingo.buerk@tngtech.com>
Mon, 28 Sep 2015 12:21:44 +0000 (14:21 +0200)
src/commands_parser.c
src/config_parser.c

index ffe416f04dd1c3659ff0aae5687f02269ee63700..d311fdd17c683d605e7a30f08d3dcc9f201fc6a0 100644 (file)
@@ -73,7 +73,14 @@ typedef struct tokenptr {
 struct stack_entry {
     /* Just a pointer, not dynamically allocated. */
     const char *identifier;
-    char *str;
+    enum {
+        STACK_STR = 0,
+        STACK_LONG = 1,
+    } type;
+    union {
+        char *str;
+        long num;
+    } val;
 };
 
 /* 10 entries should be enough for everybody. */
@@ -90,7 +97,30 @@ static void push_string(const char *identifier, char *str) {
             continue;
         /* Found a free slot, let’s store it here. */
         stack[c].identifier = identifier;
-        stack[c].str = str;
+        stack[c].val.str = str;
+        stack[c].type = STACK_STR;
+        return;
+    }
+
+    /* When we arrive here, the stack is full. This should not happen and
+     * means there’s either a bug in this parser or the specification
+     * contains a command with more than 10 identified tokens. */
+    fprintf(stderr, "BUG: commands_parser stack full. This means either a bug "
+                    "in the code, or a new command which contains more than "
+                    "10 identified tokens.\n");
+    exit(1);
+}
+
+// TODO move to a common util
+static void push_long(const char *identifier, long num) {
+    for (int c = 0; c < 10; c++) {
+        if (stack[c].identifier != NULL) {
+            continue;
+        }
+
+        stack[c].identifier = identifier;
+        stack[c].val.num = num;
+        stack[c].type = STACK_LONG;
         return;
     }
 
@@ -105,71 +135,39 @@ static void push_string(const char *identifier, char *str) {
 
 // XXX: ideally, this would be const char. need to check if that works with all
 // called functions.
+// TODO move to a common util
 static char *get_string(const char *identifier) {
     for (int c = 0; c < 10; c++) {
         if (stack[c].identifier == NULL)
             break;
         if (strcmp(identifier, stack[c].identifier) == 0)
-            return stack[c].str;
+            return stack[c].val.str;
     }
     return NULL;
 }
 
-static void clear_stack(void) {
+// TODO move to a common util
+static long get_long(const char *identifier) {
     for (int c = 0; c < 10; c++) {
-        if (stack[c].str != NULL)
-            free(stack[c].str);
-        stack[c].identifier = NULL;
-        stack[c].str = NULL;
+        if (stack[c].identifier == NULL)
+            break;
+        if (strcmp(identifier, stack[c].identifier) == 0)
+            return stack[c].val.num;
     }
-}
-
-// TODO: remove this if it turns out we don’t need it for testing.
-#if 0
-/*******************************************************************************
- * A dynamically growing linked list which holds the criteria for the current
- * command.
- ******************************************************************************/
 
-typedef struct criterion {
-    char *type;
-    char *value;
-
-    TAILQ_ENTRY(criterion) criteria;
-} criterion;
-
-static TAILQ_HEAD(criteria_head, criterion) criteria =
-  TAILQ_HEAD_INITIALIZER(criteria);
-
-/*
- * Stores the given type/value in the list of criteria.
- * Accepts a pointer as first argument, since it is 'call'ed by the parser.
- *
- */
-static void push_criterion(void *unused_criteria, const char *type,
-                           const char *value) {
-    struct criterion *criterion = smalloc(sizeof(struct criterion));
-    criterion->type = sstrdup(type);
-    criterion->value = sstrdup(value);
-    TAILQ_INSERT_TAIL(&criteria, criterion, criteria);
+    return 0;
 }
 
-/*
- * Clears the criteria linked list.
- * Accepts a pointer as first argument, since it is 'call'ed by the parser.
- *
- */
-static void clear_criteria(void *unused_criteria) {
-    struct criterion *criterion;
-    while (!TAILQ_EMPTY(&criteria)) {
-        criterion = TAILQ_FIRST(&criteria);
-        free(criterion->type);
-        free(criterion->value);
-        TAILQ_REMOVE(&criteria, criterion, criteria);
-        free(criterion);
+// TODO move to a common util
+static void clear_stack(void) {
+    for (int c = 0; c < 10; c++) {
+        if (stack[c].type == STACK_STR && stack[c].val.str != NULL)
+            free(stack[c].val.str);
+        stack[c].identifier = NULL;
+        stack[c].val.str = NULL;
+        stack[c].val.num = 0;
     }
 }
-#endif
 
 /*******************************************************************************
  * The parser itself.
@@ -316,6 +314,29 @@ CommandResult *parse_command(const char *input, yajl_gen gen) {
                 continue;
             }
 
+            if (strcmp(token->name, "number") == 0) {
+                /* Handle numbers. We only accept decimal numbers for now. */
+                char *end = NULL;
+                errno = 0;
+                long int num = strtol(walk, &end, 10);
+                if ((errno == ERANGE && (num == LONG_MIN || num == LONG_MAX)) ||
+                    (errno != 0 && num == 0))
+                    continue;
+
+                /* No valid numbers found */
+                if (end == walk)
+                    continue;
+
+                if (token->identifier != NULL)
+                    push_long(token->identifier, num);
+
+                /* Set walk to the first non-number character */
+                walk = end;
+                next_state(token);
+                token_handled = true;
+                break;
+            }
+
             if (strcmp(token->name, "string") == 0 ||
                 strcmp(token->name, "word") == 0) {
                 char *str = parse_string(&walk, (token->name[0] != 's'));
index ea00412d78b2d2533c5dd0b87486aaa3da7e9f4e..705a3e24525466056186a7f12506ee8aa1467955 100644 (file)
@@ -122,7 +122,7 @@ static void push_string(const char *identifier, const char *str) {
     /* When we arrive here, the stack is full. This should not happen and
      * means there’s either a bug in this parser or the specification
      * contains a command with more than 10 identified tokens. */
-    fprintf(stderr, "BUG: commands_parser stack full. This means either a bug "
+    fprintf(stderr, "BUG: config_parser stack full. This means either a bug "
                     "in the code, or a new command which contains more than "
                     "10 identified tokens.\n");
     exit(1);
@@ -142,7 +142,7 @@ static void push_long(const char *identifier, long num) {
     /* When we arrive here, the stack is full. This should not happen and
      * means there’s either a bug in this parser or the specification
      * contains a command with more than 10 identified tokens. */
-    fprintf(stderr, "BUG: commands_parser stack full. This means either a bug "
+    fprintf(stderr, "BUG: config_parser stack full. This means either a bug "
                     "in the code, or a new command which contains more than "
                     "10 identified tokens.\n");
     exit(1);
@@ -178,53 +178,6 @@ static void clear_stack(void) {
     }
 }
 
-// TODO: remove this if it turns out we don’t need it for testing.
-#if 0
-/*******************************************************************************
- * A dynamically growing linked list which holds the criteria for the current
- * command.
- ******************************************************************************/
-
-typedef struct criterion {
-    char *type;
-    char *value;
-
-    TAILQ_ENTRY(criterion) criteria;
-} criterion;
-
-static TAILQ_HEAD(criteria_head, criterion) criteria =
-  TAILQ_HEAD_INITIALIZER(criteria);
-
-/*
- * Stores the given type/value in the list of criteria.
- * Accepts a pointer as first argument, since it is 'call'ed by the parser.
- *
- */
-static void push_criterion(void *unused_criteria, const char *type,
-                           const char *value) {
-    struct criterion *criterion = smalloc(sizeof(struct criterion));
-    criterion->type = sstrdup(type);
-    criterion->value = sstrdup(value);
-    TAILQ_INSERT_TAIL(&criteria, criterion, criteria);
-}
-
-/*
- * Clears the criteria linked list.
- * Accepts a pointer as first argument, since it is 'call'ed by the parser.
- *
- */
-static void clear_criteria(void *unused_criteria) {
-    struct criterion *criterion;
-    while (!TAILQ_EMPTY(&criteria)) {
-        criterion = TAILQ_FIRST(&criteria);
-        free(criterion->type);
-        free(criterion->value);
-        TAILQ_REMOVE(&criteria, criterion, criteria);
-        free(criterion);
-    }
-}
-#endif
-
 /*******************************************************************************
  * The parser itself.
  ******************************************************************************/