source: fmtext.c @ 2c8a07c

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 2c8a07c was e1c4636, checked in by Erik Nygren <nygren@mit.edu>, 19 years ago
* Added owl::send_zwrite(command, message) to the perl glue to allow for the direct sending of multi-line messages. For example: owl::send_zwrite("-c foo -i bar", "hello"); * Reverted attempted fix for the pagedown problem which just made things worse. * Changed owl_fmtext_print_plain to return an alloc'd string to avoid buffer overrun risks. * Added owl::ztext_stylestrip("...") function to perlglue which returns the ztext with formatting stripped out. * Added colorztext variable which can be used to disable @color() strings arriving in messages after it is set. (Currently, changing its value won't reformat messages). * Outgoing zephyr logging now obeys the logpath variable. * The '~' character in logpath and classlogpath now gets replaced with the user's home directory.
  • Property mode set to 100644
File size: 13.0 KB
Line 
1#include "owl.h"
2#include <stdlib.h>
3#include <string.h>
4
5static const char fileIdent[] = "$Id$";
6
7void owl_fmtext_init_null(owl_fmtext *f) {
8  f->textlen=0;
9  f->textbuff=owl_strdup("");
10  f->fmbuff=owl_malloc(5);
11  f->colorbuff=owl_malloc(5);
12  f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
13  f->colorbuff[0]=OWL_COLOR_DEFAULT;
14}
15
16
17void _owl_fmtext_set_attr(owl_fmtext *f, int attr, int first, int last) {
18  int i;
19  for (i=first; i<=last; i++) {
20    f->fmbuff[i]=(unsigned char) attr;
21  }
22}
23
24void _owl_fmtext_set_color(owl_fmtext *f, int color, int first, int last) {
25  int i;
26  for (i=first; i<=last; i++) {
27    f->colorbuff[i]=(unsigned char) color;
28  }
29}
30
31
32void owl_fmtext_append_attr(owl_fmtext *f, char *text, int attr, int color) {
33  int newlen;
34
35  newlen=strlen(f->textbuff)+strlen(text);
36  f->textbuff=owl_realloc(f->textbuff, newlen+2);
37  f->fmbuff=owl_realloc(f->fmbuff, newlen+2);
38  f->colorbuff=owl_realloc(f->colorbuff, newlen+2);
39
40  strcat(f->textbuff, text);
41  _owl_fmtext_set_attr(f, attr, f->textlen, newlen);
42  _owl_fmtext_set_color(f, color, f->textlen, newlen);
43  f->textlen=newlen;
44}
45
46
47void owl_fmtext_append_normal(owl_fmtext *f, char *text) {
48  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_NONE, OWL_COLOR_DEFAULT);
49}
50
51void owl_fmtext_append_normal_color(owl_fmtext *f, char *text, int color) {
52  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_NONE, color);
53}
54
55
56void owl_fmtext_append_bold(owl_fmtext *f, char *text) {
57  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_BOLD, OWL_COLOR_DEFAULT);
58}
59
60
61void owl_fmtext_append_reverse(owl_fmtext *f, char *text) {
62  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_REVERSE, OWL_COLOR_DEFAULT);
63}
64
65
66void owl_fmtext_append_reversebold(owl_fmtext *f, char *text) {
67  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_REVERSE | OWL_FMTEXT_ATTR_BOLD, OWL_COLOR_DEFAULT);
68}
69
70
71void owl_fmtext_addattr(owl_fmtext *f, int attr) {
72  /* add the attribute to all text */
73  int i, j;
74
75  j=f->textlen;
76  for (i=0; i<j; i++) {
77    f->fmbuff[i] |= attr;
78  }
79}
80
81void owl_fmtext_colorize(owl_fmtext *f, int color) {
82  /* everywhere the color is OWL_COLOR_DEFAULT, change it to be 'color' */
83  int i, j;
84
85  j=f->textlen;
86  for(i=0; i<j; i++) {
87    if (f->colorbuff[i]==OWL_COLOR_DEFAULT) f->colorbuff[i] = color;
88  }
89}
90
91
92void owl_fmtext_append_ztext(owl_fmtext *f, char *text) {
93  int stacksize, curattrs, curcolor;
94  char *ptr, *txtptr, *buff, *tmpptr;
95  int attrstack[32], chrstack[32];
96
97  curattrs=OWL_FMTEXT_ATTR_NONE;
98  curcolor=OWL_COLOR_DEFAULT;
99  stacksize=0;
100  txtptr=text;
101  while (1) {
102    ptr=strpbrk(txtptr, "@{[<()>]}");
103    if (!ptr) {
104      /* add all the rest of the text and exit */
105      owl_fmtext_append_attr(f, txtptr, curattrs, curcolor);
106      return;
107    } else if (ptr[0]=='@') {
108      /* add the text up to this point then deal with the stack */
109      buff=owl_malloc(ptr-txtptr+20);
110      strncpy(buff, txtptr, ptr-txtptr);
111      buff[ptr-txtptr]='\0';
112      owl_fmtext_append_attr(f, buff, curattrs, curcolor);
113      owl_free(buff);
114
115      /* update pointer to point at the @ */
116      txtptr=ptr;
117
118      /* now the stack */
119
120      /* if we've hit our max stack depth, print the @ and move on */
121      if (stacksize==32) {
122        owl_fmtext_append_attr(f, "@", curattrs, curcolor);
123        txtptr++;
124        continue;
125      }
126
127      /* if it's an @@, print an @ and continue */
128      if (txtptr[1]=='@') {
129        owl_fmtext_append_attr(f, "@", curattrs, curcolor);
130        txtptr+=2;
131        continue;
132      }
133       
134      /* if there's no opener, print the @ and continue */
135      tmpptr=strpbrk(txtptr, "(<[{ ");
136      if (!tmpptr || tmpptr[0]==' ') {
137        owl_fmtext_append_attr(f, "@", curattrs, curcolor);
138        txtptr++;
139        continue;
140      }
141
142      /* check what command we've got, push it on the stack, start
143         using it, and continue ... unless it's a color command */
144      buff=owl_malloc(tmpptr-ptr+20);
145      strncpy(buff, ptr, tmpptr-ptr);
146      buff[tmpptr-ptr]='\0';
147      if (!strcasecmp(buff, "@bold")) {
148        attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD;
149        chrstack[stacksize]=tmpptr[0];
150        stacksize++;
151        curattrs|=OWL_FMTEXT_ATTR_BOLD;
152        txtptr+=6;
153        owl_free(buff);
154        continue;
155      } else if (!strcasecmp(buff, "@b")) {
156        attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD;
157        chrstack[stacksize]=tmpptr[0];
158        stacksize++;
159        curattrs|=OWL_FMTEXT_ATTR_BOLD;
160        txtptr+=3;
161        owl_free(buff);
162        continue;
163      } else if (!strcasecmp(buff, "@i")) {
164        attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE;
165        chrstack[stacksize]=tmpptr[0];
166        stacksize++;
167        curattrs|=OWL_FMTEXT_ATTR_UNDERLINE;
168        txtptr+=3;
169        owl_free(buff);
170        continue;
171      } else if (!strcasecmp(buff, "@italic")) {
172        attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE;
173        chrstack[stacksize]=tmpptr[0];
174        stacksize++;
175        curattrs|=OWL_FMTEXT_ATTR_UNDERLINE;
176        txtptr+=8;
177        owl_free(buff);
178        continue;
179
180        /* if it's a color read the color, set the current color and
181           continue */
182      } else if (!strcasecmp(buff, "@color") 
183                 && owl_global_get_hascolors(&g)
184                 && owl_global_is_colorztext(&g)) {
185        owl_free(buff);
186        txtptr+=7;
187        tmpptr=strpbrk(txtptr, "@{[<()>]}");
188        if (tmpptr &&
189            ((txtptr[-1]=='(' && tmpptr[0]==')') ||
190             (txtptr[-1]=='<' && tmpptr[0]=='>') ||
191             (txtptr[-1]=='[' && tmpptr[0]==']') ||
192             (txtptr[-1]=='{' && tmpptr[0]=='}'))) {
193
194          /* grab the color name */
195          buff=owl_malloc(tmpptr-txtptr+20);
196          strncpy(buff, txtptr, tmpptr-txtptr);
197          buff[tmpptr-txtptr]='\0';
198
199          /* set it as the current color */
200          curcolor=owl_util_string_to_color(buff);
201          owl_free(buff);
202          txtptr=tmpptr+1;
203          continue;
204
205        } else {
206
207        }
208
209      } else {
210        /* if we didn't understand it, we'll print it.  This is different from zwgc
211           but zwgc seems to be smarter about some screw cases than I am */
212        owl_fmtext_append_attr(f, "@", curattrs, curcolor);
213        txtptr++;
214        continue;
215      }
216
217    } else if (ptr[0]=='}' || ptr[0]==']' || ptr[0]==')' || ptr[0]=='>') {
218      /* add the text up to this point first */
219      buff=owl_malloc(ptr-txtptr+20);
220      strncpy(buff, txtptr, ptr-txtptr);
221      buff[ptr-txtptr]='\0';
222      owl_fmtext_append_attr(f, buff, curattrs, curcolor);
223      owl_free(buff);
224
225      /* now deal with the closer */
226      txtptr=ptr;
227
228      /* first, if the stack is empty we must bail (just print and go) */
229      if (stacksize==0) {
230        buff=owl_malloc(5);
231        buff[0]=ptr[0];
232        buff[1]='\0';
233        owl_fmtext_append_attr(f, buff, curattrs, curcolor);
234        owl_free(buff);
235        txtptr++;
236        continue;
237      }
238
239      /* if the closing char is what's on the stack, turn off the
240         attribue and pop the stack */
241      if ((ptr[0]==')' && chrstack[stacksize-1]=='(') ||
242          (ptr[0]=='>' && chrstack[stacksize-1]=='<') ||
243          (ptr[0]==']' && chrstack[stacksize-1]=='[') ||
244          (ptr[0]=='}' && chrstack[stacksize-1]=='{')) {
245        int i;
246        stacksize--;
247        curattrs=OWL_FMTEXT_ATTR_NONE;
248        for (i=0; i<stacksize; i++) {
249          curattrs|=attrstack[i];
250        }
251        txtptr+=1;
252        continue;
253      } else {
254        /* otherwise print and continue */
255        buff=owl_malloc(5);
256        buff[0]=ptr[0];
257        buff[1]='\0';
258        owl_fmtext_append_attr(f, buff, curattrs, curcolor);
259        owl_free(buff);
260        txtptr++;
261        continue;
262      }
263    } else {
264      /* we've found an unattached opener, print everything and move on */
265      buff=owl_malloc(ptr-txtptr+20);
266      strncpy(buff, txtptr, ptr-txtptr+1);
267      buff[ptr-txtptr+1]='\0';
268      owl_fmtext_append_attr(f, buff, curattrs, curcolor);
269      owl_free(buff);
270      txtptr=ptr+1;
271      continue;
272    }
273  }
274
275}
276
277void owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in, int start, int stop) {
278  int newlen, i;
279
280  newlen=strlen(f->textbuff)+(stop-start+1);
281  f->textbuff=owl_realloc(f->textbuff, newlen+1);
282  f->fmbuff=owl_realloc(f->fmbuff, newlen+1);
283  f->colorbuff=owl_realloc(f->colorbuff, newlen+1);
284
285  strncat(f->textbuff, in->textbuff+start, stop-start+1);
286  f->textbuff[newlen]='\0';
287  for (i=start; i<=stop; i++) {
288    f->fmbuff[f->textlen+(i-start)]=in->fmbuff[i];
289    f->colorbuff[f->textlen+(i-start)]=in->colorbuff[i];
290  }
291  f->textlen=newlen;
292}
293
294void owl_fmtext_append_spaces(owl_fmtext *f, int nspaces) {
295  int i;
296  for (i=0; i<nspaces; i++) {
297    owl_fmtext_append_normal(f, " ");
298  }
299}
300
301/* requires that the list values are strings or NULL.
302 * joins the elements together with join_with.
303 * If format_fn is specified, passes it the list element value
304 * and it will return a string which this needs to free. */
305void owl_fmtext_append_list(owl_fmtext *f, owl_list *l, char *join_with, char *(format_fn)(void*)) {
306  int i, size;
307  void *elem;
308  char *text;
309
310  size = owl_list_get_size(l);
311  for (i=0; i<size; i++) {
312    elem = (char*)owl_list_get_element(l,i);
313    if (elem && format_fn) {
314      text = format_fn(elem);
315      if (text) {
316        owl_fmtext_append_normal(f, text);
317        owl_free(text);
318      }
319    } else if (elem) {
320      owl_fmtext_append_normal(f, elem);
321    }
322    if ((i < size-1) && join_with) {
323      owl_fmtext_append_normal(f, join_with);
324    }
325  }
326}
327
328
329/* caller is responsible for freeing */
330char *owl_fmtext_print_plain(owl_fmtext *f) {
331  return owl_strdup(f->textbuff);
332}
333
334/* strips formatting from ztext and returns the unformatted text.
335 * caller is responsible for freeing. */
336char *owl_fmtext_ztext_stylestrip(char *zt) {
337  owl_fmtext fm;
338  char *plaintext;
339
340  owl_fmtext_init_null(&fm);
341  owl_fmtext_append_ztext(&fm, zt);
342  plaintext = owl_fmtext_print_plain(&fm);
343  owl_fmtext_free(&fm);
344  return(plaintext);
345}
346
347
348void owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w) {
349  char *tmpbuff;
350  int position, trans1, trans2, len, lastsame;
351
352  tmpbuff=owl_malloc(f->textlen+10);
353
354  position=0;
355  len=f->textlen;
356  while (position<=len) {
357    /* find the last char with the current format and color */
358    trans1=owl_util_find_trans(f->fmbuff+position, len-position);
359    trans2=owl_util_find_trans(f->colorbuff+position, len-position);
360
361    if (trans1<trans2) {
362      lastsame=position+trans1;
363    } else {
364      lastsame=position+trans2;
365    }
366
367    /* set the format */
368    wattrset(w, A_NORMAL);
369    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_BOLD) {
370      wattron(w, A_BOLD);
371    }
372    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_REVERSE) {
373      wattron(w, A_REVERSE);
374    }
375    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_UNDERLINE) {
376      wattron(w, A_UNDERLINE);
377    }
378
379    /* set the color */
380    /* warning, this is sort of a hack */
381    if (owl_global_get_hascolors(&g)) {
382      if (f->colorbuff[position]!=OWL_COLOR_DEFAULT) {
383        wattron(w, COLOR_PAIR(f->colorbuff[position]));
384      }
385    }
386
387    /* add the text */
388    strncpy(tmpbuff, f->textbuff + position, lastsame-position+1);
389    tmpbuff[lastsame-position+1]='\0';
390    waddstr(w, tmpbuff);
391
392    position=lastsame+1;
393  }
394  owl_free(tmpbuff);
395}
396
397
398int owl_fmtext_truncate_lines(owl_fmtext *in, int aline, int lines, owl_fmtext *out) {
399  /* start with line aline (where the first line is 0) and print
400   *  'lines' lines
401   */
402  char *ptr1, *ptr2;
403  int i, offset;
404
405  /* initialize out */
406  owl_fmtext_init_null(out);
407 
408  /* find the starting line */
409  ptr1=in->textbuff;
410  if (aline!=0) {
411    for (i=0; i<aline; i++) {
412      ptr1=strchr(ptr1, '\n');
413      if (!ptr1) return(-1);
414      ptr1++;
415    }
416  }
417  /* ptr1 now holds the starting point */
418
419  /* copy in the next 'lines' lines */
420  if (lines<1) return(-1);
421
422  for (i=0; i<lines; i++) {
423    ptr2=strchr(ptr1, '\n');
424    offset=ptr1-in->textbuff;
425    if (!ptr2) {
426      owl_fmtext_append_fmtext(out, in, offset, in->textlen-1);
427      return(-1);
428    }
429    owl_fmtext_append_fmtext(out, in, offset, (ptr2-ptr1)+offset);
430    ptr1=ptr2+1;
431  }
432  return(0);
433}
434
435
436void owl_fmtext_truncate_cols(owl_fmtext *in, int acol, int bcol, owl_fmtext *out) {
437  char *ptr1, *ptr2, *last;
438  int len, offset;
439 
440  /* the first column is column 0 */
441
442  /* the message is expected to end in a new line for now */
443
444  owl_fmtext_init_null(out);
445
446  last=in->textbuff+in->textlen-1;
447  ptr1=in->textbuff;
448  while (ptr1<=last) {
449    ptr2=strchr(ptr1, '\n');
450    if (!ptr2) {
451      /* but this shouldn't happen if we end in a \n */
452      break;
453    }
454   
455    if (ptr2==ptr1) {
456      owl_fmtext_append_normal(out, "\n");
457      ptr1++;
458      continue;
459    }
460
461    /* we need to check that we won't run over here */
462    len=bcol-acol;
463    if (len > (ptr2-(ptr1+acol))) {
464      len=ptr2-(ptr1+acol);
465    }
466    if (len>last-ptr1) {
467      len-=(last-ptr1);
468    }
469    if (len<=0) {
470      owl_fmtext_append_normal(out, "\n");
471      ptr1=ptr2+1;
472      continue;
473    }
474
475    offset=ptr1-in->textbuff;
476    owl_fmtext_append_fmtext(out, in, offset+acol, offset+acol+len);
477
478    ptr1=ptr2+1;
479  }
480}
481
482
483int owl_fmtext_num_lines(owl_fmtext *f) {
484  int lines, i;
485
486  lines=0;
487  for (i=0; f->textbuff[i]!='\0'; i++) {
488    if (f->textbuff[i]=='\n') lines++;
489  }
490
491  /* if the last char wasn't a \n there's one more line */
492  if (f->textbuff[i-1]!='\n') lines++;
493
494  return(lines);
495}
496
497
498char *owl_fmtext_get_text(owl_fmtext *f) {
499  return(f->textbuff);
500}
501
502void owl_fmtext_free(owl_fmtext *f) {
503  if (f->textbuff) owl_free(f->textbuff);
504  if (f->fmbuff) owl_free(f->fmbuff);
505  if (f->colorbuff) owl_free(f->colorbuff);
506}
507
508
509void owl_fmtext_copy(owl_fmtext *dst, owl_fmtext *src) {
510  dst->textlen=src->textlen;
511  dst->textbuff=owl_malloc(src->textlen+5);
512  dst->fmbuff=owl_malloc(src->textlen+5);
513  dst->colorbuff=owl_malloc(src->textlen+5);
514  memcpy(dst->textbuff, src->textbuff, src->textlen);
515  memcpy(dst->fmbuff, src->fmbuff, src->textlen);
516  memcpy(dst->colorbuff, src->colorbuff, src->textlen);
517}
Note: See TracBrowser for help on using the repository browser.