source: fmtext.c @ 72a53e9

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