source: util.c @ 6dc2d6b

release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 6dc2d6b was 4d86e06, checked in by Anders Kaseorg <andersk@mit.edu>, 13 years ago
Get rid of a whole bunch of useless casts. Signed-off-by: Anders Kaseorg <andersk@mit.edu>
  • Property mode set to 100644
File size: 18.8 KB
RevLine 
[7d4fbcd]1#include "owl.h"
2#include <stdlib.h>
3#include <string.h>
[5145235]4#include <unistd.h>
[7d4fbcd]5#include <ctype.h>
[f36222f]6#include <pwd.h>
[7d4fbcd]7
[e4eebe8]8void sepbar(char *in)
9{
[7d4fbcd]10  char buff[1024];
11  WINDOW *sepwin;
12  owl_messagelist *ml;
13  owl_view *v;
14  int x, y, i;
15  char *foo, *appendtosepbar;
16
17  sepwin=owl_global_get_curs_sepwin(&g);
18  ml=owl_global_get_msglist(&g);
19  v=owl_global_get_current_view(&g);
20
21  werase(sepwin);
22  wattron(sepwin, A_REVERSE);
[c15bbfb]23  if (owl_global_is_fancylines(&g)) {
24    whline(sepwin, ACS_HLINE, owl_global_get_cols(&g));
25  } else {
26    whline(sepwin, '-', owl_global_get_cols(&g));
27  }
[7d4fbcd]28
[73624b4]29  if (owl_global_is_sepbar_disable(&g)) {
30    getyx(sepwin, y, x);
31    wmove(sepwin, y, owl_global_get_cols(&g)-1);
32    return;
33  }
34
[7d4fbcd]35  wmove(sepwin, 0, 2); 
36
37  if (owl_messagelist_get_size(ml)==0) {
38    strcpy(buff, " (-/-) ");
39  } else {
[1c6c4d3]40    snprintf(buff, 1024, " (%i/%i/%i) ", owl_global_get_curmsg(&g)+1,
[7d4fbcd]41            owl_view_get_size(v),
42            owl_messagelist_get_size(ml));
43  }
44  waddstr(sepwin, buff);
45
46  foo=owl_view_get_filtname(v);
[330bcec]47  if (strcmp(foo, owl_global_get_view_home(&g))) wattroff(sepwin, A_REVERSE);
[7d4fbcd]48  waddstr(sepwin, " ");
49  waddstr(sepwin, owl_view_get_filtname(v));
50  waddstr(sepwin, " ");
[330bcec]51  if (strcmp(foo, owl_global_get_view_home(&g))) wattron(sepwin, A_REVERSE);
[7d4fbcd]52
53  if (owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
54    getyx(sepwin, y, x);
55    wmove(sepwin, y, x+2);
56    wattron(sepwin, A_BOLD);
57    waddstr(sepwin, " <truncated> ");
58    wattroff(sepwin, A_BOLD);
59  }
60
61  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
62  if ((i != -1) &&
63      (i < owl_view_get_size(v)-1)) {
64    getyx(sepwin, y, x);
65    wmove(sepwin, y, x+2);
66    wattron(sepwin, A_BOLD);
67    waddstr(sepwin, " <more> ");
68    wattroff(sepwin, A_BOLD);
69  }
70
71  if (owl_global_get_rightshift(&g)>0) {
72    getyx(sepwin, y, x);
73    wmove(sepwin, y, x+2);
[1c6c4d3]74    snprintf(buff, 1024, " right: %i ", owl_global_get_rightshift(&g));
[7d4fbcd]75    waddstr(sepwin, buff);
76  }
77
[4b660cc]78  if (owl_global_is_zaway(&g) || owl_global_is_aaway(&g)) {
[7d4fbcd]79    getyx(sepwin, y, x);
80    wmove(sepwin, y, x+2);
81    wattron(sepwin, A_BOLD);
82    wattroff(sepwin, A_REVERSE);
[4b660cc]83    if (owl_global_is_zaway(&g) && owl_global_is_aaway(&g)) {
84      waddstr(sepwin, " AWAY ");
85    } else if (owl_global_is_zaway(&g)) {
86      waddstr(sepwin, " Z-AWAY ");
87    } else if (owl_global_is_aaway(&g)) {
88      waddstr(sepwin, " A-AWAY ");
89    }
[7d4fbcd]90    wattron(sepwin, A_REVERSE);
91    wattroff(sepwin, A_BOLD);
92  }
93
94  if (owl_global_get_curmsg_vert_offset(&g)) {
95    getyx(sepwin, y, x);
96    wmove(sepwin, y, x+2);
97    wattron(sepwin, A_BOLD);
98    wattroff(sepwin, A_REVERSE);
99    waddstr(sepwin, " SCROLL ");
100    wattron(sepwin, A_REVERSE);
101    wattroff(sepwin, A_BOLD);
102  }
103 
104  if (in) {
105    getyx(sepwin, y, x);
106    wmove(sepwin, y, x+2);
107    waddstr(sepwin, in);
108  }
109
110  appendtosepbar = owl_global_get_appendtosepbar(&g);
111  if (appendtosepbar && *appendtosepbar) {
112    getyx(sepwin, y, x);
113    wmove(sepwin, y, x+2);
114    waddstr(sepwin, " ");
115    waddstr(sepwin, owl_global_get_appendtosepbar(&g));
116    waddstr(sepwin, " ");
117  }
118
119  getyx(sepwin, y, x);
120  wmove(sepwin, y, owl_global_get_cols(&g)-1);
121   
122  wattroff(sepwin, A_BOLD);
123  wattroff(sepwin, A_REVERSE);
124  wnoutrefresh(sepwin);
125}
126
[e4eebe8]127char **atokenize(char *buffer, char *sep, int *i)
128{
[7d4fbcd]129  /* each element of return must be freed by user */
130  char **args;
131  char *workbuff, *foo;
132  int done=0, first=1, count=0;
133
134  workbuff=owl_malloc(strlen(buffer)+1);
135  memcpy(workbuff, buffer, strlen(buffer)+1);
136
137  args=NULL;
138  while (!done) {
139    if (first) {
140      first=0;
[4d86e06]141      foo=strtok(workbuff, sep);
[7d4fbcd]142    } else {
[4d86e06]143      foo=strtok(NULL, sep);
[7d4fbcd]144    }
145    if (foo==NULL) {
146      done=1;
147    } else {
[4d86e06]148      args=owl_realloc(args, sizeof(char *) * (count+1));
[7d4fbcd]149      args[count]=owl_malloc(strlen(foo)+1);
150      strcpy(args[count], foo);
151      count++;
152    }
153  }
154  *i=count;
155  owl_free(workbuff);
156  return(args);
157}
158
159char *skiptokens(char *buff, int n) {
[42abb10]160  /* skips n tokens and returns where that would be.
161   * TODO: handle quotes more sanely. */
162 
[7d4fbcd]163  int inquotes=0;
164  while (*buff && n>0) {
165      while (*buff == ' ') buff++;
166      while (*buff && (inquotes || *buff != ' ')) { 
[e1c4636]167        if (*buff == '"' || *buff == '\'') inquotes=!inquotes;
[7d4fbcd]168        buff++;
169      }
170      while (*buff == ' ') buff++;
171      n--;
172  }
173  return buff;
174}
175
[f36222f]176/* Return a "nice" version of the path.  Tilde expansion is done, and
177 * duplicate slashes are removed.  Caller must free the return.
178 */
179char *owl_util_makepath(char *in)
180{
181  int i, j, x;
182  char *out, user[MAXPATHLEN];
183  struct passwd *pw;
184
185  out=owl_malloc(MAXPATHLEN+1);
186  out[0]='\0';
187  j=strlen(in);
188  x=0;
189  for (i=0; i<j; i++) {
190    if (in[i]=='~') {
191      if ( (i==(j-1)) ||          /* last character */
192           (in[i+1]=='/') ) {     /* ~/ */
193        /* use my homedir */
194        pw=getpwuid(getuid());
195        if (!pw) {
196          out[x]=in[i];
197        } else {
198          out[x]='\0';
199          strcat(out, pw->pw_dir);
200          x+=strlen(pw->pw_dir);
201        }
202      } else {
203        /* another user homedir */
204        int a, b;
205        b=0;
206        for (a=i+1; i<j; a++) {
207          if (in[a]==' ' || in[a]=='/') {
208            break;
209          } else {
210            user[b]=in[a];
211            i++;
212            b++;
213          }
214        }
215        user[b]='\0';
216        pw=getpwnam(user);
217        if (!pw) {
[8766d44]218          out[x]=in[i];
[f36222f]219        } else {
220          out[x]='\0';
221          strcat(out, pw->pw_dir);
222          x+=strlen(pw->pw_dir);
223        }
224      }
225    } else if (in[i]=='/') {
226      /* check for a double / */
227      if (i<(j-1) && (in[i+1]=='/')) {
228        /* do nothing */
229      } else {
230        out[x]=in[i];
231        x++;
232      }
233    } else {
234      out[x]=in[i];
235      x++;
236    }
237  }
238  out[x]='\0';
239  return(out);
240}
241
[e4eebe8]242void atokenize_free(char **tok, int nels)
243{
[7d4fbcd]244  int i;
245  for (i=0; i<nels; i++) {
246    owl_free(tok[i]);
247  }
248  owl_free(tok);
249}
250
251
[e4eebe8]252void owl_parsefree(char **argv, int argc)
253{
[7d4fbcd]254  int i;
255
256  if (!argv) return;
257 
258  for (i=0; i<argc; i++) {
259    if (argv[i]) owl_free(argv[i]);
260  }
261  owl_free(argv);
262}
263
[e4eebe8]264char **owl_parseline(char *line, int *argc)
265{
[7d4fbcd]266  /* break a command line up into argv, argc.  The caller must free
267     the returned values.  If there is an error argc will be set to
268     -1, argv will be NULL and the caller does not need to free
269     anything */
270
271  char **argv;
272  int i, len, between=1;
273  char *curarg;
274  char quote;
275
276  argv=owl_malloc(sizeof(char *));
277  len=strlen(line);
278  curarg=owl_malloc(len+10);
279  strcpy(curarg, "");
280  quote='\0';
281  *argc=0;
282  for (i=0; i<len+1; i++) {
283    /* find the first real character */
284    if (between) {
285      if (line[i]==' ' || line[i]=='\t' || line[i]=='\0') {
286        continue;
287      } else {
288        between=0;
289        i--;
290        continue;
291      }
292    }
293
294    /* deal with a quote character */
295    if (line[i]=='"' || line[i]=="'"[0]) {
296      /* if this type of quote is open, close it */
297      if (quote==line[i]) {
298        quote='\0';
299        continue;
300      }
301
302      /* if no quoting is open then open with this */
303      if (quote=='\0') {
304        quote=line[i];
305        continue;
306      }
307
308      /* if another type of quote is open then treat this as a literal */
309      curarg[strlen(curarg)+1]='\0';
310      curarg[strlen(curarg)]=line[i];
311      continue;
312    }
313
314    /* if it's not a space or end of command, then use it */
315    if (line[i]!=' ' && line[i]!='\t' && line[i]!='\n' && line[i]!='\0') {
316      curarg[strlen(curarg)+1]='\0';
317      curarg[strlen(curarg)]=line[i];
318      continue;
319    }
320
321    /* otherwise, if we're not in quotes, add the whole argument */
322    if (quote=='\0') {
323      /* add the argument */
324      argv=owl_realloc(argv, sizeof(char *)*((*argc)+1));
325      argv[*argc]=owl_malloc(strlen(curarg)+2);
326      strcpy(argv[*argc], curarg);
327      *argc=*argc+1;
328      strcpy(curarg, "");
329      between=1;
330      continue;
331    }
332
333    /* if it is a space and we're in quotes, then use it */
334    curarg[strlen(curarg)+1]='\0';
335    curarg[strlen(curarg)]=line[i];
336  }
337
[d524c83]338  owl_free(curarg);
[95caa16]339
[7d4fbcd]340  /* check for unbalanced quotes */
341  if (quote!='\0') {
342    owl_parsefree(argv, *argc);
343    *argc=-1;
344    return(NULL);
345  }
346
347  return(argv);
348}
349
[de03334]350/* caller must free the return */
[5b85d19]351char *owl_util_minutes_to_timestr(int in)
[de03334]352{
[f1e629d]353  int days, hours;
[de03334]354  long run;
355  char *out;
356
[5b85d19]357  run=in;
[de03334]358
[5b85d19]359  days=run/1440;
360  run-=days*1440;
361  hours=run/60;
362  run-=hours*60;
[de03334]363
364  if (days>0) {
[6eaf35b]365    out=owl_sprintf("%i d %2.2i:%2.2li", days, hours, run);
[de03334]366  } else {
[6eaf35b]367    out=owl_sprintf("    %2.2i:%2.2li", hours, run);
[de03334]368  }
369  return(out);
370}
371
[42abb10]372/* hooks for doing memory allocation et. al. in owl */
373
[e4eebe8]374void *owl_malloc(size_t size)
375{
[34509d5]376  return(g_malloc(size));
[7d4fbcd]377}
378
[e4eebe8]379void owl_free(void *ptr)
380{
[34509d5]381  g_free(ptr);
[7d4fbcd]382}
383
[e4eebe8]384char *owl_strdup(const char *s1)
385{
[34509d5]386  return(g_strdup(s1));
[7d4fbcd]387}
388
[e4eebe8]389void *owl_realloc(void *ptr, size_t size)
390{
[34509d5]391  return(g_realloc(ptr, size));
[7d4fbcd]392}
393
[e4eebe8]394/* allocates memory and returns the string or null.
395 * caller must free the string.
396 */
397char *owl_sprintf(const char *fmt, ...)
398{
[1c6c4d3]399  va_list ap;
[28ee32b]400  char *ret = NULL;
401  va_start(ap, fmt);
402  ret = g_strdup_vprintf(fmt, ap);
403  va_end(ap);
404  return ret;
[1c6c4d3]405}
406
[28ee32b]407
[12c35df]408/* Return the owl color associated with the named color.  Return -1
409 * if the named color is not available
410 */
[e4eebe8]411int owl_util_string_to_color(char *color)
412{
[c2c5c77]413  int c;
[7d4fbcd]414  if (!strcasecmp(color, "black")) {
415    return(OWL_COLOR_BLACK);
416  } else if (!strcasecmp(color, "red")) {
417    return(OWL_COLOR_RED);
418  } else if (!strcasecmp(color, "green")) {
419    return(OWL_COLOR_GREEN);
420  } else if (!strcasecmp(color, "yellow")) {
421    return(OWL_COLOR_YELLOW);
422  } else if (!strcasecmp(color, "blue")) {
423    return(OWL_COLOR_BLUE);
424  } else if (!strcasecmp(color, "magenta")) {
425    return(OWL_COLOR_MAGENTA);
426  } else if (!strcasecmp(color, "cyan")) {
427    return(OWL_COLOR_CYAN);
428  } else if (!strcasecmp(color, "white")) {
429    return(OWL_COLOR_WHITE);
430  } else if (!strcasecmp(color, "default")) {
431    return(OWL_COLOR_DEFAULT);
432  }
[c2c5c77]433  c = atoi(color);
434  if (c >= -1 && c < COLORS) {
435    return(c);
436  }
[601733d]437  return(OWL_COLOR_INVALID);
[7d4fbcd]438}
439
[e4eebe8]440/* Return a string name of the given owl color */
441char *owl_util_color_to_string(int color)
442{
[7d4fbcd]443  if (color==OWL_COLOR_BLACK)   return("black");
444  if (color==OWL_COLOR_RED)     return("red");
445  if (color==OWL_COLOR_GREEN)   return("green");
446  if (color==OWL_COLOR_YELLOW)  return("yellow");
447  if (color==OWL_COLOR_BLUE)    return("blue");
448  if (color==OWL_COLOR_MAGENTA) return("magenta");
449  if (color==OWL_COLOR_CYAN)    return("cyan");
450  if (color==OWL_COLOR_WHITE)   return("white");
451  if (color==OWL_COLOR_DEFAULT) return("default");
452  return("Unknown color");
453}
[e1c4636]454
[e4eebe8]455/* Get the default tty name.  Caller must free the return */
456char *owl_util_get_default_tty()
457{
[5145235]458  char *out, *tmp;
[61e79a9]459
460  if (getenv("DISPLAY")) {
461    out=owl_strdup(getenv("DISPLAY"));
[5145235]462  } else if ((tmp=ttyname(fileno(stdout)))!=NULL) {
463    out=owl_strdup(tmp);
[61e79a9]464    if (!strncmp(out, "/dev/", 5)) {
465      owl_free(out);
[5145235]466      out=owl_strdup(tmp+5);
[61e79a9]467    }
468  } else {
[5145235]469    out=owl_strdup("unknown");
[61e79a9]470  }
471  return(out);
472}
473
474
[e4eebe8]475/* Animation hack */
476void owl_hack_animate()
477{
[4b464a4]478  owl_messagelist *ml;
479  owl_message *m;
480  owl_fmtext *fm;
481  char *text, *ptr;
482  int place;
483
484  /* grab the first message and make sure its id is 0 */
485  ml=owl_global_get_msglist(&g);
486  m=owl_messagelist_get_element(ml, 0);
487  if (!m) return;
488  if (owl_message_get_id(m)!=0) return;
489
490  fm=owl_message_get_fmtext(m);
491  text=owl_fmtext_get_text(fm);
492
493  ptr=strstr(text, "OvO");
494  if (ptr) {
495    place=ptr-text;
496    owl_fmtext_set_char(fm, place, '-');
497    owl_fmtext_set_char(fm, place+2, '-');
498
499    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
[a15a84f]500    if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
501      owl_popwin_refresh(owl_global_get_popwin(&g));
502      /* TODO: this is a broken kludge */
503      if (owl_global_get_viewwin(&g)) {
504        owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
505      }
506    }
[4b464a4]507    owl_global_set_needrefresh(&g);
508    return;
509  }
510
511  ptr=strstr(text, "-v-");
512  if (ptr) {
513    place=ptr-text;
514    owl_fmtext_set_char(fm, place, 'O');
515    owl_fmtext_set_char(fm, place+2, 'O');
516
517    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
[a15a84f]518    if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
519      owl_popwin_refresh(owl_global_get_popwin(&g));
520      /* TODO: this is a broken kludge */
521      if (owl_global_get_viewwin(&g)) {
522        owl_viewwin_redisplay(owl_global_get_viewwin(&g), 0);
523      }
524    }
[4b464a4]525    owl_global_set_needrefresh(&g);
526    return;
527  }
528}
[e1c4636]529
[e4eebe8]530/* strip leading and trailing new lines.  Caller must free the
531 * return.
532 */
533char *owl_util_stripnewlines(char *in)
534{
[7e3e00a]535 
536  char  *tmp, *ptr1, *ptr2, *out;
537
538  ptr1=tmp=owl_strdup(in);
539  while (ptr1[0]=='\n') {
540    ptr1++;
541  }
542  ptr2=ptr1+strlen(ptr1)-1;
[1bb1e67]543  while (ptr2>ptr1 && ptr2[0]=='\n') {
[7e3e00a]544    ptr2[0]='\0';
545    ptr2--;
546  }
547
548  out=owl_strdup(ptr1);
549  owl_free(tmp);
550  return(out);
551}
552
[38cf544c]553/* Delete the line matching "line" from the named file.  If no such
554 * line is found the file is left intact.  If backup==1 then create a
555 * backupfile containing the original contents.  This is an
556 * inefficient impelementation which reads the entire file into
557 * memory.
558 */
559void owl_util_file_deleteline(char *filename, char *line, int backup)
560{
561  char buff[LINE], *text;
[e6449bc]562  char *backupfilename="";
563  FILE *file, *backupfile=NULL;
[38cf544c]564  int size, newline;
565
566  /* open the file for reading */
567  file=fopen(filename, "r");
568  if (!file) {
[836ea3a3]569    owl_function_error("Error opening file %s", filename);
[38cf544c]570    return;
571  }
[e6449bc]572
[38cf544c]573  /* open the backup file for writing */
574  if (backup) {
575    backupfilename=owl_sprintf("%s.backup", filename);
576    backupfile=fopen(backupfilename, "w");
577    if (!backupfile) {
[836ea3a3]578      owl_function_error("Error opening file %s for writing", backupfilename);
[378fa14]579      owl_free(backupfilename);
[e97c4a30]580      fclose(file);
[38cf544c]581      return;
582    }
583  }
584
585  /* we'll read the entire file into memory, minus the line we don't want and
586   * and at the same time create the backup file if necessary
587   */
588  text=owl_malloc(LINE);
589  strcpy(text, "");
590  size=LINE;
591  while (fgets(buff, LINE, file)!=NULL) {
592    /* strip the newline */
593    newline=0;
594    if (buff[strlen(buff)-1]=='\n') {
595      buff[strlen(buff)-1]='\0';
596      newline=1;
597    }
598   
599    /* if we don't match the line, add to saved text in memory */
600    if (strcasecmp(buff, line)) {
601      size+=LINE;
602      text=owl_realloc(text, size);
603      strcat(text, buff);
604      if (newline) strcat(text, "\n");
605    }
606
607    /* write to backupfile if necessary */
[6a50af2]608    if (backup) {
609      fputs(buff, backupfile);
610      if (newline) fputs("\n", backupfile);
611    }
[38cf544c]612  }
[65ad073]613  if (backup) fclose(backupfile);
[38cf544c]614  fclose(file);
615
616  /* now rewrite the original file from memory */
617  file=fopen(filename, "w");
618  if (!file) {
[836ea3a3]619    owl_function_error("WARNING: Error opening %s for writing.  Use %s to restore.", filename, backupfilename);
[38cf544c]620    owl_function_beep();
[e97c4a30]621  } else {
622    fputs(text, file);
623    fclose(file);
[38cf544c]624  }
625
[e97c4a30]626  if (backup)
627    owl_free(backupfilename);
628  owl_free(text);
[38cf544c]629}
630
[fe67f1f]631int owl_util_max(int a, int b)
632{
633  if (a>b) return(a);
634  return(b);
635}
636
637int owl_util_min(int a, int b)
638{
639  if (a<b) return(a);
640  return(b);
641}
642
[7a20e4c]643/* Return the base class or instance from a zephyr class, by removing
644   leading `un' or trailing `.d'.
[be5aa09]645   The caller is responsible for freeing the allocated string.
[7a20e4c]646*/
647char * owl_util_baseclass(char * class)
648{
[59916e8]649  char *start, *end;
650
[f166580]651  start = class;
[59916e8]652  while(!strncmp(start, "un", 2)) {
653    start += 2;
[7a20e4c]654  }
[f166580]655
656  start = owl_strdup(start);
[59916e8]657  end = start + strlen(start) - 1;
[04166e9]658  while(end > start && *end == 'd' && *(end-1) == '.') {
[7a20e4c]659    end -= 2;
660  }
661  *(end + 1) = 0;
[59916e8]662
[f166580]663  return start;
[7a20e4c]664}
665
[5376a95]666char * owl_get_datadir()
667{
668  char * datadir = getenv("BARNOWL_DATA_DIR");
669  if(datadir != NULL)
[7bf51d5]670    return datadir;
[5376a95]671  return DATADIR;
672}
673
674/* Strips format characters from a valid utf-8 string. Returns the
675   empty string if 'in' does not validate. */
[7f6a8a2]676char * owl_strip_format_chars(const char *in)
[5376a95]677{
678  char *r;
679  if (g_utf8_validate(in, -1, NULL)) {
[7f6a8a2]680    const char *s, *p;
[5376a95]681    r = owl_malloc(strlen(in)+1);
682    r[0] = '\0';
683    s = in;
684    p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
685    while(p) {
686      /* If it's a format character, copy up to it, and skip all
687         immediately following format characters. */
[c1522ec]688      if (owl_fmtext_is_format_char(g_utf8_get_char(p))) {
[5376a95]689        strncat(r, s, p-s);
690        p = g_utf8_next_char(p);
[c1522ec]691        while (p && owl_fmtext_is_format_char(g_utf8_get_char(p))) {
[5376a95]692          p = g_utf8_next_char(p);
693        }
694        s = p;
695        p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
696      }
697      else {
698        p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
699      }
700    }
701    if (s) strcat(r,s);
702  }
703  else {
704    r = owl_strdup("");
705  }
706  return r;
707}
708
709/* If in is not UTF-8, convert from ISO-8859-1. We may want to allow
710 * the caller to specify an alternative in the future. We also strip
711 * out characters in Unicode Plane 16, as we use that plane internally
712 * for formatting.
713 */
[7f6a8a2]714char * owl_validate_or_convert(const char *in)
[5376a95]715{
[6201646]716  if (g_utf8_validate(in, -1, NULL)) {
[5376a95]717    return owl_strip_format_chars(in);
718  }
719  else {
[6201646]720    return g_convert(in, -1,
[5376a95]721                     "UTF-8", "ISO-8859-1",
722                     NULL, NULL, NULL);
723  }
[89f5338]724}
[4b17a6c]725/*
726 * Validate 'in' as UTF-8, and either return a copy of it, or an empty
727 * string if it is invalid utf-8.
[7b1d048]728 */
[7f6a8a2]729char * owl_validate_utf8(const char *in)
[7b1d048]730{
731  char *out;
732  if (g_utf8_validate(in, -1, NULL)) {
[4b17a6c]733    out = owl_strdup(in);
734  } else {
[7b1d048]735    out = owl_strdup("");
736  }
737  return out;
738}
[89f5338]739
[84027015]740/* This is based on _extract() and _isCJ() from perl's Text::WrapI18N */
741int owl_util_can_break_after(gunichar c)
742{
743 
744  if (c == ' ') return 1;
745  if (c >= 0x3000 && c <= 0x312f) {
746    /* CJK punctuations, Hiragana, Katakana, Bopomofo */
747    if (c == 0x300a || c == 0x300c || c == 0x300e ||
748        c == 0x3010 || c == 0x3014 || c == 0x3016 ||
749        c == 0x3018 || c == 0x301a)
750      return 0;
751    return 1;
752  }
753  if (c >= 0x31a0 && c <= 0x31bf) {return 1;}  /* Bopomofo */
754  if (c >= 0x31f0 && c <= 0x31ff) {return 1;}  /* Katakana extension */
755  if (c >= 0x3400 && c <= 0x9fff) {return 1;}  /* Han Ideogram */
756  if (c >= 0xf900 && c <= 0xfaff) {return 1;}  /* Han Ideogram */
757  if (c >= 0x20000 && c <= 0x2ffff) {return 1;}  /* Han Ideogram */
758  return 0;
759}
760
[e1c4636]761/**************************************************************************/
762/************************* REGRESSION TESTS *******************************/
763/**************************************************************************/
764
765#ifdef OWL_INCLUDE_REG_TESTS
766
[0138478]767#include "test.h"
[e1c4636]768
[e4eebe8]769int owl_util_regtest(void)
770{
[e1c4636]771  int numfailed=0;
772
[1cf3f8d3]773  printf("# BEGIN testing owl_util\n");
[e1c4636]774
775  FAIL_UNLESS("owl_util_substitute 1",
[e3d9c77]776              !strcmp("foo", owl_text_substitute("foo", "", "Y")));
777  FAIL_UNLESS("owl_text_substitute 2",
778              !strcmp("fYZYZ", owl_text_substitute("foo", "o", "YZ")));
779  FAIL_UNLESS("owl_text_substitute 3",
780              !strcmp("foo", owl_text_substitute("fYZYZ", "YZ", "o")));
781  FAIL_UNLESS("owl_text_substitute 4",
782              !strcmp("/u/foo/meep", owl_text_substitute("~/meep", "~", "/u/foo")));
[e1c4636]783
784  FAIL_UNLESS("skiptokens 1", 
785              !strcmp("bar quux", skiptokens("foo bar quux", 1)));
786  FAIL_UNLESS("skiptokens 2", 
787              !strcmp("meep", skiptokens("foo 'bar quux' meep", 2)));
788
[3e8ff1e]789  FAIL_UNLESS("expand_tabs 1",
790              !strcmp("        hi", owl_text_expand_tabs("\thi")));
791
792  FAIL_UNLESS("expand_tabs 2",
793              !strcmp("        hi\nword    tab", owl_text_expand_tabs("\thi\nword\ttab")));
794
795  FAIL_UNLESS("expand_tabs 3",
796              !strcmp("                2 tabs", owl_text_expand_tabs("\t\t2 tabs")));
797
[af1920fd]798  /* if (numfailed) printf("*** WARNING: failures encountered with owl_util\n"); */
[1cf3f8d3]799  printf("# END testing owl_util (%d failures)\n", numfailed);
[e1c4636]800  return(numfailed);
801}
802
803#endif /* OWL_INCLUDE_REG_TESTS */
Note: See TracBrowser for help on using the repository browser.