root/src/noit_console_state.c

Revision 4cdbcdb30a697d3227b7be9d7deed71656552d22, 8.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 7 years ago)

partial match works. apply command works, needs range expansion which I'll lean on pcre for. Didn't have pcre on the plain -- so here we are.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include "eventer/eventer.h"
9 #include "utils/noit_log.h"
10 #include "utils/noit_hash.h"
11 #include "noit_listener.h"
12 #include "noit_console.h"
13 #include "noit_tokenizer.h"
14
15 cmd_info_t console_command_exit = {
16   "exit", noit_console_state_pop, NULL, NULL
17 };
18
19 static char *
20 noit_console_state_prompt(EditLine *el) {
21   static char *tl = "noit# ";
22   return tl;
23 }
24
25 static char *
26 apply_replace(const char *src, const char *name, const char *value) {
27   char *result, *cp;
28   const char *nextpat, *searchstart;
29   char pat[256];
30   int maxlen, patlen, vlen, slen;
31   snprintf(pat, sizeof(pat), "{%s}", name);
32   patlen = strlen(pat);
33   vlen = strlen(value);
34   slen = strlen(src);
35   /* Worst case is just a stream of replacements. */
36   maxlen = (slen / patlen) * vlen + (slen % patlen) + 1;
37   cp = result = malloc(maxlen);
38   searchstart = src;
39   while((nextpat = strstr(searchstart, pat)) != NULL) {
40     memcpy(cp, searchstart, nextpat - searchstart); /* pull the prefix */
41     cp += nextpat - searchstart;                    /* advance destination */
42     memcpy(cp, value, vlen);                        /* copy replacement */
43     cp += vlen;                                     /* advance destination */
44     searchstart += patlen;                          /* set new searchstart */
45   }
46   /* Pick up the trailer (plus '\0') */
47   memcpy(cp, searchstart, strlen(searchstart)+1);
48   return result;
49 }
50 static int
51 expand_range(const char *range, char ***set) {
52   int count;
53   /* (full:)?(\d+).(\d+)\.(\d+)(?:\.(\d+))?(?:/(\d+))? */
54   /* (\d+)(?:,(\d+))?\.\.(\d+) */
55 /* FIXME: TEST! */
56   *set = malloc(10 * sizeof(*set));
57   for(count=0;count<10;count++) {
58     (*set)[count] = strdup("00-test-expand");
59     snprintf((*set)[count], 3, "%02d", count);
60     (*set)[count][2] = '-';
61   }
62
63   return count;
64 }
65 int
66 noit_console_generic_apply(noit_console_closure_t ncct,
67                            int argc, char **argv,
68                            noit_console_state_t *dstate,
69                            void *closure) {
70   int i, j, count;
71   char *name, *range;
72   char **nargv, **expanded;
73   int problems = 0;
74   if(argc < 3) {
75     nc_printf(ncct, "apply <name> <range> cmd ...\n");
76     return -1;
77   }
78   name = argv[0];
79   range = argv[1];
80   argc -= 2;
81   argv += 2;
82
83   count = expand_range(range, &expanded);
84   if(!count) {
85     nc_printf(ncct, "apply error: '%s' range produced nothing\n", range);
86     return -1;
87   }
88   if(count < 0) {
89     nc_printf(ncct, "apply error: '%s' range would produce %d items.\n",
90               range, count);
91     return -1;
92   }
93   nargv = malloc(argc * sizeof(*nargv));
94   for(i=0; i<count; i++) {
95     for(j=0; j<argc; j++) nargv[j] = apply_replace(argv[j], name, expanded[i]);
96     if(noit_console_state_do(ncct, argc, nargv)) problems = -1;
97     for(j=0; j<argc; j++) free(nargv[j]);
98     free(expanded[i]);
99   }
100   free(nargv);
101   free(expanded);
102   return problems;
103 }
104
105 int
106 noit_console_state_delegate(noit_console_closure_t ncct,
107                             int argc, char **argv,
108                             noit_console_state_t *dstate,
109                             void *closure) {
110   noit_console_state_stack_t tmps = { 0 };
111
112   if(argc == 0) {
113     nc_printf(ncct, "arguments expected\n");
114     /* XXX: noit_console_render_help(dstate); */
115     return -1;
116   }
117   if(!dstate) {
118     nc_printf(ncct, "internal error: no delegate state\n");
119     return -1;
120   }
121   tmps.state = dstate;
122   return _noit_console_state_do(ncct, &tmps, argc, argv);
123 }
124
125 int
126 _noit_console_state_do(noit_console_closure_t ncct,
127                        noit_console_state_stack_t *stack,
128                        int argc, char **argv) {
129   noit_skiplist_node *next, *amb = NULL;
130   cmd_info_t *cmd;
131
132   if(!argc) {
133     nc_printf(ncct, "arguments expected\n");
134     return -1;
135   }
136   cmd = noit_skiplist_find_neighbors(&stack->state->cmds, argv[0],
137                                      NULL, NULL, &next);
138   if(!cmd) {
139     int ambiguous = 0;
140     if(next) {
141       cmd_info_t *pcmd = NULL;
142       cmd = next->data;
143       amb = next;
144       noit_skiplist_next(&stack->state->cmds, &amb);
145       if(amb) pcmd = amb->data;
146       /* So cmd is the next in line... pcmd is the one after that.
147        * If they both strncasecmp to 0, we're ambiguous,
148        *    neither, then we're not found.
149        *    only cmd, then we've found a partial, unambiguous.
150        */
151       if(strncasecmp(cmd->name, argv[0], strlen(argv[0])) == 0) {
152         if(pcmd && strncasecmp(pcmd->name, argv[0], strlen(argv[0])) == 0) {
153           cmd = NULL;
154           ambiguous = 1;
155         }
156       }
157       else
158         cmd = NULL;
159     }
160     if(!cmd) {
161       if(ambiguous) {
162         nc_printf(ncct, "Ambiguous command: '%s'\n", argv[0]);
163         amb = next;
164         for(amb = next; amb; noit_skiplist_next(&stack->state->cmds, &amb)) {
165           cmd = amb->data;
166           if(strncasecmp(cmd->name, argv[0], strlen(argv[0])) == 0)
167             nc_printf(ncct, "\t%s\n", cmd->name);
168           else
169             break;
170         }
171       }
172       else
173         nc_printf(ncct, "No such command: '%s'\n", argv[0]);
174       return -1;
175     }
176   }
177   return cmd->func(ncct, argc-1, argv+1, cmd->dstate, cmd->closure);
178 }
179 int
180 noit_console_state_do(noit_console_closure_t ncct, int argc, char **argv) {
181   return _noit_console_state_do(ncct, ncct->state_stack, argc, argv);
182 }
183
184 int cmd_info_comparek(const void *akv, const void *bv) {
185   char *ak = (char *)akv;
186   cmd_info_t *b = (cmd_info_t *)bv;
187   return strcasecmp(ak, b->name);
188 }
189 int cmd_info_compare(const void *av, const void *bv) {
190   cmd_info_t *a = (cmd_info_t *)av;
191   cmd_info_t *b = (cmd_info_t *)bv;
192   return strcasecmp(a->name, b->name);
193 }
194
195 noit_console_state_t *
196 noit_console_state_alloc(void) {
197   noit_console_state_t *s;
198   s = calloc(1, sizeof(*s));
199   noit_skiplist_init(&s->cmds);
200   noit_skiplist_set_compare(&s->cmds, cmd_info_compare, cmd_info_comparek);
201   noit_console_state_add_cmd(s,
202       NCSCMD("apply", noit_console_generic_apply, NULL, NULL));
203   return s;
204 }
205
206 int
207 noit_console_state_add_cmd(noit_console_state_t *state,
208                            cmd_info_t *cmd) {
209   return (noit_skiplist_insert(&state->cmds, cmd) != NULL);
210 }
211
212 cmd_info_t *
213 noit_console_state_get_cmd(noit_console_state_t *state,
214                            const char *name) {
215   cmd_info_t *cmd;
216   cmd = noit_skiplist_find(&state->cmds, name, NULL);
217   return cmd;
218 }
219
220 noit_console_state_t *
221 noit_console_state_build(console_prompt_func_t promptf, cmd_info_t **clist,
222                          state_free_func_t sfreef) {
223   noit_console_state_t *state;
224   state = noit_console_state_alloc();
225   state->console_prompt_function = promptf;
226   while(*clist) {
227     noit_skiplist_insert(&state->cmds, *clist);
228     clist++;
229   }
230   state->statefree = sfreef;
231   return state;
232 }
233
234 cmd_info_t *NCSCMD(const char *name, console_cmd_func_t func,
235                    noit_console_state_t *dstate, void *closure) {
236   cmd_info_t *cmd;
237   cmd = calloc(1, sizeof(*cmd));
238   cmd->name = strdup(name);
239   cmd->func = func;
240   cmd->dstate = dstate;
241   cmd->closure = closure;
242   return cmd;
243 }
244
245 noit_console_state_t *
246 noit_console_state_initial() {
247   static noit_console_state_t *_top_level_state = NULL;
248   if(!_top_level_state) {
249     static noit_console_state_t *show_state;
250     _top_level_state = noit_console_state_alloc();
251     noit_console_state_add_cmd(_top_level_state, &console_command_exit);
252     show_state = noit_console_state_alloc();
253     noit_console_state_add_cmd(_top_level_state,
254       NCSCMD("show", noit_console_state_delegate, show_state, NULL));
255   }
256   return _top_level_state;
257 }
258
259 void
260 noit_console_state_push_state(noit_console_closure_t ncct,
261                               noit_console_state_t *state) {
262   noit_console_state_stack_t *stack;
263   stack = calloc(1, sizeof(*stack));
264   stack->last = ncct->state_stack;
265   stack->state = state;
266   ncct->state_stack = stack;
267 }
268
269 int
270 noit_console_state_pop(noit_console_closure_t ncct, int argc, char **argv,
271                        noit_console_state_t *dstate, void *unused) {
272   noit_console_state_stack_t *current;
273
274   if(argc) {
275     nc_printf(ncct, "no arguments allowed to this command.\n");
276     return -1;
277   }
278   if(!ncct->state_stack || !ncct->state_stack->last) {
279     ncct->wants_shutdown = 1;
280     return 0;
281   }
282
283   current = ncct->state_stack;
284   ncct->state_stack = current->last;
285   current->last = NULL;
286   if(current->state->statefree) current->state->statefree(current->state);
287   free(current);
288   noit_console_state_init(ncct);
289   return 0;
290 }
291
292 int
293 noit_console_state_init(noit_console_closure_t ncct) {
294   if(ncct->el) {
295     console_prompt_func_t f;
296     f = ncct->state_stack->state->console_prompt_function;
297     el_set(ncct->el, EL_PROMPT, f ? f : noit_console_state_prompt);
298   }
299   return 0;
300 }
Note: See TracBrowser for help on using the browser.