diff options
Diffstat (limited to 'src/list.c')
-rw-r--r-- | src/list.c | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..2652bda --- /dev/null +++ b/src/list.c @@ -0,0 +1,675 @@ +/* + * list.c -- list utility functions. + * + * Copyright (C) 1998 by Massimiliano Ghilardi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> + +#include "defines.h" +#include "main.h" +#include "feature/regex.h" +#include "utils.h" +#include "cmd2.h" +#include "tty.h" +#include "eval.h" + +/* + * compare two times, return -1 if t1 < t2, 1 if t1 > t2, 0 if t1 == t2 + */ +int cmp_vtime(vtime *t1, vtime *t2) +{ + int i; + i = t1->tv_sec < t2->tv_sec ? -1 : t1->tv_sec > t2->tv_sec ? 1 : 0; + if (!i) + i = t1->tv_usec < t2->tv_usec ? -1 : t1->tv_usec > t2->tv_usec ? 1 : 0; + return i; +} + +/* + * add t2 to t1 (i.e. t1 += t2) + */ +void add_vtime(vtime *t1, vtime *t2) +{ + t1->tv_sec += t2->tv_sec; + if ((t1->tv_usec += t2->tv_usec) >= uSEC_PER_SEC) { + t1->tv_sec += t1->tv_usec / uSEC_PER_SEC; + t1->tv_usec %= uSEC_PER_SEC; + } +} + +/* + * Return t1 - t2, in milliseconds + */ +long diff_vtime(vtime *t1, vtime *t2) +{ + return (t1->tv_sec - t2->tv_sec) * mSEC_PER_SEC + + (t1->tv_usec - t2->tv_usec) / uSEC_PER_mSEC; +} + +int rev_sort(defnode *node1, defnode *node2) +{ + return -1; +} + +/* + * standard ASCII comparison between nodes + */ +int ascii_sort(defnode *node1, defnode *node2) +{ + return strcmp(node1->sortfield, node2->sortfield); +} + +int rev_ascii_sort(defnode *node1, defnode *node2) +{ + return strcmp(node2->sortfield, node1->sortfield); +} + + +/* + * comparison between times of execution of nodes + * (return -1 if node1->when < node2->when) + */ +int time_sort(defnode *node1, defnode *node2) +{ + return cmp_vtime(&((delaynode *)node1)->when, &((delaynode *)node2)->when); +} + +/* + * reverse comparison between times of execution of nodes + * (return -1 if node1->when > node2->when) + */ +int rev_time_sort(defnode *node1, defnode *node2) +{ + return cmp_vtime(&((delaynode *)node2)->when, &((delaynode *)node1)->when); +} + +/* + * compute the hash value of a name + */ +int hash(char *name, int optlen) +{ + int h = 0, i = 0; + if (optlen < 0) + optlen = strlen(name); + while (optlen-- > 0) { + h += ((*name++) ^ i) << i; + if (++i == LOG_MAX_HASH) + i = 0; + } + return (h + (h >> LOG_MAX_HASH) + (h >> (2*LOG_MAX_HASH))) & (MAX_HASH-1); +} + +/* + * generic list node adding routine + */ +void add_node(defnode *newnode, defnode **base, function_sort sort) +{ + while((*base) && (!sort || (*sort)(newnode, *base) > 0)) + base = &(*base)->next; + newnode->next = *base; + *base = newnode; +} + +static void add_sortednode(sortednode *newnode, sortednode **base, function_sort sort) +{ + while((*base) && (!sort || (*sort)((defnode *)newnode, (defnode *)*base) > 0)) + base = &(*base)->snext; + newnode->snext = *base; + *base = newnode; +} + +void reverse_list(defnode **base) +{ + defnode *node = *base, *list = NULL, *tmp; + while (node) { + tmp = node->next; + node->next = list; + list = node; + node = tmp; + } + *base = list; +} + +void reverse_sortedlist(sortednode **base) +{ + sortednode *node = *base, *list = NULL, *tmp; + while (node) { + tmp = node->snext; + node->snext = list; + list = node; + node = tmp; + } + *base = list; +} + +static sortednode **selflookup_sortednode(sortednode *self, sortednode **base) +{ + sortednode **p = base; + while (*p && *p != self) + p = &(*p)->snext; + if (!*p) { + PRINTF("#internal error, selflookup_sortednode(\"%s\") failed!\n", self->sortfield); + error = INTERNAL_ERROR; + } + return p; +} + +/* + * add a node to the alias list + */ +void add_aliasnode(char *name, char *subst) +{ + aliasnode *new = (aliasnode*)malloc(sizeof(aliasnode)); + if (!new) { + errmsg("malloc"); + return; + } + + new->group = NULL; + new->active = 1; + new->name = my_strdup(name); + new->subst = my_strdup(subst); + if ((name && !new->name) || (subst && !new->subst)) { + errmsg("malloc"); + if (new->name) + free(new->name); + if (new->subst) + free(new->subst); + free(new); + return; + } + add_node((defnode*)new, (defnode**)&aliases[hash(name,-1)], rev_sort); + add_sortednode((sortednode*)new, (sortednode**)&sortedaliases, rev_ascii_sort); +} + +/* + * add a node to the marker list + */ +void add_marknode(char *pattern, int attrcode, char mbeg, char wild) +{ + marknode **p, *new = (marknode*)malloc(sizeof(marknode)); + int i; + if (!new) { + errmsg("malloc"); + return; + } + new->pattern = my_strdup(pattern); + new->attrcode = attrcode; + new->start = new->end = NULL; + new->mbeg = mbeg; + new->wild = wild; + if (!new->pattern) { + errmsg("malloc"); + free(new); + return; + } +#ifdef DO_SORT + add_node((defnode*)new, (defnode**)&markers, ascii_sort); +#else + for (p=&markers, i=1; *p && (a_nice==0 || i<a_nice); p = &(*p)->next, i++) + ; + new->next = *p; + *p = new; +#endif +} + +/* + * add a node to the action list + */ +void add_actionnode(char *pattern, char *command, char *label, int active, int type, void *vregexp) +{ + actionnode **p, *new = (actionnode*)malloc(sizeof(actionnode)); + int i; + if (!new) { + errmsg("malloc"); + return; + } + + new->group = NULL; + new->pattern = my_strdup(pattern); + new->command = my_strdup(command); + new->label = my_strdup(label); + new->active = active; + new->type = type; +#ifdef USE_REGEXP + new->regexp = vregexp; +#endif + if (!new->pattern || (command && !new->command) || (label && !new->label)) { + errmsg("malloc"); + if (new->pattern) + free(new->pattern); + if (new->command) + free(new->command); + if (new->label) + free(new->label); + free(new); + return; + } +#ifdef DO_SORT + add_node((defnode*)new, (defnode**)&actions, ascii_sort); +#else + for (p=&actions, i=1; *p && (a_nice==0 || i<a_nice); p = &(*p)->next, i++) + ; + new->next = *p; + *p = new; +#endif +} + +/* + * add a node to the prompt list + */ +void add_promptnode(char *pattern, char *command, char *label, int active, int type, void *vregexp) +{ + promptnode **p, *new = (promptnode*)malloc(sizeof(promptnode)); + int i; + if (!new) { + errmsg("malloc"); + return; + } + + new->pattern = my_strdup(pattern); + new->command = my_strdup(command); + new->label = my_strdup(label); + new->active = active; + new->type = type; +#ifdef USE_REGEXP + new->regexp = vregexp; +#endif + if (!new->pattern || (command && !new->command) || (label && !new->label)) { + errmsg("malloc"); + if (new->pattern) + free(new->pattern); + if (new->command) + free(new->command); + if (new->label) + free(new->label); + free(new); + return; + } +#ifdef DO_SORT + add_node((defnode*)new, (defnode**)&prompts, ascii_sort); +#else + for (p=&prompts, i=1; *p && (a_nice==0 || i<a_nice); p = &(*p)->next, i++) + ; + new->next = *p; + *p = new; +#endif +} + +/* + * add a node to the keydef list + */ +void add_keynode(char *name, char *sequence, int seqlen, function_str funct, char *call_data) +{ + keynode *new = (keynode*)malloc(sizeof(keynode)); + if (!new) { + errmsg("malloc"); + return; + } + new->name = my_strdup(name); + if (!seqlen) seqlen = strlen(sequence); + new->sequence = (char *)malloc(seqlen + 1); + memmove(new->sequence, sequence, seqlen); + new->seqlen = seqlen; + new->funct = funct; + new->call_data = my_strdup(call_data); + if (!new->name || !new->sequence || (call_data && !new->call_data)) { + errmsg("malloc"); + if (new->name) + free(new->name); + if (new->sequence) + free(new->sequence); + if (new->call_data) + free(new->call_data); + free(new); + return; + } + add_node((defnode*)new, (defnode**)&keydefs, ascii_sort); +} + +/* + * add a node to the delayed command list + * is_dead == 1 means when < now (and so cannot be executed anymore) + */ +delaynode *add_delaynode(char *name, char *command, vtime *when, int is_dead) +{ + delaynode *new = (delaynode*)malloc(sizeof(delaynode)); + if (!new) { + errmsg("malloc"); + return NULL; + } + new->name = my_strdup(name); + new->command = my_strdup(command); + if (!new->name || (command && !new->command)) { + errmsg("malloc"); + if (new->name) + free(new->name); + if (new->command) + free(new->command); + free(new); + return NULL; + } + + new->when.tv_sec = when->tv_sec; + new->when.tv_usec = when->tv_usec; + if (is_dead) + add_node((defnode*)new, (defnode**)&dead_delays, rev_time_sort); + else + add_node((defnode*)new, (defnode**)&delays, time_sort); + + return new; +} + +/* + * add a node to named variables list + * + * do NOT allocate a ptr! + */ +varnode *add_varnode(char *name, int type) +{ + varnode *new; + int m, n; + + if (type) + type = 1; + + if (num_named_vars[type] >= max_named_vars) { + /* we are running low on var pointers. try to enlarge */ + m = NUMTOT + max_named_vars; + n = NUMTOT + max_named_vars * 2; + if (n < 0) { + /* overflow */ + print_error(error=OUT_OF_VAR_SPACE_ERROR); + return NULL; + } + else { + vars *newvar; + if ((newvar = (vars *)realloc(var, n*sizeof(vars) ))) + ; + else if ((newvar = (vars *)malloc( n*sizeof(vars) ))) { + memmove(newvar, var, m * sizeof(vars)); + free((void *)var); + } else { + errmsg("malloc"); + return NULL; + } + var = newvar; + max_named_vars += n-m; + memzero(var + m, (n-m)*sizeof(vars)); + } + } + + new = (varnode*)malloc(sizeof(varnode)); + if (!new) { + errmsg("malloc"); + return NULL; + } + new->name = my_strdup(name); + if (name && !new->name) { + errmsg("malloc"); + free(new); + return NULL; + } + new->num = 0; + new->str = (ptr)0; + new->index = m = NUMPARAM + num_named_vars[type]; + + if (type) + VAR[m].str = &new->str; + else + VAR[m].num = &new->num; + num_named_vars[type]++; + + add_node((defnode*)new, (defnode**)&named_vars[type][hash(name,-1)], rev_sort); + add_sortednode((sortednode*)new, (sortednode**)&sortednamed_vars[type], rev_ascii_sort); + return new; +} + +/* + * look up an alias node by name: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +aliasnode **lookup_alias(char *name) +{ + aliasnode **p = &aliases[hash(name,-1)]; + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * look up an action node by label: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +actionnode **lookup_action(char *label) +{ + actionnode **p = &actions; + while (*p && strcmp(label, (*p)->label)) + p = &(*p)->next; + return p; +} + +/* + * look up an action node by pattern: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +actionnode **lookup_action_pattern(char *pattern) +{ + actionnode **p = &actions; + while (*p && strcmp(pattern, (*p)->pattern)) + p = &(*p)->next; + return p; +} + +/* + * look up a prompt node by label: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +actionnode **lookup_prompt(char *label) +{ + promptnode **p = &prompts; + while (*p && strcmp(label, (*p)->label)) + p = &(*p)->next; + return p; +} + +/* + * look up an marker node by pattern: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +marknode **lookup_marker(char *pattern, char mbeg) +{ + marknode **p = &markers; + while (*p && (mbeg != (*p)->mbeg || strcmp(pattern, (*p)->pattern))) + p = &(*p)->next; + return p; +} + +/* + * look up a key node by name: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +keynode **lookup_key(char *name) +{ + keynode **p = &keydefs; + + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * look up a delayed command node by label: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +delaynode **lookup_delay(char *name, int is_dead) +{ + delaynode **p = (is_dead ? &dead_delays : &delays); + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * look up a named variable node by name: + * return pointer to pointer to node or a pointer to NULL if nothing found + */ +varnode **lookup_varnode(char *name, int type) +{ + varnode **p = &named_vars[type][hash(name,-1)]; + while (*p && strcmp(name, (*p)->name)) + p = &(*p)->next; + return p; +} + +/* + * delete an alias node, given a pointer to its precessor's pointer + */ +void delete_aliasnode(aliasnode **base) +{ + aliasnode *p = *base; + *base = p->next; + if (*(base = (aliasnode**)selflookup_sortednode + ((sortednode*)p, (sortednode**)&sortedaliases))) + *base = p->snext; + else + return; + if (p->name) free(p->name); + if (p->subst) free(p->subst); + free((void*)p); +} + +/* + * delete an action node, given a pointer to its precessor's pointer + */ +void delete_actionnode(actionnode **base) +{ + actionnode *p = *base; + if (p->pattern) free(p->pattern); + if (p->command) free(p->command); + if (p->label) free(p->label); +#ifdef USE_REGEXP + if (p->type == ACTION_REGEXP && p->regexp) { + regfree((regex_t *)p->regexp); + free(p->regexp); + } +#endif + *base = p->next; + free((void*)p); +} + +/* + * delete an prompt node, given a pointer to its precessor's pointer + */ +void delete_promptnode(promptnode **base) +{ + promptnode *p = *base; + if (p->pattern) free(p->pattern); + if (p->command) free(p->command); + if (p->label) free(p->label); +#ifdef USE_REGEXP + if (p->type == ACTION_REGEXP && p->regexp) { + regfree((regex_t *)p->regexp); + free(p->regexp); + } +#endif + *base = p->next; + free((void*)p); +} + +/* + * delete an marker node, given a pointer to its precessor's pointer + */ +void delete_marknode(marknode **base) +{ + marknode *p = *base; + if (p->pattern) free(p->pattern); + *base = p->next; + free((void*)p); +} + +/* + * delete a keydef node, given a pointer to its precessor's pointer + */ +void delete_keynode(keynode **base) +{ + keynode *p = *base; + if (p->name) free(p->name); + if (p->sequence) free(p->sequence); + if (p->call_data) free(p->call_data); + *base = p->next; + free((void*)p); +} + +/* + * delete a delayed command node, given a pointer to its precessor's pointer + */ +void delete_delaynode(delaynode **base) +{ + delaynode *p = *base; + if (p->name) free(p->name); + if (p->command) free(p->command); + *base = p->next; + free((void*)p); +} + +/* + * delete a named variable node, given a pointer to its precessor's pointer + */ +void delete_varnode(varnode **base, int type) +{ + varnode *p = *base; + int idx = p->index, i, n; + + *base = p->next; + if (*(base = (varnode**)selflookup_sortednode + ((sortednode*)p, (sortednode**)&sortednamed_vars[type]))) + *base = p->snext; + else + return; + if (p->name) free(p->name); + if (type && p->str) ptrdel(p->str); + free((void*)p); + + i = NUMPARAM + --num_named_vars[type]; + + if (idx == i) + return; + + /* now I must fill the hole in var[idx].*** */ + + for (n = 0; n < MAX_HASH; n++) + for (p = named_vars[type][n]; p; p = p->next) + if (p->index == i) { + n = MAX_HASH; + break; + } + + if (!p) { /* should NEVER happen */ + print_error(error=UNDEFINED_VARIABLE_ERROR); + return; + } + + p->index = idx; + + if (type) { + VAR[idx].str = &p->str; + VAR[ i ].str = NULL; + } else { + VAR[idx].num = &p->num; + VAR[ i ].num = NULL; + } +} |