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 | |
34 | static inline int space(int c) { |
35 | return (c == ' ' |
36 | || c == '\t' |
37 | || c == '\n' |
38 | || c == '\r'); |
39 | } |
40 | |
41 | static void no_error_handler(const char attribute((unused)) *msg, |
42 | void attribute((unused)) *u) { |
43 | } |
44 | |
45 | char **split(const char *p, |
46 | int *np, |
47 | unsigned flags, |
48 | void (*error_handler)(const char *msg, void *u), |
49 | void *u) { |
50 | char *f, *g; |
51 | const char *q; |
52 | struct vector v; |
53 | size_t l; |
54 | int qc; |
55 | |
56 | if(!error_handler) error_handler = no_error_handler; |
57 | vector_init(&v); |
58 | while(*p && !(*p == '#' && (flags & SPLIT_COMMENTS))) { |
59 | if(space(*p)) { |
60 | ++p; |
61 | continue; |
62 | } |
63 | if((flags & SPLIT_QUOTES) && (*p == '"' || *p == '\'')) { |
64 | qc = *p++; |
65 | l = 0; |
66 | for(q = p; *q && *q != qc; ++q) { |
67 | if(*q == '\\' && q[1]) |
68 | ++q; |
69 | ++l; |
70 | } |
71 | if(!*q) { |
72 | error_handler("unterminated quoted string", u); |
73 | return 0; |
74 | } |
75 | f = g = xmalloc_noptr(l + 1); |
76 | for(q = p; *q != qc;) { |
77 | if(*q == '\\') { |
78 | ++q; |
79 | switch(*q) { |
80 | case '\\': |
81 | case '"': |
82 | case '\'': |
83 | *g++ = *q++; |
84 | break; |
85 | case 'n': |
86 | ++q; |
87 | *g++ = '\n'; |
88 | break; |
89 | default: |
90 | error_handler("illegal escape sequence", u); |
91 | return 0; |
92 | } |
93 | } else |
94 | *g++ = *q++; |
95 | } |
96 | *g = 0; |
97 | p = q + 1; |
98 | } else { |
99 | for(q = p; *q && !space(*q); ++q) |
100 | ; |
101 | l = q - p; |
102 | f = xstrndup(p, l); |
103 | p = q; |
104 | } |
105 | vector_append(&v, f); |
106 | } |
107 | vector_terminate(&v); |
108 | if(np) |
109 | *np = v.nvec; |
110 | return v.vec; |
111 | } |
112 | |
113 | const char *quoteutf8(const char *s) { |
114 | size_t len = 3 + strlen(s); |
115 | const char *t; |
116 | char *r, *q; |
117 | |
118 | /* see if we need to quote */ |
119 | if(*s) { |
120 | for(t = s; *t; t++) |
121 | if((unsigned char)*t <= ' ' |
122 | || *t == '"' |
123 | || *t == '\\' |
124 | || *t == '\'' |
125 | || *t == '#') |
126 | break; |
127 | if(!*t) |
128 | return s; |
129 | } |
130 | |
131 | /* we rely on ASCII characters only ever representing themselves in UTF-8. */ |
132 | for(t = s; *t; t++) { |
133 | switch(*t) { |
134 | case '"': |
135 | case '\\': |
136 | case '\n': |
137 | ++len; |
138 | break; |
139 | } |
140 | } |
141 | q = r = xmalloc_noptr(len); |
142 | *q++ = '"'; |
143 | for(t = s; *t; t++) { |
144 | switch(*t) { |
145 | case '"': |
146 | case '\\': |
147 | *q++ = '\\'; |
148 | /* fall through */ |
149 | default: |
150 | *q++ = *t; |
151 | break; |
152 | case '\n': |
153 | *q++ = '\\'; |
154 | *q++ = 'n'; |
155 | break; |
156 | } |
157 | } |
158 | *q++ = '"'; |
159 | *q = 0; |
160 | return r; |
161 | } |
162 | |
163 | /* |
164 | Local Variables: |
165 | c-basic-offset:2 |
166 | comment-column:40 |
167 | End: |
168 | */ |