source: text.c @ 2be605a

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