source: util.c @ 6b93305

release-1.7release-1.8release-1.9
Last change on this file since 6b93305 was 4e33cb2, checked in by David Benjamin <davidben@mit.edu>, 11 years ago
Punt a lot of needrefreshes Move the actual needrefreshes into the functions actually dealing with curses. This will, of course, later get moved out of the paint events and no one will call it. But that's later.
  • Property mode set to 100644
File size: 17.3 KB
Line 
1#include "owl.h"
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <ctype.h>
6#include <pwd.h>
7#include <sys/stat.h>
8#include <sys/types.h>
9
10void sepbar(const char *in)
11{
12  WINDOW *sepwin;
13  const owl_messagelist *ml;
14  const owl_view *v;
15  int x, y, i;
16  const 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    waddstr(sepwin, " (-/-) ");
40  else
41    wprintw(sepwin, " (%i/%i/%i) ", owl_global_get_curmsg(&g) + 1,
42            owl_view_get_size(v),
43            owl_messagelist_get_size(ml));
44
45  foo=owl_view_get_filtname(v);
46  if (strcmp(foo, owl_global_get_view_home(&g)))
47      wattroff(sepwin, A_REVERSE);
48  wprintw(sepwin, " %s ", owl_view_get_filtname(v));
49  if (strcmp(foo, owl_global_get_view_home(&g)))
50      wattron(sepwin, A_REVERSE);
51
52  if (owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
53    getyx(sepwin, y, x);
54    wmove(sepwin, y, x+2);
55    wattron(sepwin, A_BOLD);
56    waddstr(sepwin, " <truncated> ");
57    wattroff(sepwin, A_BOLD);
58  }
59
60  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
61  if ((i != -1) &&
62      (i < owl_view_get_size(v)-1)) {
63    getyx(sepwin, y, x);
64    wmove(sepwin, y, x+2);
65    wattron(sepwin, A_BOLD);
66    waddstr(sepwin, " <more> ");
67    wattroff(sepwin, A_BOLD);
68  }
69
70  if (owl_global_get_rightshift(&g)>0) {
71    getyx(sepwin, y, x);
72    wmove(sepwin, y, x+2);
73    wprintw(sepwin, " right: %i ", owl_global_get_rightshift(&g));
74  }
75
76  if (owl_global_is_zaway(&g) || owl_global_is_aaway(&g)) {
77    getyx(sepwin, y, x);
78    wmove(sepwin, y, x+2);
79    wattron(sepwin, A_BOLD);
80    wattroff(sepwin, A_REVERSE);
81    if (owl_global_is_zaway(&g) && owl_global_is_aaway(&g)) {
82      waddstr(sepwin, " AWAY ");
83    } else if (owl_global_is_zaway(&g)) {
84      waddstr(sepwin, " Z-AWAY ");
85    } else if (owl_global_is_aaway(&g)) {
86      waddstr(sepwin, " A-AWAY ");
87    }
88    wattron(sepwin, A_REVERSE);
89    wattroff(sepwin, A_BOLD);
90  }
91
92  if (owl_global_get_curmsg_vert_offset(&g)) {
93    getyx(sepwin, y, x);
94    wmove(sepwin, y, x+2);
95    wattron(sepwin, A_BOLD);
96    wattroff(sepwin, A_REVERSE);
97    waddstr(sepwin, " SCROLL ");
98    wattron(sepwin, A_REVERSE);
99    wattroff(sepwin, A_BOLD);
100  }
101 
102  if (in) {
103    getyx(sepwin, y, x);
104    wmove(sepwin, y, x+2);
105    waddstr(sepwin, in);
106  }
107
108  appendtosepbar = owl_global_get_appendtosepbar(&g);
109  if (appendtosepbar && *appendtosepbar) {
110    getyx(sepwin, y, x);
111    wmove(sepwin, y, x+2);
112    waddstr(sepwin, " ");
113    waddstr(sepwin, owl_global_get_appendtosepbar(&g));
114    waddstr(sepwin, " ");
115  }
116
117  getyx(sepwin, y, x);
118  wmove(sepwin, y, owl_global_get_cols(&g)-1);
119   
120  wattroff(sepwin, A_BOLD);
121  wattroff(sepwin, A_REVERSE);
122  owl_global_set_needrefresh(&g);
123}
124
125char **atokenize(const char *buffer, const char *sep, int *i)
126{
127  /* each element of return must be freed by user */
128  char **args;
129  char *workbuff, *foo;
130  int done=0, first=1, count=0;
131
132  workbuff = owl_strdup(buffer);
133
134  args=NULL;
135  while (!done) {
136    if (first) {
137      first=0;
138      foo=strtok(workbuff, sep);
139    } else {
140      foo=strtok(NULL, sep);
141    }
142    if (foo==NULL) {
143      done=1;
144    } else {
145      args=owl_realloc(args, sizeof(char *) * (count+1));
146      args[count] = owl_strdup(foo);
147      count++;
148    }
149  }
150  *i=count;
151  owl_free(workbuff);
152  return(args);
153}
154
155const char *skiptokens(const char *buff, int n) {
156  /* skips n tokens and returns where that would be. */
157  char quote = 0;
158  while (*buff && n>0) {
159      while (*buff == ' ') buff++;
160      while (*buff && (quote || *buff != ' ')) {
161        if(quote) {
162          if(*buff == quote) quote = 0;
163        } else if(*buff == '"' || *buff == '\'') {
164          quote = *buff;
165        }
166        buff++;
167      }
168      while (*buff == ' ') buff++;
169      n--;
170  }
171  return buff;
172}
173
174/* Return a "nice" version of the path.  Tilde expansion is done, and
175 * duplicate slashes are removed.  Caller must free the return.
176 */
177char *owl_util_makepath(const char *in)
178{
179  int i, j, x;
180  char *out, user[MAXPATHLEN];
181  struct passwd *pw;
182
183  out=owl_malloc(MAXPATHLEN+1);
184  out[0]='\0';
185  j=strlen(in);
186  x=0;
187  for (i=0; i<j; i++) {
188    if (in[i]=='~') {
189      if ( (i==(j-1)) ||          /* last character */
190           (in[i+1]=='/') ) {     /* ~/ */
191        /* use my homedir */
192        pw=getpwuid(getuid());
193        if (!pw) {
194          out[x]=in[i];
195        } else {
196          out[x]='\0';
197          strcat(out, pw->pw_dir);
198          x+=strlen(pw->pw_dir);
199        }
200      } else {
201        /* another user homedir */
202        int a, b;
203        b=0;
204        for (a=i+1; i<j; a++) {
205          if (in[a]==' ' || in[a]=='/') {
206            break;
207          } else {
208            user[b]=in[a];
209            i++;
210            b++;
211          }
212        }
213        user[b]='\0';
214        pw=getpwnam(user);
215        if (!pw) {
216          out[x]=in[i];
217        } else {
218          out[x]='\0';
219          strcat(out, pw->pw_dir);
220          x+=strlen(pw->pw_dir);
221        }
222      }
223    } else if (in[i]=='/') {
224      /* check for a double / */
225      if (i<(j-1) && (in[i+1]=='/')) {
226        /* do nothing */
227      } else {
228        out[x]=in[i];
229        x++;
230      }
231    } else {
232      out[x]=in[i];
233      x++;
234    }
235  }
236  out[x]='\0';
237  return(out);
238}
239
240void atokenize_delete(char **tok, int nels)
241{
242  int i;
243  for (i=0; i<nels; i++) {
244    owl_free(tok[i]);
245  }
246  owl_free(tok);
247}
248
249
250void owl_parse_delete(char **argv, int argc)
251{
252  int i;
253
254  if (!argv) return;
255 
256  for (i=0; i<argc; i++) {
257    if (argv[i]) owl_free(argv[i]);
258  }
259  owl_free(argv);
260}
261
262char **owl_parseline(const char *line, int *argc)
263{
264  /* break a command line up into argv, argc.  The caller must free
265     the returned values.  If there is an error argc will be set to
266     -1, argv will be NULL and the caller does not need to free
267     anything */
268
269  char **argv;
270  int i, len, between=1;
271  char *curarg;
272  char quote;
273
274  argv=owl_malloc(sizeof(char *));
275  len=strlen(line);
276  curarg=owl_malloc(len+10);
277  strcpy(curarg, "");
278  quote='\0';
279  *argc=0;
280  for (i=0; i<len+1; i++) {
281    /* find the first real character */
282    if (between) {
283      if (line[i]==' ' || line[i]=='\t' || line[i]=='\0') {
284        continue;
285      } else {
286        between=0;
287        i--;
288        continue;
289      }
290    }
291
292    /* deal with a quote character */
293    if (line[i]=='"' || line[i]=="'"[0]) {
294      /* if this type of quote is open, close it */
295      if (quote==line[i]) {
296        quote='\0';
297        continue;
298      }
299
300      /* if no quoting is open then open with this */
301      if (quote=='\0') {
302        quote=line[i];
303        continue;
304      }
305
306      /* if another type of quote is open then treat this as a literal */
307      curarg[strlen(curarg)+1]='\0';
308      curarg[strlen(curarg)]=line[i];
309      continue;
310    }
311
312    /* if it's not a space or end of command, then use it */
313    if (line[i]!=' ' && line[i]!='\t' && line[i]!='\n' && line[i]!='\0') {
314      curarg[strlen(curarg)+1]='\0';
315      curarg[strlen(curarg)]=line[i];
316      continue;
317    }
318
319    /* otherwise, if we're not in quotes, add the whole argument */
320    if (quote=='\0') {
321      /* add the argument */
322      argv=owl_realloc(argv, sizeof(char *)*((*argc)+1));
323      argv[*argc] = owl_strdup(curarg);
324      *argc=*argc+1;
325      strcpy(curarg, "");
326      between=1;
327      continue;
328    }
329
330    /* if it is a space and we're in quotes, then use it */
331    curarg[strlen(curarg)+1]='\0';
332    curarg[strlen(curarg)]=line[i];
333  }
334
335  owl_free(curarg);
336
337  /* check for unbalanced quotes */
338  if (quote!='\0') {
339    owl_parse_delete(argv, *argc);
340    *argc=-1;
341    return(NULL);
342  }
343
344  return(argv);
345}
346
347/* caller must free the return */
348char *owl_util_minutes_to_timestr(int in)
349{
350  int days, hours;
351  long run;
352  char *out;
353
354  run=in;
355
356  days=run/1440;
357  run-=days*1440;
358  hours=run/60;
359  run-=hours*60;
360
361  if (days>0) {
362    out=owl_sprintf("%i d %2.2i:%2.2li", days, hours, run);
363  } else {
364    out=owl_sprintf("    %2.2i:%2.2li", hours, run);
365  }
366  return(out);
367}
368
369/* hooks for doing memory allocation et. al. in owl */
370
371void *owl_malloc(size_t size)
372{
373  return(g_malloc(size));
374}
375
376void owl_free(void *ptr)
377{
378  g_free(ptr);
379}
380
381char *owl_strdup(const char *s1)
382{
383  return(g_strdup(s1));
384}
385
386void *owl_realloc(void *ptr, size_t size)
387{
388  return(g_realloc(ptr, size));
389}
390
391/* allocates memory and returns the string or null.
392 * caller must free the string.
393 */
394char *owl_sprintf(const char *fmt, ...)
395{
396  va_list ap;
397  char *ret = NULL;
398  va_start(ap, fmt);
399  ret = g_strdup_vprintf(fmt, ap);
400  va_end(ap);
401  return ret;
402}
403
404/* These are in order of their value in owl.h */
405static const struct {
406  int number;
407  const char *name;
408} color_map[] = {
409  {OWL_COLOR_INVALID, "invalid"},
410  {OWL_COLOR_DEFAULT, "default"},
411  {OWL_COLOR_BLACK, "black"},
412  {OWL_COLOR_RED, "red"},
413  {OWL_COLOR_GREEN, "green"},
414  {OWL_COLOR_YELLOW,"yellow"},
415  {OWL_COLOR_BLUE, "blue"},
416  {OWL_COLOR_MAGENTA, "magenta"},
417  {OWL_COLOR_CYAN, "cyan"},
418  {OWL_COLOR_WHITE, "white"},
419};
420
421/* Return the owl color associated with the named color.  Return -1
422 * if the named color is not available
423 */
424int owl_util_string_to_color(const char *color)
425{
426  int c, i;
427  char *p;
428
429  for (i = 0; i < (sizeof(color_map)/sizeof(color_map[0])); i++)
430    if (strcasecmp(color, color_map[i].name) == 0)
431      return color_map[i].number;
432
433  c = strtol(color, &p, 10);
434  if (p != color && c >= -1 && c < COLORS) {
435    return(c);
436  }
437  return(OWL_COLOR_INVALID);
438}
439
440/* Return a string name of the given owl color */
441const char *owl_util_color_to_string(int color)
442{
443  if (color >= OWL_COLOR_INVALID && color <= OWL_COLOR_WHITE)
444    return color_map[color - OWL_COLOR_INVALID].name;
445  return("Unknown color");
446}
447
448/* Get the default tty name.  Caller must free the return */
449char *owl_util_get_default_tty(void)
450{
451  const char *tmp;
452  char *out;
453
454  if (getenv("DISPLAY")) {
455    out=owl_strdup(getenv("DISPLAY"));
456  } else if ((tmp=ttyname(fileno(stdout)))!=NULL) {
457    out=owl_strdup(tmp);
458    if (!strncmp(out, "/dev/", 5)) {
459      owl_free(out);
460      out=owl_strdup(tmp+5);
461    }
462  } else {
463    out=owl_strdup("unknown");
464  }
465  return(out);
466}
467
468/* strip leading and trailing new lines.  Caller must free the
469 * return.
470 */
471char *owl_util_stripnewlines(const char *in)
472{
473 
474  char  *tmp, *ptr1, *ptr2, *out;
475
476  ptr1=tmp=owl_strdup(in);
477  while (ptr1[0]=='\n') {
478    ptr1++;
479  }
480  ptr2=ptr1+strlen(ptr1)-1;
481  while (ptr2>ptr1 && ptr2[0]=='\n') {
482    ptr2[0]='\0';
483    ptr2--;
484  }
485
486  out=owl_strdup(ptr1);
487  owl_free(tmp);
488  return(out);
489}
490
491/* Delete all lines matching "line" from the named file.  If no such
492 * line is found the file is left intact.  If backup==1 then leave a
493 * backup file containing the original contents.  The match is
494 * case-insensitive.
495 *
496 * Returns the number of lines removed
497 */
498int owl_util_file_deleteline(const char *filename, const char *line, int backup)
499{
500  char *backupfile, *newfile, *buf = NULL;
501  FILE *old, *new;
502  struct stat st;
503  int numremoved = 0;
504
505  if ((old = fopen(filename, "r")) == NULL) {
506    owl_function_error("Cannot open %s (for reading): %s",
507                       filename, strerror(errno));
508    return 0;
509  }
510
511  if (fstat(fileno(old), &st) != 0) {
512    owl_function_error("Cannot stat %s: %s", filename, strerror(errno));
513    return 0;
514  }
515
516  newfile = owl_sprintf("%s.new", filename);
517  if ((new = fopen(newfile, "w")) == NULL) {
518    owl_function_error("Cannot open %s (for writing): %s",
519                       filename, strerror(errno));
520    free(newfile);
521    fclose(old);
522    return 0;
523  }
524
525  if (fchmod(fileno(new), st.st_mode & 0777) != 0) {
526    owl_function_error("Cannot set permissions on %s: %s",
527                       filename, strerror(errno));
528    unlink(newfile);
529    fclose(new);
530    free(newfile);
531    fclose(old);
532    return 0;
533  }
534
535  while (owl_getline_chomp(&buf, old))
536    if (strcasecmp(buf, line) != 0)
537      fprintf(new, "%s\n", buf);
538    else
539      numremoved++;
540  owl_free(buf);
541
542  fclose(new);
543  fclose(old);
544
545  if (backup) {
546    backupfile = owl_sprintf("%s.backup", filename);
547    unlink(backupfile);
548    if (link(filename, backupfile) != 0) {
549      owl_function_error("Cannot link %s: %s", backupfile, strerror(errno));
550      owl_free(backupfile);
551      unlink(newfile);
552      owl_free(newfile);
553      return 0;
554    }
555    owl_free(backupfile);
556  }
557
558  if (rename(newfile, filename) != 0) {
559    owl_function_error("Cannot move %s to %s: %s",
560                       newfile, filename, strerror(errno));
561    numremoved = 0;
562  }
563
564  unlink(newfile);
565  owl_free(newfile);
566
567  return numremoved;
568}
569
570int owl_util_max(int a, int b)
571{
572  if (a>b) return(a);
573  return(b);
574}
575
576int owl_util_min(int a, int b)
577{
578  if (a<b) return(a);
579  return(b);
580}
581
582/* Return the base class or instance from a zephyr class, by removing
583   leading `un' or trailing `.d'.
584   The caller is responsible for freeing the allocated string.
585*/
586char * owl_util_baseclass(const char * class)
587{
588  char *start, *end;
589
590  while(!strncmp(class, "un", 2)) {
591    class += 2;
592  }
593
594  start = owl_strdup(class);
595  end = start + strlen(start) - 1;
596  while(end > start && *end == 'd' && *(end-1) == '.') {
597    end -= 2;
598  }
599  *(end + 1) = 0;
600
601  return start;
602}
603
604const char * owl_get_datadir(void)
605{
606  const char * datadir = getenv("BARNOWL_DATA_DIR");
607  if(datadir != NULL)
608    return datadir;
609  return DATADIR;
610}
611
612const char * owl_get_bindir(void)
613{
614  const char * bindir = getenv("BARNOWL_BIN_DIR");
615  if(bindir != NULL)
616    return bindir;
617  return BINDIR;
618}
619
620/* Strips format characters from a valid utf-8 string. Returns the
621   empty string if 'in' does not validate. */
622char * owl_strip_format_chars(const char *in)
623{
624  char *r;
625  if (g_utf8_validate(in, -1, NULL)) {
626    const char *s, *p;
627    r = owl_malloc(strlen(in)+1);
628    r[0] = '\0';
629    s = in;
630    p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
631    while(p) {
632      /* If it's a format character, copy up to it, and skip all
633         immediately following format characters. */
634      if (owl_fmtext_is_format_char(g_utf8_get_char(p))) {
635        strncat(r, s, p-s);
636        p = g_utf8_next_char(p);
637        while (owl_fmtext_is_format_char(g_utf8_get_char(p))) {
638          p = g_utf8_next_char(p);
639        }
640        s = p;
641        p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
642      }
643      else {
644        p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
645      }
646    }
647    if (s) strcat(r,s);
648  }
649  else {
650    r = owl_strdup("");
651  }
652  return r;
653}
654
655/* If in is not UTF-8, convert from ISO-8859-1. We may want to allow
656 * the caller to specify an alternative in the future. We also strip
657 * out characters in Unicode Plane 16, as we use that plane internally
658 * for formatting.
659 */
660char * owl_validate_or_convert(const char *in)
661{
662  if (g_utf8_validate(in, -1, NULL)) {
663    return owl_strip_format_chars(in);
664  }
665  else {
666    return g_convert(in, -1,
667                     "UTF-8", "ISO-8859-1",
668                     NULL, NULL, NULL);
669  }
670}
671/*
672 * Validate 'in' as UTF-8, and either return a copy of it, or an empty
673 * string if it is invalid utf-8.
674 */
675char * owl_validate_utf8(const char *in)
676{
677  char *out;
678  if (g_utf8_validate(in, -1, NULL)) {
679    out = owl_strdup(in);
680  } else {
681    out = owl_strdup("");
682  }
683  return out;
684}
685
686/* This is based on _extract() and _isCJ() from perl's Text::WrapI18N */
687int owl_util_can_break_after(gunichar c)
688{
689 
690  if (c == ' ') return 1;
691  if (c >= 0x3000 && c <= 0x312f) {
692    /* CJK punctuations, Hiragana, Katakana, Bopomofo */
693    if (c == 0x300a || c == 0x300c || c == 0x300e ||
694        c == 0x3010 || c == 0x3014 || c == 0x3016 ||
695        c == 0x3018 || c == 0x301a)
696      return 0;
697    return 1;
698  }
699  if (c >= 0x31a0 && c <= 0x31bf) {return 1;}  /* Bopomofo */
700  if (c >= 0x31f0 && c <= 0x31ff) {return 1;}  /* Katakana extension */
701  if (c >= 0x3400 && c <= 0x9fff) {return 1;}  /* Han Ideogram */
702  if (c >= 0xf900 && c <= 0xfaff) {return 1;}  /* Han Ideogram */
703  if (c >= 0x20000 && c <= 0x2ffff) {return 1;}  /* Han Ideogram */
704  return 0;
705}
706
707char *owl_escape_highbit(const char *str)
708{
709  GString *out = g_string_new("");
710  unsigned char c;
711  while((c = (*str++))) {
712    if(c == '\\') {
713      g_string_append(out, "\\\\");
714    } else if(c & 0x80) {
715      g_string_append_printf(out, "\\x%02x", (int)c);
716    } else {
717      g_string_append_c(out, c);
718    }
719  }
720  return g_string_free(out, 0);
721}
722
723/* innards of owl_getline{,_chomp} below */
724static int owl_getline_internal(char **s, FILE *fp, int newline)
725{
726  int size = 0;
727  int target = 0;
728  int count = 0;
729  int c;
730
731  while (1) {
732    c = getc(fp);
733    if ((target + 1) > size) {
734      size += BUFSIZ;
735      *s = owl_realloc(*s, size);
736    }
737    if (c == EOF)
738      break;
739    count++;
740    if (c != '\n' || newline)
741        (*s)[target++] = c;
742    if (c == '\n')
743      break;
744  }
745  (*s)[target] = 0;
746
747  return count;
748}
749
750/* Read a line from fp, allocating memory to hold it, returning the number of
751 * byte read.  *s should either be NULL or a pointer to memory allocated with
752 * owl_malloc; it will be owl_realloc'd as appropriate.  The caller must
753 * eventually free it.  (This is roughly the interface of getline in the gnu
754 * libc).
755 *
756 * The final newline will be included if it's there.
757 */
758int owl_getline(char **s, FILE *fp)
759{
760  return owl_getline_internal(s, fp, 1);
761}
762
763/* As above, but omitting the final newline */
764int owl_getline_chomp(char **s, FILE *fp)
765{
766  return owl_getline_internal(s, fp, 0);
767}
768
769/* Read the rest of the input available in fp into a string. */
770char *owl_slurp(FILE *fp)
771{
772  char *buf = NULL;
773  char *p;
774  int size = 0;
775  int count;
776
777  while (1) {
778    buf = owl_realloc(buf, size + BUFSIZ);
779    p = &buf[size];
780    size += BUFSIZ;
781
782    if ((count = fread(p, 1, BUFSIZ, fp)) < BUFSIZ)
783      break;
784  }
785  p[count] = 0;
786
787  return buf;
788}
Note: See TracBrowser for help on using the repository browser.