source: text.c @ b470451

release-1.8release-1.9
Last change on this file since b470451 was d427f08, checked in by Nelson Elhage <nelhage@mit.edu>, 10 years ago
Use G_GNUC_WARN_UNUSED_RESULT Have gcc warn us when we ignore the result of a function that requires the caller to free the result, or an initilization function that can fail. This might help (slightly) with preventing leaks and segfaults. Additionally changed some functions that should never fail to not return values. (The owl_list_* functions changed only fail if list->size < 0, which we assume is not the case elsewhere.)
  • Property mode set to 100644
File size: 6.8 KB
Line 
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include "owl.h"
6
7/* Returns a copy of 'in' with each line indented 'n'
8 * characters. Result must be freed with g_free. */
9G_GNUC_WARN_UNUSED_RESULT char *owl_text_indent(const char *in, int n)
10{
11  const char *ptr1, *ptr2, *last;
12  GString *out = g_string_new("");
13  int i;
14
15  last=in+strlen(in)-1;
16  ptr1=in;
17  while (ptr1<=last) {
18    for (i=0; i<n; i++) {
19      g_string_append_c(out, ' ');
20    }
21    ptr2=strchr(ptr1, '\n');
22    if (!ptr2) {
23      g_string_append(out, ptr1);
24      break;
25    } else {
26      g_string_append_len(out, ptr1, ptr2-ptr1+1);
27    }
28    ptr1=ptr2+1;
29  }
30  return g_string_free(out, false);
31}
32
33int owl_text_num_lines(const char *in)
34{
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 */
43  if (i>0 && in[i-1]!='\n') lines++;
44
45  return(lines);
46}
47
48
49/* caller must free the return */
50G_GNUC_WARN_UNUSED_RESULT char *owl_text_htmlstrip(const char *in)
51{
52  const char *ptr1, *end, *ptr2, *ptr3;
53  char *out, *out2;
54
55  out=g_new(char, strlen(in)+30);
56  strcpy(out, "");
57
58  ptr1=in;
59  end=in+strlen(in);
60 
61  while(ptr1<end) {
62    /* look for an open bracket */
63    ptr2=strchr(ptr1, '<');
64
65    /* if none, copy in from here to end and exit */
66    if (ptr2==NULL) {
67      strcat(out, ptr1);
68      break;
69    }
70
71    /* otherwise copy in everything before the open bracket */
72    if (ptr2>ptr1) {
73      strncat(out, ptr1, ptr2-ptr1);
74    }
75
76    /* find the close bracket */
77    ptr3=strchr(ptr2, '>');
78   
79    /* if there is no close, copy as you are and exit */
80    if (!ptr3) {
81      strcat(out, ptr2);
82      break;
83    }
84
85    /* look for things we know */
86    if (!strncasecmp(ptr2, "<BODY", 5) ||
87        !strncasecmp(ptr2, "<FONT", 5) ||
88        !strncasecmp(ptr2, "<HTML", 5) ||
89        !strncasecmp(ptr2, "</FONT", 6) ||
90        !strncasecmp(ptr2, "</HTML", 6) ||
91        !strncasecmp(ptr2, "</BODY", 6)) {
92
93      /* advance to beyond the angle brakcet and go again */
94      ptr1=ptr3+1;
95      continue;
96    }
97    if (!strncasecmp(ptr2, "<BR>", 4)) {
98      strcat(out, "\n");
99      ptr1=ptr3+1;
100      continue;
101    }
102
103    /* if it wasn't something we know, copy to the > and  go again */
104    strncat(out, ptr2, ptr3-ptr2+1);
105    ptr1=ptr3+1;
106  }
107
108  out2=owl_text_substitute(out, "&lt;", "<");
109  g_free(out);
110  out=owl_text_substitute(out2, "&gt;", ">");
111  g_free(out2);
112  out2=owl_text_substitute(out, "&amp;", "&");
113  g_free(out);
114  out=owl_text_substitute(out2, "&quot;", "\"");
115  g_free(out2);
116  out2=owl_text_substitute(out, "&nbsp;", " ");
117  g_free(out);
118  out=owl_text_substitute(out2, "&ensp;", "  ");
119  g_free(out2);
120  out2=owl_text_substitute(out, "&emsp;", "   ");
121  g_free(out);
122  out=owl_text_substitute(out2, "&endash;", "--");
123  g_free(out2);
124  out2=owl_text_substitute(out, "&emdash;", "---");
125  g_free(out);
126
127  return(out2);
128}
129
130/* Caller must free return */
131G_GNUC_WARN_UNUSED_RESULT char *owl_text_expand_tabs(const char *in)
132{
133  int len = 0;
134  const char *p = in;
135  char *ret, *out;
136  int col;
137
138  col = 0;
139  while(*p) {
140    gunichar c = g_utf8_get_char(p);
141    const char *q = g_utf8_next_char(p);
142    switch (c) {
143    case '\t':
144      do { len++; col++; } while (col % OWL_TAB_WIDTH);
145      p = q;
146      continue;
147    case '\n':
148      col = 0;
149      break;
150    default:
151      col += mk_wcwidth(c);
152      break;
153    }
154    len += q - p;
155    p = q;
156  }
157
158  ret = g_new(char, len + 1);
159
160  p = in;
161  out = ret;
162
163  col = 0;
164  while(*p) {
165    gunichar c = g_utf8_get_char(p);
166    const char *q = g_utf8_next_char(p);
167    switch (c) {
168    case '\t':
169      do {*(out++) = ' '; col++; } while (col % OWL_TAB_WIDTH);
170      p = q;
171      continue;
172    case '\n':
173      col = 0;
174      break;
175    default:
176      col += mk_wcwidth(c);
177      break;
178    }
179    memcpy(out, p, q - p);
180    out += q - p;
181    p = q;
182  }
183
184  *out = 0;
185
186  return ret;
187}
188
189/* caller must free the return */
190G_GNUC_WARN_UNUSED_RESULT char *owl_text_wordwrap(const char *in, int col)
191{
192  char *out;
193  int cur, lastspace, len, lastnewline;
194
195  out=g_strdup(in);
196  len=strlen(in);
197  cur=0;
198  lastspace=-1;
199  lastnewline=-1;
200
201  while (cur<(len-1)) {
202    if (out[cur]==' ') {
203      lastspace=cur;
204      cur++;
205      continue;
206    } else if (out[cur]=='\n') {
207      lastnewline=cur;
208      cur++;
209      continue;
210    }
211
212    /* do we need to wrap? */
213    if ( (cur-(lastnewline+1)) > col ) {
214      if (lastspace==-1 ||
215          (lastnewline>0 && (lastspace<=lastnewline))) {
216        /* we can't help, sorry */
217        cur++;
218        continue;
219      }
220
221      /* turn the last space into a newline */
222      out[lastspace]='\n';
223      lastnewline=lastspace;
224      lastspace=-1;
225      cur++;
226      continue;
227    }
228
229    cur++;
230    continue;
231  }
232  return(out);
233}
234
235/* this modifies 'in' */
236void owl_text_wordunwrap(char *in)
237{
238  int i, j;
239
240  j=strlen(in);
241  for (i=0; i<j; i++) {
242    if ( (in[i]=='\n') &&
243         ((i>0) && (i<(j-1))) &&
244         (in[i-1]!='\n') &&
245         (in[i+1]!='\n') )
246      in[i]=' ';
247  }
248}
249
250/* return 1 if a string is only whitespace, otherwise 0 */
251int only_whitespace(const char *s)
252{
253  if (g_utf8_validate(s,-1,NULL)) {
254    const char *p;
255    for(p = s; p[0]; p=g_utf8_next_char(p)) {
256      if (!g_unichar_isspace(g_utf8_get_char(p))) return 0;
257    }
258  }
259  else {
260    int i;
261    for (i=0; s[i]; i++) {
262      if (!isspace((int) s[i])) return(0);
263    }
264  }
265  return(1);
266}
267
268/* Return a string with any occurances of 'from' replaced with 'to'.
269 * Caller must free returned string.
270 */
271G_GNUC_WARN_UNUSED_RESULT char *owl_text_substitute(const char *in, const char *from, const char *to)
272{
273  char **split = g_strsplit(in, from, 0), *out;
274  out = g_strjoinv(to, split);
275  g_strfreev(split);
276  return out;
277}
278
279/* Return a string which is like 'in' except that every instance of
280 * any character in 'toquote' found in 'in' is preceeded by the string
281 * 'quotestr'.  For example, owl_text_quote(in, "+*.", "\") would
282 * place a backslash before every '+', '*' or '.' in 'in'.  It is
283 * permissable for a character in 'quotestr' to be in 'toquote'.
284 * On success returns the string, on error returns NULL.
285 */
286G_GNUC_WARN_UNUSED_RESULT char *owl_text_quote(const char *in, const char *toquote, const char *quotestr)
287{
288  int i, x, r, place, escape;
289  int in_len, toquote_len, quotestr_len;
290  char *out;
291
292  in_len=strlen(in);
293  toquote_len=strlen(toquote);
294  quotestr_len=strlen(quotestr);
295  place=0;
296  escape = 0;
297  for (i=0; i<in_len; i++) {
298    if(strchr(toquote, in[i]) != NULL)
299      escape++;
300  }
301  out = g_new(char, in_len + quotestr_len*escape+1);
302  for (i=0; i<in_len; i++) {
303
304    /* check if it's a character that needs quoting */
305    for (x=0; x<toquote_len; x++) {
306      if (in[i]==toquote[x]) {
307        /* quote it */
308        for (r=0; r<quotestr_len; r++) {
309          out[place+r]=quotestr[r];
310        }
311        place+=quotestr_len;
312        break;
313      }
314    }
315
316    /* either way, we now copy over the character */
317    out[place]=in[i];
318    place++;
319  }
320  out[place]='\0';
321  return(out);
322}
Note: See TracBrowser for help on using the repository browser.