source: text.c @ 367fbf3

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 367fbf3 was 47519e1b, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 16 years ago
text entry: * first pass at utf-8 text entry. This is not yet complete, and it certainly has bugs. The following is an incomplete list of functions that will probably misbehave if you use them. - owl_editwin_move_to_nextword() - owl_editwin_move_to_previousword() - owl_editwin_delete_nextword() - owl_editwin_delete_previousword() - owl_editwin_delete_to_endofline() - owl_editwin_fill_paragraph() format text: * owl_fmtext_curs_waddstr() contract restored to match trunk. * owl_fmtext_curs_waddstr_without_search() added. misc: * Importing Markus Kuhn's wcwidth.c from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c * Change wcwidth() calls to mk_wcwidth()
  • Property mode set to 100644
File size: 9.1 KB
Line 
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include "owl.h"
6
7static const char fileIdent[] = "$Id$";
8
9/* start with line aline (where the first line is 1) and print 'lines'
10 *  lines
11 */
12int owl_text_truncate_lines(char *out, char *in, int aline, int lines)
13{
14  char *ptr1, *ptr2;
15  int i;
16
17  strcpy(out, "");
18 
19  if (aline==0) aline=1; /* really illegal use */
20
21  /* find the starting line */
22  ptr1=in;
23  if (aline!=1) {
24     for (i=0; i<aline-1; i++) {
25      ptr1=strchr(ptr1, '\n');
26      if (!ptr1) return(-1);
27      ptr1++;
28    }
29  }
30  /* ptr1 now holds the starting point */
31
32  /* copy in the next 'lines' lines */
33  if (lines<1) return(-1);
34 
35  for (i=0; i<lines; i++) {
36    ptr2=strchr(ptr1, '\n');
37    if (!ptr2) {
38      strcat(out, ptr1);
39      return(-1);
40    }
41    strncat(out, ptr1, ptr2-ptr1+1);
42    ptr1=ptr2+1;
43  }
44  return(0);
45}
46
47 
48/* the first column is column 0.  The message is expected to end in a
49 * new line for now */
50void owl_text_truncate_cols(char *out, char *in, int acol, int bcol)
51{
52  char *ptr_s, *ptr_e, *ptr_c, *tmpbuff, *last;
53  int col, cnt, padding;
54 
55  tmpbuff=owl_malloc(strlen(in)+20);
56
57  strcpy(tmpbuff, "");
58  last=in+strlen(in)-1;
59  ptr_s=in;
60  while (ptr_s<last) {
61    ptr_e=strchr(ptr_s, '\n');
62    if (!ptr_e) {
63      /* but this shouldn't happen if we end in a \n */
64      break;
65    }
66   
67    if (ptr_e==ptr_s) {
68      strcat(tmpbuff, "\n");
69      ptr_s++;
70      continue;
71    }
72
73    col = 0;
74    cnt = 0;
75    padding = 0;
76    ptr_c = ptr_s;
77    while(col < bcol && ptr_c < ptr_e) {
78      gunichar c = g_utf8_get_char(ptr_c);
79      if (col + mk_wcwidth(c) > bcol) break;
80      col += mk_wcwidth(c);
81      ptr_c = g_utf8_next_char(ptr_c);
82      if (col >= acol) {
83        if (cnt == 0) {
84          ptr_s = ptr_c;
85          padding = col - acol;
86        }
87        ++cnt;
88      }
89    }
90    if (cnt) {
91      while(padding-- > 0) {
92        strcat(tmpbuff, " ");
93      }
94      strncat(tmpbuff, ptr_s, ptr_c - ptr_s - 1);
95    }
96    strcat(tmpbuff, "\n");
97    ptr_s = ptr_e + 1;
98#if 0
99    /* we need to check that we won't run over here */
100    if ( (ptr_e-ptr_s) < (bcol-acol) ) {
101      len=ptr_e-(ptr_s+acol);
102    } else {
103      len=bcol-acol;
104    }
105    if ((ptr_s+len)>=last) {
106      len-=last-(ptr_s+len);
107    }
108
109    strncat(tmpbuff, ptr_s+acol, len);
110    strcat(tmpbuff, "\n");
111
112    ptr_s=ptr_e+1;
113#endif
114  }
115  strcpy(out, tmpbuff);
116  owl_free(tmpbuff);
117}
118
119
120void owl_text_indent(char *out, char *in, int n)
121{
122  char *ptr1, *ptr2, *last;
123  int i;
124
125  strcpy(out, "");
126
127  last=in+strlen(in)-1;
128  ptr1=in;
129  while (ptr1<=last) {
130    for (i=0; i<n; i++) {
131      strcat(out, " ");
132    }
133    ptr2=strchr(ptr1, '\n');
134    if (!ptr2) {
135      strcat(out, ptr1);
136      break;
137    } else {
138      strncat(out, ptr1, ptr2-ptr1+1);
139    }
140    ptr1=ptr2+1;
141  }
142}
143
144int owl_text_num_lines(char *in)
145{
146  int lines, i;
147
148  lines=0;
149  for (i=0; in[i]!='\0'; i++) {
150    if (in[i]=='\n') lines++;
151  }
152
153  /* if the last char wasn't a \n there's one more line */
154  if (i>0 && in[i-1]!='\n') lines++;
155
156  return(lines);
157}
158
159
160/* caller must free the return */
161char *owl_text_htmlstrip(char *in)
162{
163  char *ptr1, *end, *ptr2, *ptr3, *out, *out2;
164
165  out=owl_malloc(strlen(in)+30);
166  strcpy(out, "");
167
168  ptr1=in;
169  end=in+strlen(in);
170 
171  while(ptr1<end) {
172    /* look for an open bracket */
173    ptr2=strchr(ptr1, '<');
174
175    /* if none, copy in from here to end and exit */
176    if (ptr2==NULL) {
177      strcat(out, ptr1);
178      break;
179    }
180
181    /* otherwise copy in everything before the open bracket */
182    if (ptr2>ptr1) {
183      strncat(out, ptr1, ptr2-ptr1);
184    }
185
186    /* find the close bracket */
187    ptr3=strchr(ptr2, '>');
188   
189    /* if there is no close, copy as you are and exit */
190    if (!ptr3) {
191      strcat(out, ptr2);
192      break;
193    }
194
195    /* look for things we know */
196    if (!strncasecmp(ptr2, "<BODY ", 6) ||
197        !strncasecmp(ptr2, "<FONT", 5) ||
198        !strncasecmp(ptr2, "<HTML", 5) ||
199        !strncasecmp(ptr2, "</FONT", 6) ||
200        !strncasecmp(ptr2, "</HTML", 6) ||
201        !strncasecmp(ptr2, "</BODY", 6)) {
202
203      /* advance to beyond the angle brakcet and go again */
204      ptr1=ptr3+1;
205      continue;
206    }
207    if (!strncasecmp(ptr2, "<BR>", 4)) {
208      strcat(out, "\n");
209      ptr1=ptr3+1;
210      continue;
211    }
212
213    /* if it wasn't something we know, copy to the > and  go again */
214    strncat(out, ptr2, ptr3-ptr2+1);
215    ptr1=ptr3+1;
216  }
217
218  out2=owl_text_substitute(out, "&lt;", "<");
219  owl_free(out);
220  out=owl_text_substitute(out2, "&gt;", ">");
221  owl_free(out2);
222  out2=owl_text_substitute(out, "&amp;", "&");
223  owl_free(out);
224  out=owl_text_substitute(out2, "&quot;", "\"");
225  owl_free(out2);
226  out2=owl_text_substitute(out, "&nbsp;", " ");
227  owl_free(out);
228  out=owl_text_substitute(out2, "&ensp;", "  ");
229  owl_free(out2);
230  out2=owl_text_substitute(out, "&emsp;", "   ");
231  owl_free(out);
232  out=owl_text_substitute(out2, "&endash;", "--");
233  owl_free(out2);
234  out2=owl_text_substitute(out, "&emdash;", "---");
235  owl_free(out);
236
237  return(out2);
238}
239
240/* caller must free the return */
241char *owl_text_wordwrap(char *in, int col)
242{
243  char *out;
244  int cur, lastspace, len, lastnewline;
245
246  out=owl_strdup(in);
247  len=strlen(in);
248  cur=0;
249  lastspace=-1;
250  lastnewline=-1;
251
252  while (cur<(len-1)) {
253    if (out[cur]==' ') {
254      lastspace=cur;
255      cur++;
256      continue;
257    } else if (out[cur]=='\n') {
258      lastnewline=cur;
259      cur++;
260      continue;
261    }
262
263    /* do we need to wrap? */
264    if ( (cur-(lastnewline+1)) > col ) {
265      if (lastspace==-1 ||
266          (lastnewline>0 && (lastspace<=lastnewline))) {
267        /* we can't help, sorry */
268        cur++;
269        continue;
270      }
271
272      /* turn the last space into a newline */
273      out[lastspace]='\n';
274      lastnewline=lastspace;
275      lastspace=-1;
276      cur++;
277      continue;
278    }
279
280    cur++;
281    continue;
282  }
283  return(out);
284}
285
286/* this modifies 'in' */
287void owl_text_wordunwrap(char *in)
288{
289  int i, j;
290
291  j=strlen(in);
292  for (i=0; i<j; i++) {
293    if ( (in[i]=='\n') &&
294         ((i>0) && (i<(j-1))) &&
295         (in[i-1]!='\n') &&
296         (in[i+1]!='\n') )
297      in[i]=' ';
298  }
299}
300
301/* exactly like strstr but case insensitive */
302char *stristr(char *a, char *b)
303{
304  char *x, *y;
305  char *ret = NULL;
306  if ((x = g_utf8_casefold(a, -1)) != NULL) {
307    if ((y = g_utf8_casefold(b, -1)) != NULL) {
308      ret = strstr(x, y);
309      if (ret != NULL) {
310        ret = ret - x + a;
311      }
312      g_free(y);
313    }
314    g_free(x);
315  }
316  return(ret);
317}
318
319/* return 1 if a string is only whitespace, otherwise 0 */
320int only_whitespace(char *s)
321{
322  if (g_utf8_validate(s,-1,NULL)) {
323    char *p;
324    for(p = s; p[0]; p=g_utf8_next_char(p)) {
325      if (!g_unichar_isspace(g_utf8_get_char(p))) return 0;
326    }
327  }
328  else {
329    int i;
330    for (i=0; s[i]; i++) {
331      if (!isspace((int) s[i])) return(0);
332    }
333  }
334  return(1);
335}
336
337char *owl_getquoting(char *line)
338{
339  if (line[0]=='\0') return("'");
340  if (strchr(line, '\'')) return("\"");
341  if (strchr(line, '"')) return("'");
342  if (strchr(line, ' ')) return("'");
343  return("");
344}
345
346/* Return a string with any occurances of 'from' replaced with 'to'.
347 * Does not currently handle backslash quoting, but may in the future.
348 * Caller must free returned string.
349 */
350char *owl_text_substitute(char *in, char *from, char *to)
351{
352 
353  char *out;
354  int   outlen, tolen, fromlen, inpos=0, outpos=0;
355
356  if (!*from) return owl_strdup(in);
357
358  outlen = strlen(in)+1;
359  tolen  = strlen(to);
360  fromlen  = strlen(from);
361  out = owl_malloc(outlen);
362
363  while (in[inpos]) {
364    if (!strncmp(in+inpos, from, fromlen)) {
365      outlen += tolen;
366      out = owl_realloc(out, outlen);
367      strcpy(out+outpos, to);
368      inpos += fromlen;
369      outpos += tolen;
370    } else {
371      out[outpos] = in[inpos];
372      inpos++; outpos++;
373    }
374  }
375  out[outpos] = '\0';
376  return(out);
377}
378
379/* replace all instances of character a in buff with the character
380 * b.  buff must be null terminated.
381 */
382void owl_text_tr(char *buff, char a, char b)
383{
384  int i;
385
386  owl_function_debugmsg("In: %s", buff);
387  for (i=0; buff[i]!='\0'; i++) {
388    if (buff[i]==a) buff[i]=b;
389  }
390  owl_function_debugmsg("Out: %s", buff);
391}
392
393/* Return a string which is like 'in' except that every instance of
394 * any character in 'toquote' found in 'in' is preceeded by the string
395 * 'quotestr'.  For example, owl_text_quote(in, "+*.", "\") would
396 * place a backslash before every '+', '*' or '.' in 'in'.  It is
397 * permissable for a character in 'quotestr' to be in 'toquote'.
398 * On success returns the string, on error returns NULL.
399 */
400char *owl_text_quote(char *in, char *toquote, char *quotestr)
401{
402  int i, x, r, place, escape;
403  int in_len, toquote_len, quotestr_len;
404  char *out;
405
406  in_len=strlen(in);
407  toquote_len=strlen(toquote);
408  quotestr_len=strlen(quotestr);
409  out=owl_malloc((in_len*quotestr_len)+30);
410  place=0;
411  escape = 0;
412  for (i=0; i<in_len; i++) {
413    if(strchr(toquote, in[i]) != NULL)
414      escape++;
415  }
416  out = owl_malloc(in_len + quotestr_len*escape+1);
417  for (i=0; i<in_len; i++) {
418
419    /* check if it's a character that needs quoting */
420    for (x=0; x<toquote_len; x++) {
421      if (in[i]==toquote[x]) {
422        /* quote it */
423        for (r=0; r<quotestr_len; r++) {
424          out[place+r]=quotestr[r];
425        }
426        place+=quotestr_len;
427        break;
428      }
429    }
430
431    /* either way, we now copy over the character */
432    out[place]=in[i];
433    place++;
434  }
435  out[place]='\0';
436  return(out);
437}
Note: See TracBrowser for help on using the repository browser.