chiark / gitweb /
client.c make-cookie support
[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
5e49fa7f
RK
59 if(!error_handler)
60 error_handler = no_error_handler;
460b9539 61 vector_init(&v);
62 while(*p && !(*p == '#' && (flags & SPLIT_COMMENTS))) {
63 if(space(*p)) {
64 ++p;
65 continue;
66 }
67 if((flags & SPLIT_QUOTES) && (*p == '"' || *p == '\'')) {
68 qc = *p++;
69 l = 0;
70 for(q = p; *q && *q != qc; ++q) {
71 if(*q == '\\' && q[1])
72 ++q;
73 ++l;
74 }
75 if(!*q) {
76 error_handler("unterminated quoted string", u);
77 return 0;
78 }
79 f = g = xmalloc_noptr(l + 1);
80 for(q = p; *q != qc;) {
81 if(*q == '\\') {
82 ++q;
83 switch(*q) {
84 case '\\':
85 case '"':
86 case '\'':
87 *g++ = *q++;
88 break;
89 case 'n':
90 ++q;
91 *g++ = '\n';
92 break;
93 default:
94 error_handler("illegal escape sequence", u);
95 return 0;
96 }
97 } else
98 *g++ = *q++;
99 }
100 *g = 0;
101 p = q + 1;
102 } else {
103 for(q = p; *q && !space(*q); ++q)
104 ;
105 l = q - p;
106 f = xstrndup(p, l);
107 p = q;
108 }
109 vector_append(&v, f);
110 }
111 vector_terminate(&v);
112 if(np)
113 *np = v.nvec;
114 return v.vec;
115}
116
f9635e06
RK
117/* TODO handle initial combining characters sanely */
118
460b9539 119const char *quoteutf8(const char *s) {
120 size_t len = 3 + strlen(s);
121 const char *t;
122 char *r, *q;
123
124 /* see if we need to quote */
125 if(*s) {
126 for(t = s; *t; t++)
127 if((unsigned char)*t <= ' '
128 || *t == '"'
129 || *t == '\\'
130 || *t == '\''
131 || *t == '#')
132 break;
133 if(!*t)
134 return s;
135 }
136
137 /* we rely on ASCII characters only ever representing themselves in UTF-8. */
138 for(t = s; *t; t++) {
139 switch(*t) {
140 case '"':
141 case '\\':
142 case '\n':
143 ++len;
144 break;
145 }
146 }
147 q = r = xmalloc_noptr(len);
148 *q++ = '"';
149 for(t = s; *t; t++) {
150 switch(*t) {
151 case '"':
152 case '\\':
153 *q++ = '\\';
154 /* fall through */
155 default:
156 *q++ = *t;
157 break;
158 case '\n':
159 *q++ = '\\';
160 *q++ = 'n';
161 break;
162 }
163 }
164 *q++ = '"';
165 *q = 0;
166 return r;
167}
168
169/*
170Local Variables:
171c-basic-offset:2
172comment-column:40
173End:
174*/