Commit 9a1d162e 9a1d162e76c05616bc4f1fedc98825f5ace01aed by Sergey Poznyakoff

Rewritten mail variables support using list_t.

(util_find_entry,util_help): Rewritten to work with opaque data
tables
(util_command_list): New function
(var_iterate_first,var_iterate_next,var_iterate_end): New
functions
(util_folder_path): Convert folder to full name
1 parent 8e8f1a17
Showing 1 changed file with 215 additions and 157 deletions
...@@ -34,48 +34,7 @@ ...@@ -34,48 +34,7 @@
34 #endif 34 #endif
35 #include <mu_asprintf.h> 35 #include <mu_asprintf.h>
36 36
37 typedef struct _node { 37 list_t environment = NULL;
38 /* for the msglist expander */
39 int data;
40 /* for the environment table */
41 struct mail_env_entry env_entry;
42 struct _node *next;
43 } node;
44
45 static node *environment = NULL;
46
47 /*
48 * add a new node to the list
49 */
50 static node *
51 util_ll_add (node *c, int data)
52 {
53 c->next = xmalloc (sizeof (node));
54 c->data = data;
55 c->next->env_entry.var = NULL;
56 c->next->env_entry.set = 0;
57 c->next->env_entry.value.number = 0;
58 c->next->next = NULL;
59 return c->next;
60 }
61
62 /*
63 * free a linked list
64 * Unused so far
65 */
66 #if 0
67 static void
68 util_ll_free (node *c)
69 {
70 node *t = c;
71 while (t != NULL)
72 {
73 c = t;
74 t = t->next;
75 free (c);
76 }
77 }
78 #endif
79 38
80 /* 39 /*
81 * expands command into its command and arguments, then runs command 40 * expands command into its command and arguments, then runs command
...@@ -124,7 +83,7 @@ util_do_command (const char *c, ...) ...@@ -124,7 +83,7 @@ util_do_command (const char *c, ...)
124 83
125 if (argcv_get (cmd, delim, NULL, &argc, &argv) == 0 && argc > 0) 84 if (argcv_get (cmd, delim, NULL, &argc, &argv) == 0 && argc > 0)
126 { 85 {
127 struct mail_command_entry entry; 86 struct mail_command_entry *entry;
128 char *p; 87 char *p;
129 88
130 /* Special case: a number alone implies "print" */ 89 /* Special case: a number alone implies "print" */
...@@ -136,10 +95,9 @@ util_do_command (const char *c, ...) ...@@ -136,10 +95,9 @@ util_do_command (const char *c, ...)
136 free (p); 95 free (p);
137 } 96 }
138 97
139 entry = util_find_entry (mail_command_table, argv[0]); 98 command = util_command_get (argv[0]);
140 command = entry.func;
141 /* Make sure we are not in any if/else */ 99 /* Make sure we are not in any if/else */
142 exec = !(if_cond () == 0 && (entry.flags & EF_FLOW) == 0); 100 exec = !(if_cond () == 0 && (entry->flags & EF_FLOW) == 0);
143 } 101 }
144 free (cmd); 102 free (cmd);
145 } 103 }
...@@ -248,32 +206,109 @@ util_range_msg (size_t low, size_t high, int flags, ...@@ -248,32 +206,109 @@ util_range_msg (size_t low, size_t high, int flags,
248 function_t * 206 function_t *
249 util_command_get (const char *cmd) 207 util_command_get (const char *cmd)
250 { 208 {
251 struct mail_command_entry entry = util_find_entry (mail_command_table, cmd); 209 const struct mail_command_entry *entry = mail_find_command (cmd);
252 return entry.func; 210 return entry ? entry->func : NULL;
253 } 211 }
254 212
255 /* 213 /*
256 * returns the mail_command_entry structure for the command matching cmd 214 * returns the mail_command_entry structure for the command matching cmd
257 */ 215 */
258 struct mail_command_entry 216 void *
259 util_find_entry (const struct mail_command_entry *table, const char *cmd) 217 util_find_entry (void *table, size_t nmemb, size_t size, const char *cmd)
260 { 218 {
261 int i = 0, ll = 0, sl = 0; 219 int i;
262 int len = strlen (cmd); 220 int len = strlen (cmd);
221 char *p;
222
223 for (p = table, i = 0; i < nmemb; i++, p += size)
224 {
225 struct mail_command *cp = (struct mail_command *)p;
226 int ll = strlen (cp->longname);
227 int sl = strlen (cp->shortname);
228
229 if (sl > ll && !strncmp (cp->shortname, cmd, sl))
230 return p;
231 else if (sl == len && !strcmp (cp->shortname, cmd))
232 return p;
233 else if (sl < len && !strncmp (cp->longname, cmd, len))
234 return p;
235 }
236 return NULL;
237 }
238
239 int
240 util_help (void *table, size_t nmemb, size_t size, const char *word)
241 {
242 if (!word)
243 {
244 int i = 0;
245 FILE *out = stdout;
246 char *p;
247
248 if (util_getenv (NULL, "crt", Mail_env_boolean, 0) == 0)
249 out = popen (getenv ("PAGER"), "w");
250
251
252 for (p = table, i = 0; i < nmemb; i++, p += size)
253 {
254 struct mail_command *cp = (struct mail_command *)p;
255 fprintf (out, "%s\n", cp->synopsis);
256 }
257
258 if (out != stdout)
259 pclose (out);
260
261 return 0;
262 }
263 else
264 {
265 int status = 0;
266 struct mail_command *cp = util_find_entry (table, nmemb, size, word);
267 if (cp)
268 fprintf (stdout, "%s\n", cp->synopsis);
269 else
270 {
271 status = 1;
272 fprintf (stdout, _("Unknown command: %s\n"), word);
273 }
274 return status;
275 }
276 return 1;
277 }
263 278
264 while (table[i].shortname != 0) 279 int
280 util_command_list (void *table, size_t nmemb, size_t size)
281 {
282 int i;
283 char *p;
284 int cols = util_getcols ();
285 int pos;
286
287 for (p = table, i = 0; i < nmemb; i++, p += size)
265 { 288 {
266 sl = strlen (table[i].shortname); 289 const char *cmd;
267 ll = strlen (table[i].longname); 290 struct mail_command *cp = (struct mail_command *)p;
268 if (sl > ll && !strncmp (table[i].shortname, cmd, sl)) 291 int len = strlen (cp->longname);
269 return table[i]; 292 if (len < 1)
270 else if (sl == len && !strcmp (table[i].shortname, cmd)) 293 {
271 return table[i]; 294 cmd = cp->shortname;
272 else if (sl < len && !strncmp (table[i].longname, cmd, len)) 295 len = strlen (cmd);
273 return table[i]; 296 }
274 i++; 297 else
298 cmd = cp->longname;
299
300 pos += len + 1;
301
302 if (pos >= cols)
303 {
304 pos = len + 1;
305 fprintf (ofile, "\n%s ", cmd);
306 }
307 else
308 fprintf (ofile, "%s ", cmd);
275 } 309 }
276 return table[i]; 310 fprintf (ofile, "\n");
311 return 0;
277 } 312 }
278 313
279 /* 314 /*
...@@ -426,85 +461,141 @@ util_getenv (void *ptr, const char *variable, mail_env_data_t type, int warn) ...@@ -426,85 +461,141 @@ util_getenv (void *ptr, const char *variable, mail_env_data_t type, int warn)
426 return 0; 461 return 0;
427 } 462 }
428 463
464 static int
465 env_comp (const void *a, const void *b)
466 {
467 const struct mail_env_entry *epa = a;
468 const struct mail_env_entry *epb = b;
469
470 return strcmp (epa->var, epb->var);
471 }
472
429 /* Find environment entry var. If not found and CREATE is not null, then 473 /* Find environment entry var. If not found and CREATE is not null, then
430 create the (unset and untyped) variable */ 474 create the (unset and untyped) variable */
431 struct mail_env_entry * 475 struct mail_env_entry *
432 util_find_env (const char *variable, int create) 476 util_find_env (const char *var, int create)
433 { 477 {
434 node *ep; 478 struct mail_env_entry entry, *p;
435 /* Annoying, variable "ask" is equivalent to "asksub". */
436 static const char *asksub = "asksub";
437 const char *var = variable;
438 size_t len = strlen (var);
439 node *t;
440
441 if (len < 1)
442 return NULL;
443 479
444 /* Catch "ask" --> "asksub". */ 480 if (strcmp (var, "ask") == 0)
445 if (len == strlen ("ask") && !strcmp ("ask", var)) 481 entry.var = "asksub";
482 else
483 entry.var = var;
484
485 if (environment == NULL)
446 { 486 {
447 var = asksub; 487 list_create (&environment);
448 len = strlen (var); 488 list_set_comparator (environment, env_comp);
449 } 489 }
450 490
451 if (environment == NULL) 491 if (list_locate (environment, &entry, (void**)&p))
452 { 492 {
453 if (!create) 493 if (!create)
454 return 0; 494 return 0;
455 environment = xmalloc (sizeof (node)); 495
456 environment->env_entry.var = NULL; 496 p = xmalloc (sizeof *p);
457 environment->env_entry.set = 0; 497 p->var = xstrdup (entry.var);
458 environment->env_entry.value.number = 0; 498 list_prepend (environment, p);
459 environment->next = NULL; 499 p->set = 0;
500 p->type = Mail_env_whatever;
501 p->value.number = 0;
460 } 502 }
461 503
462 for (ep = environment; ep->next; ep = ep->next) 504 return p;
505 }
506
507 struct var_iterator
508 {
509 const char *prefix;
510 int prefixlen;
511 iterator_t itr;
512 };
513
514 const char *
515 var_iterate_next (var_iterator_t itr)
516 {
517 struct mail_env_entry *ep;
518
519 while (!iterator_is_done (itr->itr))
463 { 520 {
464 if (strlen (ep->env_entry.var) == len && 521 if (iterator_current (itr->itr, (void **)&ep))
465 !strcmp (var, ep->env_entry.var)) 522 return NULL;
466 return &ep->env_entry; 523 iterator_next (itr->itr);
524
525 if (strlen (ep->var) >= itr->prefixlen
526 && strncmp (ep->var, itr->prefix, itr->prefixlen) == 0)
527 return ep->var;
467 } 528 }
529 return NULL;
530 }
468 531
469 ep->env_entry.var = strdup (var); 532 const char *
470 ep->env_entry.set = 0; 533 var_iterate_first (const char *prefix, var_iterator_t *pitr)
471 ep->env_entry.type = Mail_env_whatever; 534 {
472 ep->env_entry.value.number = 0; 535 if (environment)
473 t = ep; 536 {
474 ep = util_ll_add (ep, 0); 537 var_iterator_t itr = xmalloc (sizeof *itr);
475 return &t->env_entry; 538 itr->prefix = prefix;
539 itr->prefixlen = strlen (prefix);
540 list_get_iterator (environment, &itr->itr);
541 iterator_first (itr->itr);
542 *pitr = itr;
543 return var_iterate_next (itr);
544 }
545 *pitr = NULL;
546 return NULL;
547 }
548
549 void
550 var_iterate_end (var_iterator_t *itr)
551 {
552 iterator_destroy (&(*itr)->itr);
553 free (*itr);
554 *itr = NULL;
476 } 555 }
477 556
478 /* print the environment */ 557 /* print the environment */
558 static int
559 envp_comp (const void *a, const void *b)
560 {
561 const struct mail_env_entry **epa = a;
562 const struct mail_env_entry **epb = b;
563
564 return strcmp ((*epa)->var, (*epb)->var);
565 }
566
479 int 567 int
480 util_printenv (int set) 568 util_printenv (int set)
481 { 569 {
482 node *ep; 570 struct mail_env_entry **ep;
483 for (ep = environment; ep != NULL; ep = ep->next) 571 size_t i, count = 0;
572
573 list_count (environment, &count);
574 ep = xcalloc (count, sizeof *ep);
575 list_to_array (environment, ep, count, NULL);
576 qsort (ep, count, sizeof *ep, envp_comp);
577 for (i = 0; i < count; i++)
484 { 578 {
485 if (ep->env_entry.set == set) 579 fprintf (ofile, "%s", ep[i]->var);
580 switch (ep[i]->type)
486 { 581 {
487 fprintf (ofile, "%s", ep->env_entry.var); 582 case Mail_env_number:
488 switch (ep->env_entry.type) 583 fprintf (ofile, "=%d", ep[i]->value.number);
489 { 584 break;
490 case Mail_env_number: 585
491 fprintf (ofile, "=%d", ep->env_entry.value.number); 586 case Mail_env_string:
492 break; 587 fprintf (ofile, "=\"%s\"", ep[i]->value.string);
493 588 break;
494 case Mail_env_string: 589
495 fprintf (ofile, "=\"%s\"", ep->env_entry.value.string); 590 case Mail_env_boolean:
496 break; 591 break;
497 592
498 case Mail_env_boolean: 593 case Mail_env_whatever:
499 break; 594 fprintf (ofile, _("oops?"));
500
501 case Mail_env_whatever:
502 fprintf (ofile, _("oops?"));
503 }
504 fprintf (ofile, "\n");
505 } 595 }
596 fprintf (ofile, "\n");
506 } 597 }
507 return 0; 598 free (ep);
508 } 599 }
509 600
510 /* Initialize environment entry: clear set indicator and free any memory 601 /* Initialize environment entry: clear set indicator and free any memory
...@@ -576,7 +667,7 @@ util_setenv (const char *variable, void *value, mail_env_data_t type, ...@@ -576,7 +667,7 @@ util_setenv (const char *variable, void *value, mail_env_data_t type,
576 int rc; 667 int rc;
577 char *err; 668 char *err;
578 669
579 if (rc = munre_set_regex (value, 0, &err)) 670 if ((rc = munre_set_regex (value, 0, &err)))
580 { 671 {
581 fprintf (stderr, "%s", mu_strerror (rc)); 672 fprintf (stderr, "%s", mu_strerror (rc));
582 if (err) 673 if (err)
...@@ -658,7 +749,8 @@ util_folder_path (const char *name) ...@@ -658,7 +749,8 @@ util_folder_path (const char *name)
658 { 749 {
659 char *folder; 750 char *folder;
660 char *tmp; 751 char *tmp;
661 752 char *p;
753
662 if (util_getenv (&folder, "folder", Mail_env_string, 1)) 754 if (util_getenv (&folder, "folder", Mail_env_string, 1))
663 return NULL; 755 return NULL;
664 756
...@@ -667,7 +759,7 @@ util_folder_path (const char *name) ...@@ -667,7 +759,7 @@ util_folder_path (const char *name)
667 if (name[0] == '+') 759 if (name[0] == '+')
668 name++; 760 name++;
669 761
670 if (folder[0] != '/' && folder[1] != '~') 762 if (folder[0] != '/' && folder[0] != '~')
671 { 763 {
672 char *home = mu_get_homedir (); 764 char *home = mu_get_homedir ();
673 tmp = xmalloc (strlen (home) + 1 + 765 tmp = xmalloc (strlen (home) + 1 +
...@@ -681,9 +773,10 @@ util_folder_path (const char *name) ...@@ -681,9 +773,10 @@ util_folder_path (const char *name)
681 strlen (name) + 1); 773 strlen (name) + 1);
682 sprintf (tmp, "%s/%s", folder, name); 774 sprintf (tmp, "%s/%s", folder, name);
683 } 775 }
684 name = tmp; 776 p = util_fullpath (tmp);
685 777 free (tmp);
686 return (char*) name; 778
779 return p;
687 } 780 }
688 781
689 char * 782 char *
...@@ -1005,41 +1098,6 @@ util_error (va_alist) ...@@ -1005,41 +1098,6 @@ util_error (va_alist)
1005 va_end(ap); 1098 va_end(ap);
1006 } 1099 }
1007 1100
1008 int
1009 util_help (const struct mail_command_entry *table, char *word)
1010 {
1011 if (!word)
1012 {
1013 int i = 0;
1014 FILE *out = stdout;
1015
1016 if (util_getenv (NULL, "crt", Mail_env_boolean, 0) == 0)
1017 out = popen (getenv ("PAGER"), "w");
1018
1019 while (table[i].synopsis != 0)
1020 fprintf (out, "%s\n", table[i++].synopsis);
1021
1022 if (out != stdout)
1023 pclose (out);
1024
1025 return 0;
1026 }
1027 else
1028 {
1029 int status = 0;
1030 struct mail_command_entry entry = util_find_entry(table, word);
1031 if (entry.synopsis != NULL)
1032 fprintf (stdout, "%s\n", entry.synopsis);
1033 else
1034 {
1035 status = 1;
1036 fprintf (stdout, _("Unknown command: %s\n"), word);
1037 }
1038 return status;
1039 }
1040 return 1;
1041 }
1042
1043 static int 1101 static int
1044 util_descend_subparts (message_t mesg, msgset_t *msgset, message_t *part) 1102 util_descend_subparts (message_t mesg, msgset_t *msgset, message_t *part)
1045 { 1103 {
......