chiark / gitweb /
exercise the C client a bit from tests
[disorder] / lib / split.c
CommitLineData
460b9539 1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2004, 2006 Richard Kettlewell
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 */
20
21#include <config.h>
22#include "types.h"
23
24#include <ctype.h>
25#include <string.h>
26#include <errno.h>
27
28#include "mem.h"
29#include "split.h"
30#include "log.h"
31#include "charset.h"
32#include "vector.h"
33
34static inline int space(int c) {
35 return (c == ' '
36 || c == '\t'
37 || c == '\n'
38 || c == '\r');
39}
40
41static void no_error_handler(const char attribute((unused)) *msg,
42 void attribute((unused)) *u) {
43}
44
f9635e06
RK
45/* TODO: handle combining characters attached to delimiters in some
46 * sane way (might include reporting an error) */
47
460b9539 48char **split(const char *p,
49 int *np,
50 unsigned flags,
51 void (*error_handler)(const char *msg, void *u),
52 void *u) {
53 char *f, *g;
54 const char *q;
55 struct vector v;
56 size_t l;
57 int qc;
58
59 if(!error_handler) error_handler = no_error_handler;
60 vector_init(&v);
61 while(*p && !(*p == '#' && (flags & SPLIT_COMMENTS))) {
62 if(space(*p)) {
63 ++p;
64 continue;
65 }
66 if((flags & SPLIT_QUOTES) && (*p == '"' || *p == '\'')) {
67 qc = *p++;
68 l = 0;
69 for(q = p; *q && *q != qc; ++q) {
70 if(*q == '\\' && q[1])
71 ++q;
72 ++l;
73 }
74 if(!*q) {
75 error_handler("unterminated quoted string", u);
76 return 0;
77 }
78 f = g = xmalloc_noptr(l + 1);
79 for(q = p; *q != qc;) {
80 if(*q == '\\') {
81 ++q;
82 switch(*q) {
83 case '\\':
84 case '"':
85 case '\'':
86 *g++ = *q++;
87 break;
88 case 'n':
89 ++q;
90 *g++ = '\n';
91 break;
92 default:
93 error_handler("illegal escape sequence", u);
94 return 0;
95 }
96 } else
97 *g++ = *q++;
98 }
99 *g = 0;
100 p = q + 1;
101 } else {
102 for(q = p; *q && !space(*q); ++q)
103 ;
104 l = q - p;
105 f = xstrndup(p, l);
106 p = q;
107 }
108 vector_append(&v, f);
109 }
110 vector_terminate(&v);
111 if(np)
112 *np = v.nvec;
113 return v.vec;
114}
115
f9635e06
RK
116/* TODO handle initial combining characters sanely */
117
460b9539 118const char *quoteutf8(const char *s) {
119 size_t len = 3 + strlen(s);
120 const char *t;
121 char *r, *q;
122
123 /* see if we need to quote */
124 if(*s) {
125 for(t = s; *t; t++)
126 if((unsigned char)*t <= ' '
127 || *t == '"'
128 || *t == '\\'
129 || *t == '\''
130 || *t == '#')
131 break;
132 if(!*t)
133 return s;
134 }
135
136 /* we rely on ASCII characters only ever representing themselves in UTF-8. */
137 for(t = s; *t; t++) {
138 switch(*t) {
139 case '"':
140 case '\\':
141 case '\n':
142 ++len;
143 break;
144 }
145 }
146 q = r = xmalloc_noptr(len);
147 *q++ = '"';
148 for(t = s; *t; t++) {
149 switch(*t) {
150 case '"':
151 case '\\':
152 *q++ = '\\';
153 /* fall through */
154 default:
155 *q++ = *t;
156 break;
157 case '\n':
158 *q++ = '\\';
159 *q++ = 'n';
160 break;
161 }
162 }
163 *q++ = '"';
164 *q = 0;
165 return r;
166}
167
168/*
169Local Variables:
170c-basic-offset:2
171comment-column:40
172End:
173*/