source: fmtext.c @ dd24b6a

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since dd24b6a was dd24b6a, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 17 years ago
* include wchar.h * replace hand-rolled width detection with wcswidth. * pad with space if we end up halfway into a character at the start of a line. WARNING: Still not safe.
  • Property mode set to 100644
File size: 22.1 KB
Line 
1#include "owl.h"
2#include <stdlib.h>
3#include <string.h>
4
5static const char fileIdent[] = "$Id$";
6
7/* initialize an fmtext with no data */
8void owl_fmtext_init_null(owl_fmtext *f)
9{
10  f->textlen=0;
11  f->bufflen=5;
12  f->textbuff=owl_malloc(5);
13  f->fmbuff=owl_malloc(5);
14  f->fgcolorbuff=owl_malloc(5 * sizeof(short));
15  f->bgcolorbuff=owl_malloc(5 * sizeof(short));
16  f->textbuff[0]=0;
17  f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
18  f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
19  f->bgcolorbuff[0]=OWL_COLOR_DEFAULT;
20}
21
22/* Clear the data from an fmtext, but don't deallocate memory. This
23   fmtext can then be appended to again. */
24void owl_fmtext_clear(owl_fmtext *f)
25{
26    f->textlen = 0;
27    f->textbuff[0] = 0;
28    f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
29    f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
30    f->bgcolorbuff[0]=OWL_COLOR_DEFAULT;
31}
32
33/* Internal function.  Set the attribute 'attr' from index 'first' to
34 * index 'last'
35 */
36void _owl_fmtext_set_attr(owl_fmtext *f, int attr, int first, int last)
37{
38  int i;
39  for (i=first; i<=last; i++) {
40    f->fmbuff[i]=(unsigned char) attr;
41  }
42}
43
44/* Internal function.  Add the attribute 'attr' to the existing
45 * attributes from index 'first' to index 'last'
46 */
47void _owl_fmtext_add_attr(owl_fmtext *f, int attr, int first, int last)
48{
49  int i;
50  for (i=first; i<=last; i++) {
51    f->fmbuff[i]|=(unsigned char) attr;
52  }
53}
54
55/* Internal function.  Set the color to be 'color' from index 'first'
56 * to index 'last
57 */
58void _owl_fmtext_set_fgcolor(owl_fmtext *f, int color, int first, int last)
59{
60  int i;
61  for (i=first; i<=last; i++) {
62    f->fgcolorbuff[i]=(short)color;
63  }
64}
65
66void _owl_fmtext_set_bgcolor(owl_fmtext *f, int color, int first, int last)
67{
68  int i;
69  for (i=first; i<=last; i++) {
70    f->bgcolorbuff[i]=(short)color;
71  }
72}
73
74void _owl_fmtext_realloc(owl_fmtext *f, int newlen) /*noproto*/
75{
76    if(newlen + 1 > f->bufflen) {
77      f->textbuff=owl_realloc(f->textbuff, newlen+1);
78      f->fmbuff=owl_realloc(f->fmbuff, newlen+1);
79      f->fgcolorbuff=owl_realloc(f->fgcolorbuff, (newlen+1) * sizeof(short));
80      f->bgcolorbuff=owl_realloc(f->bgcolorbuff, (newlen+1) * sizeof(short));
81      f->bufflen = newlen+1;
82  }
83}
84
85/* append text to the end of 'f' with attribute 'attr' and color
86 * 'color'
87 */
88void owl_fmtext_append_attr(owl_fmtext *f, char *text, int attr, int fgcolor, int bgcolor)
89{
90  int newlen;
91  newlen=strlen(f->textbuff)+strlen(text);
92  _owl_fmtext_realloc(f, newlen);
93 
94  strcat(f->textbuff, text);
95  _owl_fmtext_set_attr(f, attr, f->textlen, newlen);
96  _owl_fmtext_set_fgcolor(f, fgcolor, f->textlen, newlen);
97  _owl_fmtext_set_bgcolor(f, bgcolor, f->textlen, newlen);
98  f->textlen=newlen;
99}
100
101/* Append normal, uncolored text 'text' to 'f' */
102void owl_fmtext_append_normal(owl_fmtext *f, char *text)
103{
104  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_NONE, OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
105}
106
107/* Append normal text 'text' to 'f' with color 'color' */
108void owl_fmtext_append_normal_color(owl_fmtext *f, char *text, int fgcolor, int bgcolor)
109{
110  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_NONE, fgcolor, bgcolor);
111}
112
113/* Append bold text 'text' to 'f' */
114void owl_fmtext_append_bold(owl_fmtext *f, char *text)
115{
116  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_BOLD, OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
117}
118
119/* Append reverse video text 'text' to 'f' */
120void owl_fmtext_append_reverse(owl_fmtext *f, char *text)
121{
122  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_REVERSE, OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
123}
124
125/* Append reversed and bold, uncolored text 'text' to 'f' */
126void owl_fmtext_append_reversebold(owl_fmtext *f, char *text)
127{
128  owl_fmtext_append_attr(f, text, OWL_FMTEXT_ATTR_REVERSE | OWL_FMTEXT_ATTR_BOLD, OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
129}
130
131/* Add the attribute 'attr' to all text in 'f' */
132void owl_fmtext_addattr(owl_fmtext *f, int attr)
133{
134  /* add the attribute to all text */
135  int i, j;
136
137  j=f->textlen;
138  for (i=0; i<j; i++) {
139    f->fmbuff[i] |= attr;
140  }
141}
142
143/* Anywhere the color is NOT ALREDY SET, set the color to 'color'.
144 * Other colors are left unchanged
145 */
146void owl_fmtext_colorize(owl_fmtext *f, int color)
147{
148  /* everywhere the fgcolor is OWL_COLOR_DEFAULT, change it to be 'color' */
149  int i, j;
150
151  j=f->textlen;
152  for(i=0; i<j; i++) {
153    if (f->fgcolorbuff[i]==OWL_COLOR_DEFAULT) f->fgcolorbuff[i] = (short)color;
154  }
155}
156
157void owl_fmtext_colorizebg(owl_fmtext *f, int color)
158{
159  /* everywhere the bgcolor is OWL_COLOR_DEFAULT, change it to be 'color' */
160  int i, j;
161
162  j=f->textlen;
163  for(i=0; i<j; i++) {
164    if (f->bgcolorbuff[i]==OWL_COLOR_DEFAULT) f->bgcolorbuff[i] = (short)color;
165  }
166}
167
168/* Internal function.  Append text from 'in' between index 'start' and
169 * 'stop' to the end of 'f'
170 */
171void _owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in, int start, int stop)
172{
173  int newlen, i;
174
175  newlen=strlen(f->textbuff)+(stop-start+1);
176  _owl_fmtext_realloc(f, newlen);
177
178  strncat(f->textbuff, in->textbuff+start, stop-start+1);
179  f->textbuff[newlen]='\0';
180  for (i=start; i<=stop; i++) {
181    f->fmbuff[f->textlen+(i-start)]=in->fmbuff[i];
182    f->fgcolorbuff[f->textlen+(i-start)]=in->fgcolorbuff[i];
183    f->bgcolorbuff[f->textlen+(i-start)]=in->bgcolorbuff[i];
184  }
185  f->textlen=newlen;
186}
187
188/* append fmtext 'in' to 'f' */
189void owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in)
190{
191  _owl_fmtext_append_fmtext(f, in, 0, in->textlen);
192
193}
194
195/* Append 'nspaces' number of spaces to the end of 'f' */
196void owl_fmtext_append_spaces(owl_fmtext *f, int nspaces)
197{
198  int i;
199  for (i=0; i<nspaces; i++) {
200    owl_fmtext_append_normal(f, " ");
201  }
202}
203
204/* Return a plain version of the fmtext.  Caller is responsible for
205 * freeing the return
206 */
207char *owl_fmtext_print_plain(owl_fmtext *f)
208{
209  return(owl_strdup(f->textbuff));
210}
211
212/* add the formatted text to the curses window 'w'.  The window 'w'
213 * must already be initiatlized with curses
214 */
215void owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w)
216{
217  char *tmpbuff;
218  int position, trans1, trans2, trans3, len, lastsame;
219
220  if (w==NULL) {
221    owl_function_debugmsg("Hit a null window in owl_fmtext_curs_waddstr.");
222    return;
223  }
224
225  tmpbuff=owl_malloc(f->textlen+10);
226
227  position=0;
228  len=f->textlen;
229  while (position<=len) {
230    /* find the last char with the current format and color */
231    trans1=owl_util_find_trans(f->fmbuff+position, len-position);
232    trans2=owl_util_find_trans_short(f->fgcolorbuff+position, len-position);
233    trans3=owl_util_find_trans_short(f->bgcolorbuff+position, len-position);
234
235    lastsame = (trans1 < trans2) ? trans1 : trans2;
236    lastsame = (lastsame < trans3) ? lastsame : trans3;
237    lastsame += position;
238
239    /* set the format */
240    wattrset(w, A_NORMAL);
241    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_BOLD) {
242      wattron(w, A_BOLD);
243    }
244    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_REVERSE) {
245      wattron(w, A_REVERSE);
246    }
247    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_UNDERLINE) {
248      wattron(w, A_UNDERLINE);
249    }
250
251    /* set the color */
252    /* warning, this is sort of a hack */
253    if (owl_global_get_hascolors(&g)) {
254      short fg, bg, pair;
255      fg = f->fgcolorbuff[position];
256      bg = f->bgcolorbuff[position];
257
258      pair = owl_fmtext_get_colorpair(fg, bg);
259      if (pair != -1) {
260        wcolor_set(w,pair,NULL);
261      }
262    }
263
264    /* add the text */
265    strncpy(tmpbuff, f->textbuff + position, lastsame-position+1);
266    tmpbuff[lastsame-position+1]='\0';
267    waddstr(w, tmpbuff);
268
269    position=lastsame+1;
270  }
271  owl_free(tmpbuff);
272}
273
274
275/* start with line 'aline' (where the first line is 0) and print
276 * 'lines' number of lines into 'out'
277 */
278int owl_fmtext_truncate_lines(owl_fmtext *in, int aline, int lines, owl_fmtext *out)
279{
280  char *ptr1, *ptr2;
281  int i, offset;
282 
283  /* find the starting line */
284  ptr1=in->textbuff;
285  if (aline!=0) {
286    for (i=0; i<aline; i++) {
287      ptr1=strchr(ptr1, '\n');
288      if (!ptr1) return(-1);
289      ptr1++;
290    }
291  }
292  /* ptr1 now holds the starting point */
293
294  /* copy in the next 'lines' lines */
295  if (lines<1) return(-1);
296
297  for (i=0; i<lines; i++) {
298    offset=ptr1-in->textbuff;
299    ptr2=strchr(ptr1, '\n');
300    if (!ptr2) {
301      _owl_fmtext_append_fmtext(out, in, offset, (in->textlen)-1);
302      return(-1);
303    }
304    _owl_fmtext_append_fmtext(out, in, offset, (ptr2-ptr1)+offset);
305    ptr1=ptr2+1;
306  }
307  return(0);
308}
309
310/* Truncate the message so that each line begins at column 'acol' and
311 * ends at 'bcol' or sooner.  The first column is number 0.  The new
312 * message is placed in 'out'.  The message is * expected to end in a
313 * new line for now
314 */
315void owl_fmtext_truncate_cols(owl_fmtext *in, int acol, int bcol, owl_fmtext *out)
316{
317  char *ptr_s, *ptr_e, *ptr_c, *last;
318  int col, cnt, padding;
319
320  last=in->textbuff+in->textlen-1;
321  ptr_s=in->textbuff;
322  while (ptr_s<=last) {
323    ptr_e=strchr(ptr_s, '\n');
324    if (!ptr_e) {
325      /* but this shouldn't happen if we end in a \n */
326      break;
327    }
328   
329    if (ptr_e==ptr_s) {
330      owl_fmtext_append_normal(out, "\n");
331      ptr_s++;
332      continue;
333    }
334
335    col = 0;
336    cnt = 0;
337    padding = 0;
338    ptr_c = ptr_s;
339    while(col < bcol && ptr_c < ptr_e) {
340      gunichar c = g_utf8_get_char(ptr_c);
341      if (col + wcwidth(c) > bcol) break;
342      col += wcwidth(c);
343      ptr_c = g_utf8_next_char(ptr_c);
344      if (col >= acol) {
345        if (cnt == 0) {
346          ptr_s = ptr_c;
347          padding = col - acol;
348        }
349        ++cnt;
350      }
351    }
352    if (cnt) {
353      while(padding-- > 0) {
354        owl_fmtext_append_normal(out, " ");
355      }
356      _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
357    }
358    else {
359      owl_fmtext_append_normal(out, "\n");
360    }
361    ptr_s=ptr_e+1;
362     
363#if 0
364    /* we need to check that we won't run over here */
365    len=bcol-acol;
366    if (len > (ptr_e-(ptr_s+acol))) {
367      /* the whole line fits with room to spare, don't take a full 'len' */
368      len=ptr_e-(ptr_s+acol);
369    }
370    if (len>last-ptr_s) {
371      /* the whole rest of the text fits with room to spare, adjust for it */
372      len-=(last-ptr_s);
373    }
374    if (len<=0) {
375      /* saftey check */
376      owl_fmtext_append_normal(out, "\n");
377      ptr_s=ptr_e+1;
378      continue;
379    }
380
381    offset = ptr_s - in->textbuff;
382    _owl_fmtext_append_fmtext(out, in, offset+acol, offset+acol+len);
383
384    ptr_s=ptr_e+1;
385#endif
386  }
387}
388
389/* Return the number of lines in 'f' */
390int owl_fmtext_num_lines(owl_fmtext *f)
391{
392  int lines, i;
393
394  if (f->textlen==0) return(0);
395 
396  lines=0;
397  for (i=0; i<f->textlen; i++) {
398    if (f->textbuff[i]=='\n') lines++;
399  }
400
401  /* if the last char wasn't a \n there's one more line */
402  if (f->textbuff[i-1]!='\n') lines++;
403
404  return(lines);
405}
406
407char *owl_fmtext_get_text(owl_fmtext *f)
408{
409  return(f->textbuff);
410}
411
412/* set the charater at 'index' to be 'char'.  If index is out of
413 * bounds don't do anything */
414void owl_fmtext_set_char(owl_fmtext *f, int index, int ch)
415{
416  if ((index < 0) || (index > f->textlen-1)) return;
417  f->textbuff[index]=ch;
418}
419
420/* Make a copy of the fmtext 'src' into 'dst' */
421void owl_fmtext_copy(owl_fmtext *dst, owl_fmtext *src)
422{
423  int mallocsize;
424
425  if (src->textlen==0) {
426    mallocsize=5;
427  } else {
428    mallocsize=src->textlen+2;
429  }
430  dst->textlen=src->textlen;
431  dst->textbuff=owl_malloc(mallocsize);
432  dst->fmbuff=owl_malloc(mallocsize);
433  dst->fgcolorbuff=owl_malloc(mallocsize * sizeof(short));
434  dst->bgcolorbuff=owl_malloc(mallocsize * sizeof(short));
435  memcpy(dst->textbuff, src->textbuff, src->textlen+1);
436  memcpy(dst->fmbuff, src->fmbuff, src->textlen);
437  memcpy(dst->fgcolorbuff, src->fgcolorbuff, src->textlen * sizeof(short));
438  memcpy(dst->bgcolorbuff, src->bgcolorbuff, src->textlen * sizeof(short));
439}
440
441/* highlight all instances of "string".  Return the number of
442 * instances found.  This is a case insensitive search.
443 */
444int owl_fmtext_search_and_highlight(owl_fmtext *f, char *string)
445{
446
447  int found, len;
448  char *ptr1, *ptr2;
449
450  len=strlen(string);
451  found=0;
452  ptr1=f->textbuff;
453  while (ptr1-f->textbuff <= f->textlen) {
454    ptr2=stristr(ptr1, string);
455    if (!ptr2) return(found);
456
457    found++;
458    _owl_fmtext_add_attr(f, OWL_FMTEXT_ATTR_REVERSE,
459                         ptr2 - f->textbuff,
460                         ptr2 - f->textbuff + len - 1);
461
462    ptr1=ptr2+len;
463  }
464  return(found);
465}
466
467/* return 1 if the string is found, 0 if not.  This is a case
468 *  insensitive search.
469 */
470int owl_fmtext_search(owl_fmtext *f, char *string)
471{
472
473  if (stristr(f->textbuff, string)) return(1);
474  return(0);
475}
476
477
478/* Append the text 'text' to 'f' and interpret the zephyr style
479 * formatting syntax to set appropriate attributes.
480 */
481void owl_fmtext_append_ztext(owl_fmtext *f, char *text)
482{
483  int stacksize, curattrs, curcolor;
484  char *ptr, *txtptr, *buff, *tmpptr;
485  int attrstack[32], chrstack[32], colorstack[32];
486
487  curattrs=OWL_FMTEXT_ATTR_NONE;
488  curcolor=OWL_COLOR_DEFAULT;
489  stacksize=0;
490  txtptr=text;
491  while (1) {
492    ptr=strpbrk(txtptr, "@{[<()>]}");
493    if (!ptr) {
494      /* add all the rest of the text and exit */
495      owl_fmtext_append_attr(f, txtptr, curattrs, curcolor, OWL_COLOR_DEFAULT);
496      return;
497    } else if (ptr[0]=='@') {
498      /* add the text up to this point then deal with the stack */
499      buff=owl_malloc(ptr-txtptr+20);
500      strncpy(buff, txtptr, ptr-txtptr);
501      buff[ptr-txtptr]='\0';
502      owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
503      owl_free(buff);
504
505      /* update pointer to point at the @ */
506      txtptr=ptr;
507
508      /* now the stack */
509
510      /* if we've hit our max stack depth, print the @ and move on */
511      if (stacksize==32) {
512        owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
513        txtptr++;
514        continue;
515      }
516
517      /* if it's an @@, print an @ and continue */
518      if (txtptr[1]=='@') {
519        owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
520        txtptr+=2;
521        continue;
522      }
523       
524      /* if there's no opener, print the @ and continue */
525      tmpptr=strpbrk(txtptr, "(<[{ ");
526      if (!tmpptr || tmpptr[0]==' ') {
527        owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
528        txtptr++;
529        continue;
530      }
531
532      /* check what command we've got, push it on the stack, start
533         using it, and continue ... unless it's a color command */
534      buff=owl_malloc(tmpptr-ptr+20);
535      strncpy(buff, ptr, tmpptr-ptr);
536      buff[tmpptr-ptr]='\0';
537      if (!strcasecmp(buff, "@bold")) {
538        attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD;
539        chrstack[stacksize]=tmpptr[0];
540        colorstack[stacksize]=curcolor;
541        stacksize++;
542        curattrs|=OWL_FMTEXT_ATTR_BOLD;
543        txtptr+=6;
544        owl_free(buff);
545        continue;
546      } else if (!strcasecmp(buff, "@b")) {
547        attrstack[stacksize]=OWL_FMTEXT_ATTR_BOLD;
548        chrstack[stacksize]=tmpptr[0];
549        colorstack[stacksize]=curcolor;
550        stacksize++;
551        curattrs|=OWL_FMTEXT_ATTR_BOLD;
552        txtptr+=3;
553        owl_free(buff);
554        continue;
555      } else if (!strcasecmp(buff, "@i")) {
556        attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE;
557        chrstack[stacksize]=tmpptr[0];
558        colorstack[stacksize]=curcolor;
559        stacksize++;
560        curattrs|=OWL_FMTEXT_ATTR_UNDERLINE;
561        txtptr+=3;
562        owl_free(buff);
563        continue;
564      } else if (!strcasecmp(buff, "@italic")) {
565        attrstack[stacksize]=OWL_FMTEXT_ATTR_UNDERLINE;
566        chrstack[stacksize]=tmpptr[0];
567        colorstack[stacksize]=curcolor;
568        stacksize++;
569        curattrs|=OWL_FMTEXT_ATTR_UNDERLINE;
570        txtptr+=8;
571        owl_free(buff);
572        continue;
573      } else if (!strcasecmp(buff, "@")) {
574        attrstack[stacksize]=OWL_FMTEXT_ATTR_NONE;
575        chrstack[stacksize]=tmpptr[0];
576        colorstack[stacksize]=curcolor;
577        stacksize++;
578        txtptr+=2;
579        owl_free(buff);
580        continue;
581
582        /* if it's a color read the color, set the current color and
583           continue */
584      } else if (!strcasecmp(buff, "@color") 
585                 && owl_global_get_hascolors(&g)
586                 && owl_global_is_colorztext(&g)) {
587        owl_free(buff);
588        txtptr+=7;
589        tmpptr=strpbrk(txtptr, "@{[<()>]}");
590        if (tmpptr &&
591            ((txtptr[-1]=='(' && tmpptr[0]==')') ||
592             (txtptr[-1]=='<' && tmpptr[0]=='>') ||
593             (txtptr[-1]=='[' && tmpptr[0]==']') ||
594             (txtptr[-1]=='{' && tmpptr[0]=='}'))) {
595
596          /* grab the color name */
597          buff=owl_malloc(tmpptr-txtptr+20);
598          strncpy(buff, txtptr, tmpptr-txtptr);
599          buff[tmpptr-txtptr]='\0';
600
601          /* set it as the current color */
602          curcolor=owl_util_string_to_color(buff);
603          if (curcolor==-1) curcolor=OWL_COLOR_DEFAULT;
604          owl_free(buff);
605          txtptr=tmpptr+1;
606          continue;
607
608        } else {
609
610        }
611
612      } else {
613        /* if we didn't understand it, we'll print it.  This is different from zwgc
614         * but zwgc seems to be smarter about some screw cases than I am
615         */
616        owl_fmtext_append_attr(f, "@", curattrs, curcolor, OWL_COLOR_DEFAULT);
617        txtptr++;
618        continue;
619      }
620
621    } else if (ptr[0]=='}' || ptr[0]==']' || ptr[0]==')' || ptr[0]=='>') {
622      /* add the text up to this point first */
623      buff=owl_malloc(ptr-txtptr+20);
624      strncpy(buff, txtptr, ptr-txtptr);
625      buff[ptr-txtptr]='\0';
626      owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
627      owl_free(buff);
628
629      /* now deal with the closer */
630      txtptr=ptr;
631
632      /* first, if the stack is empty we must bail (just print and go) */
633      if (stacksize==0) {
634        buff=owl_malloc(5);
635        buff[0]=ptr[0];
636        buff[1]='\0';
637        owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
638        owl_free(buff);
639        txtptr++;
640        continue;
641      }
642
643      /* if the closing char is what's on the stack, turn off the
644         attribue and pop the stack */
645      if ((ptr[0]==')' && chrstack[stacksize-1]=='(') ||
646          (ptr[0]=='>' && chrstack[stacksize-1]=='<') ||
647          (ptr[0]==']' && chrstack[stacksize-1]=='[') ||
648          (ptr[0]=='}' && chrstack[stacksize-1]=='{')) {
649        int i;
650        stacksize--;
651        curattrs=OWL_FMTEXT_ATTR_NONE;
652        curcolor = colorstack[stacksize];
653        for (i=0; i<stacksize; i++) {
654          curattrs|=attrstack[i];
655        }
656        txtptr+=1;
657        continue;
658      } else {
659        /* otherwise print and continue */
660        buff=owl_malloc(5);
661        buff[0]=ptr[0];
662        buff[1]='\0';
663        owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
664        owl_free(buff);
665        txtptr++;
666        continue;
667      }
668    } else {
669      /* we've found an unattached opener, print everything and move on */
670      buff=owl_malloc(ptr-txtptr+20);
671      strncpy(buff, txtptr, ptr-txtptr+1);
672      buff[ptr-txtptr+1]='\0';
673      owl_fmtext_append_attr(f, buff, curattrs, curcolor, OWL_COLOR_DEFAULT);
674      owl_free(buff);
675      txtptr=ptr+1;
676      continue;
677    }
678  }
679}
680
681/* requires that the list values are strings or NULL.
682 * joins the elements together with join_with.
683 * If format_fn is specified, passes it the list element value
684 * and it will return a string which this needs to free. */
685void owl_fmtext_append_list(owl_fmtext *f, owl_list *l, char *join_with, char *(format_fn)(void*))
686{
687  int i, size;
688  void *elem;
689  char *text;
690
691  size = owl_list_get_size(l);
692  for (i=0; i<size; i++) {
693    elem = (char*)owl_list_get_element(l,i);
694    if (elem && format_fn) {
695      text = format_fn(elem);
696      if (text) {
697        owl_fmtext_append_normal(f, text);
698        owl_free(text);
699      }
700    } else if (elem) {
701      owl_fmtext_append_normal(f, elem);
702    }
703    if ((i < size-1) && join_with) {
704      owl_fmtext_append_normal(f, join_with);
705    }
706  }
707}
708
709/* Free all memory allocated by the object */
710void owl_fmtext_free(owl_fmtext *f)
711{
712  if (f->textbuff) owl_free(f->textbuff);
713  if (f->fmbuff) owl_free(f->fmbuff);
714  if (f->fgcolorbuff) owl_free(f->fgcolorbuff);
715  if (f->bgcolorbuff) owl_free(f->bgcolorbuff);
716}
717
718/*** Color Pair manager ***/
719void owl_fmtext_init_colorpair_mgr(owl_colorpair_mgr *cpmgr)
720{
721  // This could be a bitarray if we wanted to save memory.
722  short i, j;
723  cpmgr->next = 8;
724 
725  // The test is <= because we allocate COLORS+1 entries.
726  cpmgr->pairs = owl_malloc((COLORS+1) * sizeof(short*));
727  for(i = 0; i <= COLORS; i++) {
728    cpmgr->pairs[i] = owl_malloc((COLORS+1) * sizeof(short));
729    for(j = 0; j <= COLORS; j++) {
730      cpmgr->pairs[i][j] = -1;
731    }
732  }
733  if (owl_global_get_hascolors(&g)) {
734    for(i = 0; i < 8; i++) {
735      short fg, bg;
736      if (i >= COLORS) continue;
737      pair_content(i, &fg, &bg);
738      cpmgr->pairs[fg+1][bg+1] = i;
739    }
740  }
741}
742
743/* Reset used list */
744void owl_fmtext_reset_colorpairs()
745{
746  if (owl_global_get_hascolors(&g)) {
747    short i, j;
748    owl_colorpair_mgr *cpmgr = owl_global_get_colorpair_mgr(&g);
749    cpmgr->next = 8;
750   
751    // The test is <= because we allocated COLORS+1 entries.
752    for(i = 0; i <= COLORS; i++) {
753      for(j = 0; j <= COLORS; j++) {
754        cpmgr->pairs[i][j] = -1;
755      }
756    }
757    for(i = 0; i < 8; i++) {
758      short fg, bg;
759      if (i >= COLORS) continue;
760      pair_content(i, &fg, &bg);
761      cpmgr->pairs[fg+1][bg+1] = i;
762    }
763  }
764}
765
766/* Assign pairs by request */
767short owl_fmtext_get_colorpair(int fg, int bg)
768{
769  owl_colorpair_mgr *cpmgr;
770  short pair, default_bg;
771
772#ifdef HAVE_USE_DEFAULT_COLORS
773  if (fg == OWL_COLOR_DEFAULT) fg = -1;
774  default_bg = OWL_COLOR_DEFAULT;
775#else
776  if (fg == OWL_COLOR_DEFAULT) fg = 0;
777  if (bg == OWL_COLOR_DEFAULT) bg = 0;
778  default_bg = COLOR_BLACK;
779#endif
780
781  // looking for a pair we already set up for this draw.
782  cpmgr = owl_global_get_colorpair_mgr(&g);
783  pair = cpmgr->pairs[fg+1][bg+1];
784  if (!(pair != -1 && pair < cpmgr->next)) {
785/*    owl_global_set_needrefresh(&g);*/
786    // If we didn't find a pair, search for a free one to assign.
787    pair = (cpmgr->next < COLOR_PAIRS) ? cpmgr->next : -1;
788    if (pair != -1) {
789      // We found a free pair, initialize it.
790      init_pair(pair, fg, bg);
791      cpmgr->pairs[fg+1][bg+1] = pair;
792      cpmgr->next++;
793    }
794    else if (bg != OWL_COLOR_DEFAULT) {
795      // We still don't have a pair, drop the background color. Too bad.
796      owl_function_debugmsg("colorpairs: color shortage - dropping background color.");
797      pair = owl_fmtext_get_colorpair(fg, OWL_COLOR_DEFAULT);
798    }
799    else {
800      // We still don't have a pair, defaults all around.
801      owl_function_debugmsg("colorpairs: color shortage - dropping foreground and background color.");
802      pair = 0;
803    }
804  }
805  return pair;
806}
Note: See TracBrowser for help on using the repository browser.