From a5ddd2cd225d8f53d91935759ec6108685efc452 Mon Sep 17 00:00:00 2001 From: phillbush Date: Fri, 29 May 2020 23:48:49 -0300 Subject: [PATCH] Simplifying parsing and data structure building MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit • Parsing of stdin was simplified by using conventional stdlib functions rather than parsing the stdin byte-by-byte. • Splited parsing of textual input and building of internal data structures into two different functions. --- xmenu.c | 149 +++++++++++++++++++++++++++----------------------------- 1 file changed, 73 insertions(+), 76 deletions(-) diff --git a/xmenu.c b/xmenu.c index 7127914..5fefae8 100644 --- a/xmenu.c +++ b/xmenu.c @@ -73,6 +73,7 @@ static void setupdc(void); static void calcgeom(void); static struct Item *allocitem(const char *label, const char *output); static struct Menu *allocmenu(struct Menu *parent, struct Item *list, unsigned level); +static struct Menu * buildmenutree(unsigned level, const char *label, const char *output); static struct Menu *parsestdin(void); static void calcmenu(struct Menu *menu); static void grabpointer(void); @@ -251,7 +252,7 @@ allocitem(const char *label, const char *output) if ((item = malloc(sizeof *item)) == NULL) err(1, "malloc"); - if (*label == '\0') { + if (label == NULL) { item->label = NULL; item->output = NULL; } else { @@ -310,96 +311,92 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level) return menu; } -/* create menus and items from the stdin */ +/* build the menu tree */ static struct Menu * -parsestdin(void) +buildmenutree(unsigned level, const char *label, const char *output) { - char *s, buf[BUFSIZ]; - char *label, *output; - unsigned level = 0; + static struct Menu *prevmenu = NULL; /* menu the previous item was added to */ + static struct Menu *rootmenu = NULL; /* menu to be returned */ + struct Item *curritem = NULL; /* item currently being read */ + struct Item *item; /* dummy item for loops */ + struct Menu *menu; /* dummy menu for loops */ unsigned i; - struct Item *curritem = NULL; /* item currently being read */ - struct Menu *prevmenu = NULL; /* menu the previous item was added to */ - struct Item *item; /* dummy item for loops */ - struct Menu *menu; /* dummy menu for loops */ - struct Menu *rootmenu; /* menu to be returned */ - - rootmenu = NULL; - - while (fgets(buf, BUFSIZ, stdin) != NULL) { - level = 0; - s = buf; - - while (*s == '\t') { - level++; - s++; - } - label = output = s; - - while (*s != '\0' && *s != '\t' && *s != '\n') - s++; - - while (*s == '\t') - *s++ = '\0'; - - if (*s != '\0' && *s != '\n') - output = s; - - while (*s != '\0' && *s != '\n') - s++; - - if (*s == '\n') - *s = '\0'; - - curritem = allocitem(label, output); - - if (prevmenu == NULL) { /* there is no menu yet */ - menu = allocmenu(NULL, curritem, level); - rootmenu = menu; - prevmenu = menu; - curritem->prev = NULL; - curritem->next = NULL; - } else if (level < prevmenu->level) { /* item is continuation of a parent menu*/ - for (menu = prevmenu, i = level; - menu != NULL && i < prevmenu->level; - menu = menu->parent, i++) - ; - - if (menu == NULL) - errx(1, "reached NULL menu"); + /* create the item */ + curritem = allocitem(label, output); + + /* put the item in the menu tree */ + if (prevmenu == NULL) { /* there is no menu yet */ + menu = allocmenu(NULL, curritem, level); + rootmenu = menu; + prevmenu = menu; + curritem->prev = NULL; + } else if (level < prevmenu->level) { /* item is continuation of a parent menu */ + /* go up the menu tree until find the menu this item continues */ + for (menu = prevmenu, i = level; + menu != NULL && i != prevmenu->level; + menu = menu->parent, i++) + ; + if (menu == NULL) + errx(1, "reached NULL menu"); - for (item = menu->list; item->next != NULL; item = item->next) - ; + /* find last item in the new menu */ + for (item = menu->list; item->next != NULL; item = item->next) + ; - item->next = curritem; + prevmenu = menu; + item->next = curritem; + curritem->prev = item; + } else if (level == prevmenu->level) { /* item is a continuation of current menu */ + /* find last item in the previous menu */ + for (item = prevmenu->list; item->next != NULL; item = item->next) + ; - curritem->prev = item; - curritem->next = NULL; + item->next = curritem; + curritem->prev = item; + } else if (level > prevmenu->level) { /* item begins a new menu */ + menu = allocmenu(prevmenu, curritem, level); - prevmenu = menu; - } else if (level == prevmenu->level) { /* item is a continuation of current menu */ - for (item = prevmenu->list; item->next != NULL; item = item->next) - ; - item->next = curritem; + /* find last item in the previous menu */ + for (item = prevmenu->list; item->next != NULL; item = item->next) + ; - curritem->prev = item; - curritem->next = NULL; + prevmenu = menu; + menu->caller = item; + item->submenu = menu; + curritem->prev = NULL; + } - } else if (level > prevmenu->level) { /* item begins a new menu */ - menu = allocmenu(prevmenu, curritem, level); + return rootmenu; +} - for (item = prevmenu->list; item->next != NULL; item = item->next) - ; +/* create menus and items from the stdin */ +static struct Menu * +parsestdin(void) +{ + struct Menu *rootmenu; + char *s, buf[BUFSIZ]; + char *label, *output; + unsigned level = 0; - item->submenu = menu; - menu->caller = item; + while (fgets(buf, BUFSIZ, stdin) != NULL) { + /* get the indentation level */ + level = strspn(buf, "\t"); - curritem->prev = NULL; - curritem->next = NULL; + /* get the label */ + s = level + buf; + label = strtok(s, "\t\n"); - prevmenu = menu; + /* get the output */ + output = strtok(NULL, "\n"); + if (output == NULL) { + output = label; + } else { + while (*output == '\t') + output++; } + + rootmenu = buildmenutree(level, label, output); } return rootmenu; -- 2.20.1