source: fmtext.c @ ae4cd12

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since ae4cd12 was f2f9314, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
Added some defenses against resize crashes, and put in debug messages if they're encountered
  • Property mode set to 100644
File size: 13.9 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  if (w==NULL) {
347    owl_function_debugmsg("Hit a null window in owl_fmtext_curs_waddstr.");
348    return;
349  }
350
351  tmpbuff=owl_malloc(f->textlen+10);
352
353  position=0;
354  len=f->textlen;
355  while (position<=len) {
356    /* find the last char with the current format and color */
357    trans1=owl_util_find_trans(f->fmbuff+position, len-position);
358    trans2=owl_util_find_trans(f->colorbuff+position, len-position);
359
360    if (trans1<trans2) {
361      lastsame=position+trans1;
362    } else {
363      lastsame=position+trans2;
364    }
365
366    /* set the format */
367    wattrset(w, A_NORMAL);
368    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_BOLD) {
369      wattron(w, A_BOLD);
370    }
371    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_REVERSE) {
372      wattron(w, A_REVERSE);
373    }
374    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_UNDERLINE) {
375      wattron(w, A_UNDERLINE);
376    }
377
378    /* set the color */
379    /* warning, this is sort of a hack */
380    if (owl_global_get_hascolors(&g)) {
381      if (f->colorbuff[position]!=OWL_COLOR_DEFAULT) {
382        wattron(w, COLOR_PAIR(f->colorbuff[position]));
383      }
384    }
385
386    /* add the text */
387    strncpy(tmpbuff, f->textbuff + position, lastsame-position+1);
388    tmpbuff[lastsame-position+1]='\0';
389    waddstr(w, tmpbuff);
390
391    position=lastsame+1;
392  }
393  owl_free(tmpbuff);
394}
395
396
397int owl_fmtext_truncate_lines(owl_fmtext *in, int aline, int lines, owl_fmtext *out) {
398  /* start with line aline (where the first line is 0) and print
399   *  'lines' lines
400   */
401  char *ptr1, *ptr2;
402  int i, offset;
403 
404  /* find the starting line */
405  ptr1=in->textbuff;
406  if (aline!=0) {
407    for (i=0; i<aline; i++) {
408      ptr1=strchr(ptr1, '\n');
409      if (!ptr1) return(-1);
410      ptr1++;
411    }
412  }
413  /* ptr1 now holds the starting point */
414
415  /* copy in the next 'lines' lines */
416  if (lines<1) return(-1);
417
418  for (i=0; i<lines; i++) {
419    ptr2=strchr(ptr1, '\n');
420    offset=ptr1-in->textbuff;
421    if (!ptr2) {
422      owl_fmtext_append_fmtext(out, in, offset, in->textlen-1);
423      return(-1);
424    }
425    owl_fmtext_append_fmtext(out, in, offset, (ptr2-ptr1)+offset);
426    ptr1=ptr2+1;
427  }
428  return(0);
429}
430
431
432void owl_fmtext_truncate_cols(owl_fmtext *in, int acol, int bcol, owl_fmtext *out) {
433  char *ptr1, *ptr2, *last;
434  int len, offset;
435 
436  /* the first column is column 0 */
437
438  /* the message is expected to end in a new line for now */
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  if (f->textlen==0) return(0);
481 
482  lines=0;
483  for (i=0; i<f->textlen; i++) {
484    if (f->textbuff[i]=='\n') lines++;
485  }
486
487  /* if the last char wasn't a \n there's one more line */
488  if (f->textbuff[i-1]!='\n') lines++;
489
490  return(lines);
491}
492
493
494char *owl_fmtext_get_text(owl_fmtext *f) {
495  return(f->textbuff);
496}
497
498void owl_fmtext_set_char(owl_fmtext *f, int index, int ch) {
499  /* set the charater at 'index' to be 'char'.  If index is out of
500   * bounds don't do anything */
501  if ((index < 0) || (index > f->textlen-1)) return;
502  f->textbuff[index]=ch;
503}
504
505void owl_fmtext_free(owl_fmtext *f) {
506  if (f->textbuff) owl_free(f->textbuff);
507  if (f->fmbuff) owl_free(f->fmbuff);
508  if (f->colorbuff) owl_free(f->colorbuff);
509}
510
511
512void owl_fmtext_copy(owl_fmtext *dst, owl_fmtext *src) {
513  dst->textlen=src->textlen;
514  dst->textbuff=owl_malloc(src->textlen+5);
515  dst->fmbuff=owl_malloc(src->textlen+5);
516  dst->colorbuff=owl_malloc(src->textlen+5);
517  memcpy(dst->textbuff, src->textbuff, src->textlen);
518  memcpy(dst->fmbuff, src->fmbuff, src->textlen);
519  memcpy(dst->colorbuff, src->colorbuff, src->textlen);
520}
521
522
523int owl_fmtext_search_and_highlight(owl_fmtext *f, char *string) {
524  /* highlight all instance of "string".  Return the number of
525   * instances found.  This is case insensitive. */
526
527  int found, len;
528  char *ptr1, *ptr2;
529
530  len=strlen(string);
531  found=0;
532  ptr1=f->textbuff;
533  while (ptr1-f->textbuff <= f->textlen) {
534    ptr2=stristr(ptr1, string);
535    if (!ptr2) return(found);
536
537    found++;
538    _owl_fmtext_add_attr(f, OWL_FMTEXT_ATTR_REVERSE,
539                         ptr2 - f->textbuff,
540                         ptr2 - f->textbuff + len - 1);
541
542    ptr1=ptr2+len;
543  }
544  return(found);
545}
546
547int owl_fmtext_search(owl_fmtext *f, char *string) {
548  /* return 1 if the string is found, 0 if not.  This is case
549   *  insensitive */
550
551  if (stristr(f->textbuff, string)) return(1);
552  return(0);
553}
Note: See TracBrowser for help on using the repository browser.