source: fmtext.c @ 985f85b

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 985f85b was af2ca19, checked in by James M. Kretchmar <kretch@mit.edu>, 22 years ago
Fixed memory leak and buffer overrun in fmtext
  • 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  /* find the starting line */
400  ptr1=in->textbuff;
401  if (aline!=0) {
402    for (i=0; i<aline; i++) {
403      ptr1=strchr(ptr1, '\n');
404      if (!ptr1) return(-1);
405      ptr1++;
406    }
407  }
408  /* ptr1 now holds the starting point */
409
410  /* copy in the next 'lines' lines */
411  if (lines<1) return(-1);
412
413  for (i=0; i<lines; i++) {
414    ptr2=strchr(ptr1, '\n');
415    offset=ptr1-in->textbuff;
416    if (!ptr2) {
417      owl_fmtext_append_fmtext(out, in, offset, in->textlen-1);
418      return(-1);
419    }
420    owl_fmtext_append_fmtext(out, in, offset, (ptr2-ptr1)+offset);
421    ptr1=ptr2+1;
422  }
423  return(0);
424}
425
426
427void owl_fmtext_truncate_cols(owl_fmtext *in, int acol, int bcol, owl_fmtext *out) {
428  char *ptr1, *ptr2, *last;
429  int len, offset;
430 
431  /* the first column is column 0 */
432
433  /* the message is expected to end in a new line for now */
434
435  last=in->textbuff+in->textlen-1;
436  ptr1=in->textbuff;
437  while (ptr1<=last) {
438    ptr2=strchr(ptr1, '\n');
439    if (!ptr2) {
440      /* but this shouldn't happen if we end in a \n */
441      break;
442    }
443   
444    if (ptr2==ptr1) {
445      owl_fmtext_append_normal(out, "\n");
446      ptr1++;
447      continue;
448    }
449
450    /* we need to check that we won't run over here */
451    len=bcol-acol;
452    if (len > (ptr2-(ptr1+acol))) {
453      len=ptr2-(ptr1+acol);
454    }
455    if (len>last-ptr1) {
456      len-=(last-ptr1);
457    }
458    if (len<=0) {
459      owl_fmtext_append_normal(out, "\n");
460      ptr1=ptr2+1;
461      continue;
462    }
463
464    offset=ptr1-in->textbuff;
465    owl_fmtext_append_fmtext(out, in, offset+acol, offset+acol+len);
466
467    ptr1=ptr2+1;
468  }
469}
470
471
472int owl_fmtext_num_lines(owl_fmtext *f) {
473  int lines, i;
474
475  if (f->textlen==0) return(0);
476 
477  lines=0;
478  for (i=0; i<f->textlen; i++) {
479    if (f->textbuff[i]=='\n') lines++;
480  }
481
482  /* if the last char wasn't a \n there's one more line */
483  if (f->textbuff[i-1]!='\n') lines++;
484
485  return(lines);
486}
487
488
489char *owl_fmtext_get_text(owl_fmtext *f) {
490  return(f->textbuff);
491}
492
493void owl_fmtext_set_char(owl_fmtext *f, int index, int ch) {
494  /* set the charater at 'index' to be 'char'.  If index is out of
495   * bounds don't do anything */
496  if ((index < 0) || (index > f->textlen-1)) return;
497  f->textbuff[index]=ch;
498}
499
500void owl_fmtext_free(owl_fmtext *f) {
501  if (f->textbuff) owl_free(f->textbuff);
502  if (f->fmbuff) owl_free(f->fmbuff);
503  if (f->colorbuff) owl_free(f->colorbuff);
504}
505
506
507void owl_fmtext_copy(owl_fmtext *dst, owl_fmtext *src) {
508  dst->textlen=src->textlen;
509  dst->textbuff=owl_malloc(src->textlen+5);
510  dst->fmbuff=owl_malloc(src->textlen+5);
511  dst->colorbuff=owl_malloc(src->textlen+5);
512  memcpy(dst->textbuff, src->textbuff, src->textlen);
513  memcpy(dst->fmbuff, src->fmbuff, src->textlen);
514  memcpy(dst->colorbuff, src->colorbuff, src->textlen);
515}
516
517
518int owl_fmtext_search_and_highlight(owl_fmtext *f, char *string) {
519  /* highlight all instance of "string".  Return the number of
520   * instances found.  This is case insensitive. */
521
522  int found, len;
523  char *ptr1, *ptr2;
524
525  len=strlen(string);
526  found=0;
527  ptr1=f->textbuff;
528  while (ptr1-f->textbuff <= f->textlen) {
529    ptr2=stristr(ptr1, string);
530    if (!ptr2) return(found);
531
532    found++;
533    _owl_fmtext_add_attr(f, OWL_FMTEXT_ATTR_REVERSE,
534                         ptr2 - f->textbuff,
535                         ptr2 - f->textbuff + len - 1);
536
537    ptr1=ptr2+len;
538  }
539  return(found);
540}
541
542int owl_fmtext_search(owl_fmtext *f, char *string) {
543  /* return 1 if the string is found, 0 if not.  This is case
544   *  insensitive */
545
546  if (stristr(f->textbuff, string)) return(1);
547  return(0);
548}
Note: See TracBrowser for help on using the repository browser.