source: util.c @ a0a5179

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since a0a5179 was 12c35df, checked in by James M. Kretchmar <kretch@mit.edu>, 17 years ago
Fixed replies to loopback messages Fixed smartnarrow on classes/instances with spaces Don't allow duplicates in command history Added the 'loggingdirection' variable All loopback messages log to 'loopback' now Print an error message if trying an invalid color for a filter Fixed bug causing > not to go to end of editwin every time
  • Property mode set to 100644
File size: 16.0 KB
Line 
1#include "owl.h"
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <ctype.h>
6
7static const char fileIdent[] = "$Id$";
8
9void sepbar(char *in)
10{
11  char buff[1024];
12  WINDOW *sepwin;
13  owl_messagelist *ml;
14  owl_view *v;
15  int x, y, i;
16  char *foo, *appendtosepbar;
17
18  sepwin=owl_global_get_curs_sepwin(&g);
19  ml=owl_global_get_msglist(&g);
20  v=owl_global_get_current_view(&g);
21
22  werase(sepwin);
23  wattron(sepwin, A_REVERSE);
24  if (owl_global_is_fancylines(&g)) {
25    whline(sepwin, ACS_HLINE, owl_global_get_cols(&g));
26  } else {
27    whline(sepwin, '-', owl_global_get_cols(&g));
28  }
29
30  if (owl_global_is_sepbar_disable(&g)) {
31    getyx(sepwin, y, x);
32    wmove(sepwin, y, owl_global_get_cols(&g)-1);
33    return;
34  }
35
36  wmove(sepwin, 0, 2); 
37
38  if (owl_messagelist_get_size(ml)==0) {
39    strcpy(buff, " (-/-) ");
40  } else {
41    snprintf(buff, 1024, " (%i/%i/%i) ", owl_global_get_curmsg(&g)+1,
42            owl_view_get_size(v),
43            owl_messagelist_get_size(ml));
44  }
45  waddstr(sepwin, buff);
46
47  foo=owl_view_get_filtname(v);
48  if (strcmp(foo, "all")) wattroff(sepwin, A_REVERSE);
49  waddstr(sepwin, " ");
50  waddstr(sepwin, owl_view_get_filtname(v));
51  waddstr(sepwin, " ");
52  if (strcmp(foo, "all")) wattron(sepwin, A_REVERSE);
53
54  if (owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
55    getyx(sepwin, y, x);
56    wmove(sepwin, y, x+2);
57    wattron(sepwin, A_BOLD);
58    waddstr(sepwin, " <truncated> ");
59    wattroff(sepwin, A_BOLD);
60  }
61
62  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
63  if ((i != -1) &&
64      (i < owl_view_get_size(v)-1)) {
65    getyx(sepwin, y, x);
66    wmove(sepwin, y, x+2);
67    wattron(sepwin, A_BOLD);
68    waddstr(sepwin, " <more> ");
69    wattroff(sepwin, A_BOLD);
70  }
71
72  if (owl_global_get_rightshift(&g)>0) {
73    getyx(sepwin, y, x);
74    wmove(sepwin, y, x+2);
75    snprintf(buff, 1024, " right: %i ", owl_global_get_rightshift(&g));
76    waddstr(sepwin, buff);
77  }
78
79  if (owl_global_is_zaway(&g)) {
80    getyx(sepwin, y, x);
81    wmove(sepwin, y, x+2);
82    wattron(sepwin, A_BOLD);
83    wattroff(sepwin, A_REVERSE);
84    waddstr(sepwin, " ZAWAY ");
85    wattron(sepwin, A_REVERSE);
86    wattroff(sepwin, A_BOLD);
87  }
88
89  if (owl_global_get_curmsg_vert_offset(&g)) {
90    getyx(sepwin, y, x);
91    wmove(sepwin, y, x+2);
92    wattron(sepwin, A_BOLD);
93    wattroff(sepwin, A_REVERSE);
94    waddstr(sepwin, " SCROLL ");
95    wattron(sepwin, A_REVERSE);
96    wattroff(sepwin, A_BOLD);
97  }
98 
99  if (in) {
100    getyx(sepwin, y, x);
101    wmove(sepwin, y, x+2);
102    waddstr(sepwin, in);
103  }
104
105  appendtosepbar = owl_global_get_appendtosepbar(&g);
106  if (appendtosepbar && *appendtosepbar) {
107    getyx(sepwin, y, x);
108    wmove(sepwin, y, x+2);
109    waddstr(sepwin, " ");
110    waddstr(sepwin, owl_global_get_appendtosepbar(&g));
111    waddstr(sepwin, " ");
112  }
113
114  getyx(sepwin, y, x);
115  wmove(sepwin, y, owl_global_get_cols(&g)-1);
116   
117  wattroff(sepwin, A_BOLD);
118  wattroff(sepwin, A_REVERSE);
119  wnoutrefresh(sepwin);
120}
121
122
123void pophandler_quit(int ch)
124{
125  if (ch=='q') {
126    owl_popwin_close(owl_global_get_popwin(&g));
127  }
128}
129
130char **atokenize(char *buffer, char *sep, int *i)
131{
132  /* each element of return must be freed by user */
133  char **args;
134  char *workbuff, *foo;
135  int done=0, first=1, count=0;
136
137  workbuff=owl_malloc(strlen(buffer)+1);
138  memcpy(workbuff, buffer, strlen(buffer)+1);
139
140  args=NULL;
141  while (!done) {
142    if (first) {
143      first=0;
144      foo=(char *)strtok(workbuff, sep);
145    } else {
146      foo=(char *)strtok(NULL, sep);
147    }
148    if (foo==NULL) {
149      done=1;
150    } else {
151      args=(char **)owl_realloc(args, sizeof(char *) * (count+1));
152      args[count]=owl_malloc(strlen(foo)+1);
153      strcpy(args[count], foo);
154      count++;
155    }
156  }
157  *i=count;
158  owl_free(workbuff);
159  return(args);
160}
161
162char *skiptokens(char *buff, int n) {
163  /* skips n tokens and returns where that would be.
164   * TODO: handle quotes more sanely. */
165 
166  int inquotes=0;
167  while (*buff && n>0) {
168      while (*buff == ' ') buff++;
169      while (*buff && (inquotes || *buff != ' ')) { 
170        if (*buff == '"' || *buff == '\'') inquotes=!inquotes;
171        buff++;
172      }
173      while (*buff == ' ') buff++;
174      n--;
175  }
176  return buff;
177}
178
179void atokenize_free(char **tok, int nels)
180{
181  int i;
182  for (i=0; i<nels; i++) {
183    owl_free(tok[i]);
184  }
185  owl_free(tok);
186}
187
188
189void owl_parsefree(char **argv, int argc)
190{
191  int i;
192
193  if (!argv) return;
194 
195  for (i=0; i<argc; i++) {
196    if (argv[i]) owl_free(argv[i]);
197  }
198  owl_free(argv);
199}
200
201char **owl_parseline(char *line, int *argc)
202{
203  /* break a command line up into argv, argc.  The caller must free
204     the returned values.  If there is an error argc will be set to
205     -1, argv will be NULL and the caller does not need to free
206     anything */
207
208  char **argv;
209  int i, len, between=1;
210  char *curarg;
211  char quote;
212
213  argv=owl_malloc(sizeof(char *));
214  len=strlen(line);
215  curarg=owl_malloc(len+10);
216  strcpy(curarg, "");
217  quote='\0';
218  *argc=0;
219  for (i=0; i<len+1; i++) {
220    /* find the first real character */
221    if (between) {
222      if (line[i]==' ' || line[i]=='\t' || line[i]=='\0') {
223        continue;
224      } else {
225        between=0;
226        i--;
227        continue;
228      }
229    }
230
231    /* deal with a quote character */
232    if (line[i]=='"' || line[i]=="'"[0]) {
233      /* if this type of quote is open, close it */
234      if (quote==line[i]) {
235        quote='\0';
236        continue;
237      }
238
239      /* if no quoting is open then open with this */
240      if (quote=='\0') {
241        quote=line[i];
242        continue;
243      }
244
245      /* if another type of quote is open then treat this as a literal */
246      curarg[strlen(curarg)+1]='\0';
247      curarg[strlen(curarg)]=line[i];
248      continue;
249    }
250
251    /* if it's not a space or end of command, then use it */
252    if (line[i]!=' ' && line[i]!='\t' && line[i]!='\n' && line[i]!='\0') {
253      curarg[strlen(curarg)+1]='\0';
254      curarg[strlen(curarg)]=line[i];
255      continue;
256    }
257
258    /* otherwise, if we're not in quotes, add the whole argument */
259    if (quote=='\0') {
260      /* add the argument */
261      argv=owl_realloc(argv, sizeof(char *)*((*argc)+1));
262      argv[*argc]=owl_malloc(strlen(curarg)+2);
263      strcpy(argv[*argc], curarg);
264      *argc=*argc+1;
265      strcpy(curarg, "");
266      between=1;
267      continue;
268    }
269
270    /* if it is a space and we're in quotes, then use it */
271    curarg[strlen(curarg)+1]='\0';
272    curarg[strlen(curarg)]=line[i];
273  }
274
275  /* check for unbalanced quotes */
276  if (quote!='\0') {
277    owl_parsefree(argv, *argc);
278    *argc=-1;
279    return(NULL);
280  }
281
282  return(argv);
283}
284
285/* caller must free the return */
286char *owl_util_minutes_to_timestr(int in)
287{
288  int days, hours;
289  long run;
290  char *out;
291
292  run=in;
293
294  days=run/1440;
295  run-=days*1440;
296  hours=run/60;
297  run-=hours*60;
298
299  if (days>0) {
300    out=owl_sprintf("%i d %2.2i:%2.2i", days, hours, run);
301  } else {
302    out=owl_sprintf("    %2.2i:%2.2i", hours, run);
303  }
304  return(out);
305}
306
307/* return the index of the last char before a change from the first one */
308int owl_util_find_trans(char *in, int len)
309{
310  int i;
311  for (i=1; i<len; i++) {
312    if (in[i] != in[0]) return(i-1);
313  }
314  return(i);
315}
316
317/* downcase the string 'foo' */
318void downstr(char *foo)
319{
320  int i;
321  for (i=0; foo[i]!='\0'; i++) {
322    foo[i]=tolower(foo[i]);
323  }
324}
325
326/* Caller must free response.
327 * Takes in strings which are space-separated lists of tokens
328 * and returns a single string containing no token more than once.
329 * If prohibit is non-null, no token may start with a character
330 * in prohibit.
331 */
332char *owl_util_uniq(char *A, char *B, char *prohibit)
333{
334 
335  char *cat, **tok;
336  int toklen, i, j, first=1;
337  cat = owl_malloc(strlen(A)+strlen(B)+3);
338  strcpy(cat, A);
339  strcat(cat, " ");
340  strcat(cat, B);
341  tok = atokenize(cat, " ", &toklen);
342  strcpy(cat, "");
343  for (i=0; i<toklen; i++) {
344    int dup=0;
345    for (j=0; j<i; j++) {
346      if (!strcmp(tok[i], tok[j])) dup=1;
347    }
348    if (!dup && (!prohibit || !strchr(prohibit, tok[i][0]))) {
349      if (!first) {
350        strcat(cat, " ");
351      }
352      first=0;
353      strcat(cat, tok[i]);
354    }
355  }
356  atokenize_free(tok, toklen);
357  return(cat);
358}
359
360/* hooks for doing memory allocation et. al. in owl */
361
362void *owl_malloc(size_t size)
363{
364  return(malloc(size));
365}
366
367void owl_free(void *ptr)
368{
369  free(ptr);
370}
371
372char *owl_strdup(const char *s1)
373{
374  return(strdup(s1));
375}
376
377void *owl_realloc(void *ptr, size_t size)
378{
379  return(realloc(ptr, size));
380}
381
382/* allocates memory and returns the string or null.
383 * caller must free the string.
384 * from Linux sprintf man page.
385 */
386char *owl_sprintf(const char *fmt, ...)
387{
388  int n, size = 100;
389  char *p;
390  va_list ap;
391  if ((p = owl_malloc (size)) == NULL) return (NULL);
392  while (1) {
393    /* Try to print in the allocated space. */
394    va_start(ap, fmt);
395    n = vsnprintf (p, size, fmt, ap);
396    va_end(ap);
397    /* If that worked, return the string. */
398    if (n > -1 && n < size)
399      return p;
400    /* Else try again with more space. */
401    if (n > -1)    /* glibc 2.1 */
402      size = n+1; /* precisely what is needed */
403    else           /* glibc 2.0 */
404      size *= 2;  /* twice the old size */
405    if ((p = owl_realloc (p, size)) == NULL)
406      return NULL;
407  }
408}
409
410/* Return the owl color associated with the named color.  Return -1
411 * if the named color is not available
412 */
413int owl_util_string_to_color(char *color)
414{
415  if (!strcasecmp(color, "black")) {
416    return(OWL_COLOR_BLACK);
417  } else if (!strcasecmp(color, "red")) {
418    return(OWL_COLOR_RED);
419  } else if (!strcasecmp(color, "green")) {
420    return(OWL_COLOR_GREEN);
421  } else if (!strcasecmp(color, "yellow")) {
422    return(OWL_COLOR_YELLOW);
423  } else if (!strcasecmp(color, "blue")) {
424    return(OWL_COLOR_BLUE);
425  } else if (!strcasecmp(color, "magenta")) {
426    return(OWL_COLOR_MAGENTA);
427  } else if (!strcasecmp(color, "cyan")) {
428    return(OWL_COLOR_CYAN);
429  } else if (!strcasecmp(color, "white")) {
430    return(OWL_COLOR_WHITE);
431  } else if (!strcasecmp(color, "default")) {
432    return(OWL_COLOR_DEFAULT);
433  }
434  return(-1);
435}
436
437/* Return a string name of the given owl color */
438char *owl_util_color_to_string(int color)
439{
440  if (color==OWL_COLOR_BLACK)   return("black");
441  if (color==OWL_COLOR_RED)     return("red");
442  if (color==OWL_COLOR_GREEN)   return("green");
443  if (color==OWL_COLOR_YELLOW)  return("yellow");
444  if (color==OWL_COLOR_BLUE)    return("blue");
445  if (color==OWL_COLOR_MAGENTA) return("magenta");
446  if (color==OWL_COLOR_CYAN)    return("cyan");
447  if (color==OWL_COLOR_WHITE)   return("white");
448  if (color==OWL_COLOR_DEFAULT) return("default");
449  return("Unknown color");
450}
451
452/* Get the default tty name.  Caller must free the return */
453char *owl_util_get_default_tty()
454{
455  char *out, *tmp;
456
457  if (getenv("DISPLAY")) {
458    out=owl_strdup(getenv("DISPLAY"));
459  } else if ((tmp=ttyname(fileno(stdout)))!=NULL) {
460    out=owl_strdup(tmp);
461    if (!strncmp(out, "/dev/", 5)) {
462      owl_free(out);
463      out=owl_strdup(tmp+5);
464    }
465  } else {
466    out=owl_strdup("unknown");
467  }
468  return(out);
469}
470
471
472/* Animation hack */
473void owl_hack_animate()
474{
475  owl_messagelist *ml;
476  owl_message *m;
477  owl_fmtext *fm;
478  char *text, *ptr;
479  int place;
480
481  /* grab the first message and make sure its id is 0 */
482  ml=owl_global_get_msglist(&g);
483  m=owl_messagelist_get_element(ml, 0);
484  if (!m) return;
485  if (owl_message_get_id(m)!=0) return;
486
487  fm=owl_message_get_fmtext(m);
488  text=owl_fmtext_get_text(fm);
489
490  ptr=strstr(text, "OvO");
491  if (ptr) {
492    place=ptr-text;
493    owl_fmtext_set_char(fm, place, '-');
494    owl_fmtext_set_char(fm, place+2, '-');
495
496    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
497    if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
498      owl_popwin_refresh(owl_global_get_popwin(&g));
499      /* TODO: this is a broken kludge */
500      if (owl_global_get_viewwin(&g)) {
501        owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
502      }
503    }
504    owl_global_set_needrefresh(&g);
505    return;
506  }
507
508  ptr=strstr(text, "-v-");
509  if (ptr) {
510    place=ptr-text;
511    owl_fmtext_set_char(fm, place, 'O');
512    owl_fmtext_set_char(fm, place+2, 'O');
513
514    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
515    if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
516      owl_popwin_refresh(owl_global_get_popwin(&g));
517      /* TODO: this is a broken kludge */
518      if (owl_global_get_viewwin(&g)) {
519        owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
520      }
521    }
522    owl_global_set_needrefresh(&g);
523    return;
524  }
525}
526
527/* strip leading and trailing new lines.  Caller must free the
528 * return.
529 */
530char *owl_util_stripnewlines(char *in)
531{
532 
533  char  *tmp, *ptr1, *ptr2, *out;
534
535  ptr1=tmp=owl_strdup(in);
536  while (ptr1[0]=='\n') {
537    ptr1++;
538  }
539  ptr2=ptr1+strlen(ptr1)-1;
540  while (ptr2[0]=='\n' && ptr2>ptr1) {
541    ptr2[0]='\0';
542    ptr2--;
543  }
544
545  out=owl_strdup(ptr1);
546  owl_free(tmp);
547  return(out);
548}
549
550/* Delete the line matching "line" from the named file.  If no such
551 * line is found the file is left intact.  If backup==1 then create a
552 * backupfile containing the original contents.  This is an
553 * inefficient impelementation which reads the entire file into
554 * memory.
555 */
556void owl_util_file_deleteline(char *filename, char *line, int backup)
557{
558  char buff[LINE], *text;
559  char *backupfilename="";
560  FILE *file, *backupfile=NULL;
561  int size, newline;
562
563  /* open the file for reading */
564  file=fopen(filename, "r");
565  if (!file) {
566    owl_function_error("Error opening file %s", filename);
567    return;
568  }
569
570  /* open the backup file for writing */
571  if (backup) {
572    backupfilename=owl_sprintf("%s.backup", filename);
573    backupfile=fopen(backupfilename, "w");
574    if (!backupfile) {
575      owl_function_error("Error opening file %s for writing", backupfilename);
576      owl_free(backupfilename);
577      return;
578    }
579    owl_free(backupfilename);
580  }
581
582  /* we'll read the entire file into memory, minus the line we don't want and
583   * and at the same time create the backup file if necessary
584   */
585  text=owl_malloc(LINE);
586  strcpy(text, "");
587  size=LINE;
588  while (fgets(buff, LINE, file)!=NULL) {
589    /* strip the newline */
590    newline=0;
591    if (buff[strlen(buff)-1]=='\n') {
592      buff[strlen(buff)-1]='\0';
593      newline=1;
594    }
595   
596    /* if we don't match the line, add to saved text in memory */
597    if (strcasecmp(buff, line)) {
598      size+=LINE;
599      text=owl_realloc(text, size);
600      strcat(text, buff);
601      if (newline) strcat(text, "\n");
602    }
603
604    /* write to backupfile if necessary */
605    if (backup) {
606      fputs(buff, backupfile);
607      if (newline) fputs("\n", backupfile);
608    }
609  }
610  if (backup) fclose(backupfile);
611  fclose(file);
612
613  /* now rewrite the original file from memory */
614  file=fopen(filename, "w");
615  if (!file) {
616    owl_function_error("WARNING: Error opening %s for writing.  Use %s to restore.", filename, backupfilename);
617    owl_function_beep();
618    owl_free(line);
619    return;
620  }
621
622  fputs(text, file);
623  fclose(file);
624}
625
626/**************************************************************************/
627/************************* REGRESSION TESTS *******************************/
628/**************************************************************************/
629
630#ifdef OWL_INCLUDE_REG_TESTS
631
632#define FAIL_UNLESS(desc,pred) printf("\t%-4s: %s\n", (pred)?"ok":(numfailed++,"FAIL"), desc)
633
634int owl_util_regtest(void)
635{
636  int numfailed=0;
637
638  printf("BEGIN testing owl_util\n");
639
640  FAIL_UNLESS("owl_util_substitute 1",
641              !strcmp("foo", owl_text_substitute("foo", "", "Y")));
642  FAIL_UNLESS("owl_text_substitute 2",
643              !strcmp("fYZYZ", owl_text_substitute("foo", "o", "YZ")));
644  FAIL_UNLESS("owl_text_substitute 3",
645              !strcmp("foo", owl_text_substitute("fYZYZ", "YZ", "o")));
646  FAIL_UNLESS("owl_text_substitute 4",
647              !strcmp("/u/foo/meep", owl_text_substitute("~/meep", "~", "/u/foo")));
648
649  FAIL_UNLESS("skiptokens 1", 
650              !strcmp("bar quux", skiptokens("foo bar quux", 1)));
651  FAIL_UNLESS("skiptokens 2", 
652              !strcmp("meep", skiptokens("foo 'bar quux' meep", 2)));
653
654  FAIL_UNLESS("owl_util_uniq 1", 
655              !strcmp("foo bar x", owl_util_uniq("foo", "bar x", "-")));
656  FAIL_UNLESS("owl_util_uniq 2", 
657              !strcmp("foo bar x", owl_util_uniq("foo", "bar -y x", "-")));
658  FAIL_UNLESS("owl_util_uniq 3", 
659              !strcmp("meep foo bar", owl_util_uniq("meep foo", "bar foo meep", "-")));
660
661  if (numfailed) printf("*** WARNING: failures encountered with owl_util\n");
662  printf("END testing owl_util (%d failures)\n", numfailed);
663  return(numfailed);
664}
665
666#endif /* OWL_INCLUDE_REG_TESTS */
Note: See TracBrowser for help on using the repository browser.