source: text.c @ 385cce2

release-1.10release-1.7release-1.8release-1.9
Last change on this file since 385cce2 was 2b83ad6, checked in by David Benjamin <davidben@mit.edu>, 14 years ago
Add owl_fmtext_expand_tabs with test case
  • Property mode set to 100644
File size: 7.5 KB
RevLine 
[7d4fbcd]1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
[995eb4b]4#include <ctype.h>
[7d4fbcd]5#include "owl.h"
6
[e19eb97]7void owl_text_indent(char *out, const char *in, int n)
[ab31454]8{
[e19eb97]9  const char *ptr1, *ptr2, *last;
[7d4fbcd]10  int i;
11
12  strcpy(out, "");
13
14  last=in+strlen(in)-1;
15  ptr1=in;
16  while (ptr1<=last) {
17    for (i=0; i<n; i++) {
18      strcat(out, " ");
19    }
20    ptr2=strchr(ptr1, '\n');
21    if (!ptr2) {
22      strcat(out, ptr1);
23      break;
24    } else {
25      strncat(out, ptr1, ptr2-ptr1+1);
26    }
27    ptr1=ptr2+1;
28  }
29}
30
[e19eb97]31int owl_text_num_lines(const char *in)
[ab31454]32{
[7d4fbcd]33  int lines, i;
34
35  lines=0;
36  for (i=0; in[i]!='\0'; i++) {
37    if (in[i]=='\n') lines++;
38  }
39
40  /* if the last char wasn't a \n there's one more line */
[1bb1e67]41  if (i>0 && in[i-1]!='\n') lines++;
[7d4fbcd]42
43  return(lines);
44}
45
[3abf28b]46
47/* caller must free the return */
[e19eb97]48char *owl_text_htmlstrip(const char *in)
[ab31454]49{
[e19eb97]50  const char *ptr1, *end, *ptr2, *ptr3;
[65b2173]51  char *out, *out2;
[3abf28b]52
53  out=owl_malloc(strlen(in)+30);
54  strcpy(out, "");
55
56  ptr1=in;
57  end=in+strlen(in);
58 
59  while(ptr1<end) {
60    /* look for an open bracket */
61    ptr2=strchr(ptr1, '<');
62
[dafd919]63    /* if none, copy in from here to end and exit */
[3abf28b]64    if (ptr2==NULL) {
65      strcat(out, ptr1);
[8d24696]66      break;
[3abf28b]67    }
68
69    /* otherwise copy in everything before the open bracket */
70    if (ptr2>ptr1) {
71      strncat(out, ptr1, ptr2-ptr1);
72    }
73
74    /* find the close bracket */
75    ptr3=strchr(ptr2, '>');
76   
77    /* if there is no close, copy as you are and exit */
78    if (!ptr3) {
79      strcat(out, ptr2);
[8d24696]80      break;
[3abf28b]81    }
82
83    /* look for things we know */
[3bcf125]84    if (!strncasecmp(ptr2, "<BODY", 5) ||
[dafd919]85        !strncasecmp(ptr2, "<FONT", 5) ||
[3abf28b]86        !strncasecmp(ptr2, "<HTML", 5) ||
87        !strncasecmp(ptr2, "</FONT", 6) ||
88        !strncasecmp(ptr2, "</HTML", 6) ||
89        !strncasecmp(ptr2, "</BODY", 6)) {
90
91      /* advance to beyond the angle brakcet and go again */
92      ptr1=ptr3+1;
93      continue;
94    }
[75e3879]95    if (!strncasecmp(ptr2, "<BR>", 4)) {
96      strcat(out, "\n");
97      ptr1=ptr3+1;
98      continue;
99    }
[3abf28b]100
101    /* if it wasn't something we know, copy to the > and  go again */
[75e3879]102    strncat(out, ptr2, ptr3-ptr2+1);
[3abf28b]103    ptr1=ptr3+1;
104  }
[8d24696]105
[e3d9c77]106  out2=owl_text_substitute(out, "&lt;", "<");
[8d24696]107  owl_free(out);
[e3d9c77]108  out=owl_text_substitute(out2, "&gt;", ">");
[8d24696]109  owl_free(out2);
[e3d9c77]110  out2=owl_text_substitute(out, "&amp;", "&");
[8d24696]111  owl_free(out);
[e3d9c77]112  out=owl_text_substitute(out2, "&quot;", "\"");
[8d24696]113  owl_free(out2);
[e3d9c77]114  out2=owl_text_substitute(out, "&nbsp;", " ");
[8d24696]115  owl_free(out);
[e3d9c77]116  out=owl_text_substitute(out2, "&ensp;", "  ");
[8d24696]117  owl_free(out2);
[e3d9c77]118  out2=owl_text_substitute(out, "&emsp;", "   ");
[8d24696]119  owl_free(out);
[e3d9c77]120  out=owl_text_substitute(out2, "&endash;", "--");
[8d24696]121  owl_free(out2);
[e3d9c77]122  out2=owl_text_substitute(out, "&emdash;", "---");
[8d24696]123  owl_free(out);
124
125  return(out2);
[3abf28b]126}
[ab31454]127
[3e8ff1e]128/* Caller must free return */
[e19eb97]129char *owl_text_expand_tabs(const char *in)
[3e8ff1e]130{
[f7cd7c9]131  int len = 0;
[e19eb97]132  const char *p = in;
[3e8ff1e]133  char *ret, *out;
134  int col;
135
[f7cd7c9]136  col = 0;
[3e8ff1e]137  while(*p) {
[f7cd7c9]138    gunichar c = g_utf8_get_char(p);
139    char *q = g_utf8_next_char(p);
140    switch (c) {
141    case '\t':
142      do { len++; col++; } while (col % OWL_TAB_WIDTH);
143      p = q;
144      continue;
145    case '\n':
146      col = 0;
147      break;
148    default:
149      col += mk_wcwidth(c);
150      break;
151    }
152    len += q - p;
153    p = q;
[3e8ff1e]154  }
155
[f7cd7c9]156  ret = owl_malloc(len + 1);
[3e8ff1e]157
158  p = in;
159  out = ret;
160
161  col = 0;
162  while(*p) {
[f7cd7c9]163    gunichar c = g_utf8_get_char(p);
164    char *q = g_utf8_next_char(p);
165    switch (c) {
[3e8ff1e]166    case '\t':
167      do {*(out++) = ' '; col++; } while (col % OWL_TAB_WIDTH);
[f7cd7c9]168      p = q;
169      continue;
[3e8ff1e]170    case '\n':
[f7cd7c9]171      col = 0;
172      break;
[3e8ff1e]173    default:
[f7cd7c9]174      col += mk_wcwidth(c);
175      break;
[3e8ff1e]176    }
[f7cd7c9]177    memcpy(out, p, q - p);
178    out += q - p;
179    p = q;
[3e8ff1e]180  }
181
182  *out = 0;
183
184  return ret;
185}
186
[ab31454]187/* caller must free the return */
[e19eb97]188char *owl_text_wordwrap(const char *in, int col)
[ab31454]189{
190  char *out;
191  int cur, lastspace, len, lastnewline;
192
193  out=owl_strdup(in);
194  len=strlen(in);
195  cur=0;
196  lastspace=-1;
197  lastnewline=-1;
198
199  while (cur<(len-1)) {
200    if (out[cur]==' ') {
201      lastspace=cur;
202      cur++;
203      continue;
204    } else if (out[cur]=='\n') {
205      lastnewline=cur;
206      cur++;
207      continue;
208    }
209
210    /* do we need to wrap? */
211    if ( (cur-(lastnewline+1)) > col ) {
212      if (lastspace==-1 ||
213          (lastnewline>0 && (lastspace<=lastnewline))) {
214        /* we can't help, sorry */
215        cur++;
216        continue;
217      }
218
219      /* turn the last space into a newline */
220      out[lastspace]='\n';
221      lastnewline=lastspace;
222      lastspace=-1;
223      cur++;
224      continue;
225    }
226
227    cur++;
228    continue;
229  }
230  return(out);
231}
[e3d9c77]232
[f82e233]233/* this modifies 'in' */
234void owl_text_wordunwrap(char *in)
235{
236  int i, j;
237
238  j=strlen(in);
239  for (i=0; i<j; i++) {
240    if ( (in[i]=='\n') &&
241         ((i>0) && (i<(j-1))) &&
242         (in[i-1]!='\n') &&
243         (in[i+1]!='\n') )
244      in[i]=' ';
245  }
246}
247
[e3d9c77]248/* return 1 if a string is only whitespace, otherwise 0 */
[e19eb97]249int only_whitespace(const char *s)
[e3d9c77]250{
[28ee32b]251  if (g_utf8_validate(s,-1,NULL)) {
[e19eb97]252    const char *p;
[28ee32b]253    for(p = s; p[0]; p=g_utf8_next_char(p)) {
254      if (!g_unichar_isspace(g_utf8_get_char(p))) return 0;
255    }
256  }
257  else {
258    int i;
259    for (i=0; s[i]; i++) {
260      if (!isspace((int) s[i])) return(0);
261    }
[e3d9c77]262  }
263  return(1);
264}
265
[e19eb97]266const char *owl_getquoting(const char *line)
[e3d9c77]267{
268  if (line[0]=='\0') return("'");
269  if (strchr(line, '\'')) return("\"");
270  if (strchr(line, '"')) return("'");
[ef4700c]271  if (strcspn(line, "\n\t ") != strlen(line)) return("'");
[e3d9c77]272  return("");
273}
274
275/* Return a string with any occurances of 'from' replaced with 'to'.
276 * Does not currently handle backslash quoting, but may in the future.
277 * Caller must free returned string.
278 */
[e19eb97]279char *owl_text_substitute(const char *in, const char *from, const char *to)
[e3d9c77]280{
281 
282  char *out;
283  int   outlen, tolen, fromlen, inpos=0, outpos=0;
284
285  if (!*from) return owl_strdup(in);
286
287  outlen = strlen(in)+1;
288  tolen  = strlen(to);
289  fromlen  = strlen(from);
[34509d5]290  out = owl_malloc(outlen);
[e3d9c77]291
292  while (in[inpos]) {
293    if (!strncmp(in+inpos, from, fromlen)) {
294      outlen += tolen;
295      out = owl_realloc(out, outlen);
296      strcpy(out+outpos, to);
297      inpos += fromlen;
298      outpos += tolen;
299    } else {
300      out[outpos] = in[inpos];
301      inpos++; outpos++;
302    }
303  }
304  out[outpos] = '\0';
305  return(out);
306}
307
308/* replace all instances of character a in buff with the character
309 * b.  buff must be null terminated.
310 */
311void owl_text_tr(char *buff, char a, char b)
312{
313  int i;
314
315  owl_function_debugmsg("In: %s", buff);
316  for (i=0; buff[i]!='\0'; i++) {
317    if (buff[i]==a) buff[i]=b;
318  }
319  owl_function_debugmsg("Out: %s", buff);
320}
321
322/* Return a string which is like 'in' except that every instance of
323 * any character in 'toquote' found in 'in' is preceeded by the string
324 * 'quotestr'.  For example, owl_text_quote(in, "+*.", "\") would
325 * place a backslash before every '+', '*' or '.' in 'in'.  It is
326 * permissable for a character in 'quotestr' to be in 'toquote'.
327 * On success returns the string, on error returns NULL.
328 */
[e19eb97]329char *owl_text_quote(const char *in, const char *toquote, const char *quotestr)
[e3d9c77]330{
[72db971]331  int i, x, r, place, escape;
[e3d9c77]332  int in_len, toquote_len, quotestr_len;
333  char *out;
334
335  in_len=strlen(in);
336  toquote_len=strlen(toquote);
337  quotestr_len=strlen(quotestr);
338  place=0;
[72db971]339  escape = 0;
340  for (i=0; i<in_len; i++) {
341    if(strchr(toquote, in[i]) != NULL)
342      escape++;
343  }
344  out = owl_malloc(in_len + quotestr_len*escape+1);
[e3d9c77]345  for (i=0; i<in_len; i++) {
346
347    /* check if it's a character that needs quoting */
348    for (x=0; x<toquote_len; x++) {
349      if (in[i]==toquote[x]) {
350        /* quote it */
351        for (r=0; r<quotestr_len; r++) {
352          out[place+r]=quotestr[r];
353        }
354        place+=quotestr_len;
355        break;
356      }
357    }
358
359    /* either way, we now copy over the character */
360    out[place]=in[i];
361    place++;
362  }
363  out[place]='\0';
364  return(out);
365}
Note: See TracBrowser for help on using the repository browser.