Simplifying parsing and data structure building
• 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.
This commit is contained in:
parent
15dfafdfb1
commit
a5ddd2cd22
107
xmenu.c
107
xmenu.c
|
@ -73,6 +73,7 @@ static void setupdc(void);
|
||||||
static void calcgeom(void);
|
static void calcgeom(void);
|
||||||
static struct Item *allocitem(const char *label, const char *output);
|
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 *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 struct Menu *parsestdin(void);
|
||||||
static void calcmenu(struct Menu *menu);
|
static void calcmenu(struct Menu *menu);
|
||||||
static void grabpointer(void);
|
static void grabpointer(void);
|
||||||
|
@ -251,7 +252,7 @@ allocitem(const char *label, const char *output)
|
||||||
|
|
||||||
if ((item = malloc(sizeof *item)) == NULL)
|
if ((item = malloc(sizeof *item)) == NULL)
|
||||||
err(1, "malloc");
|
err(1, "malloc");
|
||||||
if (*label == '\0') {
|
if (label == NULL) {
|
||||||
item->label = NULL;
|
item->label = NULL;
|
||||||
item->output = NULL;
|
item->output = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -310,96 +311,92 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create menus and items from the stdin */
|
/* build the menu tree */
|
||||||
static struct Menu *
|
static struct Menu *
|
||||||
parsestdin(void)
|
buildmenutree(unsigned level, const char *label, const char *output)
|
||||||
{
|
{
|
||||||
char *s, buf[BUFSIZ];
|
static struct Menu *prevmenu = NULL; /* menu the previous item was added to */
|
||||||
char *label, *output;
|
static struct Menu *rootmenu = NULL; /* menu to be returned */
|
||||||
unsigned level = 0;
|
|
||||||
unsigned i;
|
|
||||||
struct Item *curritem = NULL; /* item currently being read */
|
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 Item *item; /* dummy item for loops */
|
||||||
struct Menu *menu; /* dummy menu for loops */
|
struct Menu *menu; /* dummy menu for loops */
|
||||||
struct Menu *rootmenu; /* menu to be returned */
|
unsigned i;
|
||||||
|
|
||||||
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';
|
|
||||||
|
|
||||||
|
/* create the item */
|
||||||
curritem = allocitem(label, output);
|
curritem = allocitem(label, output);
|
||||||
|
|
||||||
|
/* put the item in the menu tree */
|
||||||
if (prevmenu == NULL) { /* there is no menu yet */
|
if (prevmenu == NULL) { /* there is no menu yet */
|
||||||
menu = allocmenu(NULL, curritem, level);
|
menu = allocmenu(NULL, curritem, level);
|
||||||
rootmenu = menu;
|
rootmenu = menu;
|
||||||
prevmenu = menu;
|
prevmenu = menu;
|
||||||
curritem->prev = NULL;
|
curritem->prev = NULL;
|
||||||
curritem->next = NULL;
|
} else if (level < prevmenu->level) { /* item is continuation of a parent menu */
|
||||||
} 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;
|
for (menu = prevmenu, i = level;
|
||||||
menu != NULL && i < prevmenu->level;
|
menu != NULL && i != prevmenu->level;
|
||||||
menu = menu->parent, i++)
|
menu = menu->parent, i++)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (menu == NULL)
|
if (menu == NULL)
|
||||||
errx(1, "reached NULL menu");
|
errx(1, "reached NULL menu");
|
||||||
|
|
||||||
|
/* find last item in the new menu */
|
||||||
for (item = menu->list; item->next != NULL; item = item->next)
|
for (item = menu->list; item->next != NULL; item = item->next)
|
||||||
;
|
;
|
||||||
|
|
||||||
item->next = curritem;
|
|
||||||
|
|
||||||
curritem->prev = item;
|
|
||||||
curritem->next = NULL;
|
|
||||||
|
|
||||||
prevmenu = menu;
|
prevmenu = menu;
|
||||||
|
item->next = curritem;
|
||||||
|
curritem->prev = item;
|
||||||
} else if (level == prevmenu->level) { /* item is a continuation of current menu */
|
} 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)
|
for (item = prevmenu->list; item->next != NULL; item = item->next)
|
||||||
;
|
;
|
||||||
|
|
||||||
item->next = curritem;
|
item->next = curritem;
|
||||||
|
|
||||||
curritem->prev = item;
|
curritem->prev = item;
|
||||||
curritem->next = NULL;
|
|
||||||
|
|
||||||
} else if (level > prevmenu->level) { /* item begins a new menu */
|
} else if (level > prevmenu->level) { /* item begins a new menu */
|
||||||
menu = allocmenu(prevmenu, curritem, level);
|
menu = allocmenu(prevmenu, curritem, level);
|
||||||
|
|
||||||
|
/* find last item in the previous menu */
|
||||||
for (item = prevmenu->list; item->next != NULL; item = item->next)
|
for (item = prevmenu->list; item->next != NULL; item = item->next)
|
||||||
;
|
;
|
||||||
|
|
||||||
item->submenu = menu;
|
|
||||||
menu->caller = item;
|
|
||||||
|
|
||||||
curritem->prev = NULL;
|
|
||||||
curritem->next = NULL;
|
|
||||||
|
|
||||||
prevmenu = menu;
|
prevmenu = menu;
|
||||||
|
menu->caller = item;
|
||||||
|
item->submenu = menu;
|
||||||
|
curritem->prev = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rootmenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
while (fgets(buf, BUFSIZ, stdin) != NULL) {
|
||||||
|
/* get the indentation level */
|
||||||
|
level = strspn(buf, "\t");
|
||||||
|
|
||||||
|
/* get the label */
|
||||||
|
s = level + buf;
|
||||||
|
label = strtok(s, "\t\n");
|
||||||
|
|
||||||
|
/* get the output */
|
||||||
|
output = strtok(NULL, "\n");
|
||||||
|
if (output == NULL) {
|
||||||
|
output = label;
|
||||||
|
} else {
|
||||||
|
while (*output == '\t')
|
||||||
|
output++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rootmenu = buildmenutree(level, label, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootmenu;
|
return rootmenu;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user