source: fmtext.c @ 4b464a4

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