Add \cfg / -C directives to allow the user to choose the output file
[sgt/halibut] / ustring.c
1 /*
2 * ustring.c: Unicode string routines
3 */
4
5 #include <wchar.h>
6 #include <time.h>
7 #include "halibut.h"
8
9 wchar_t *ustrdup(wchar_t *s) {
10 wchar_t *r;
11 if (s) {
12 r = mknewa(wchar_t, 1+ustrlen(s));
13 ustrcpy(r, s);
14 } else {
15 r = mknew(wchar_t);
16 *r = 0;
17 }
18 return r;
19 }
20
21 char *ustrtoa(wchar_t *s, char *outbuf, int size) {
22 char *p;
23 if (!s) {
24 *outbuf = '\0';
25 return outbuf;
26 }
27 for (p = outbuf; *s && p < outbuf+size; p++,s++)
28 *p = *s;
29 if (p < outbuf+size)
30 *p = '\0';
31 else
32 outbuf[size-1] = '\0';
33 return outbuf;
34 }
35
36 char *utoa_dup(wchar_t *s) {
37 int len;
38 char *buf = NULL;
39
40 len = ustrlen(s) + 1;
41 do {
42 buf = resize(buf, len);
43 ustrtoa(s, buf, len);
44 len = (3 * len) / 2 + 1; /* this guarantees a strict increase */
45 } while ((int)strlen(buf) >= len-1);
46
47 buf = resize(buf, strlen(buf)+1);
48 return buf;
49 }
50
51 int ustrlen(wchar_t *s) {
52 int len = 0;
53 while (*s++) len++;
54 return len;
55 }
56
57 wchar_t *uadv(wchar_t *s) {
58 return s + 1 + ustrlen(s);
59 }
60
61 wchar_t *ustrcpy(wchar_t *dest, wchar_t *source) {
62 wchar_t *ret = dest;
63 do {
64 *dest++ = *source;
65 } while (*source++);
66 return ret;
67 }
68
69 int ustrcmp(wchar_t *lhs, wchar_t *rhs) {
70 if (!lhs && !rhs) return 0;
71 if (!lhs) return -1;
72 if (!rhs) return +1;
73 while (*lhs && *rhs && *lhs==*rhs)
74 lhs++, rhs++;
75 if (*lhs < *rhs)
76 return -1;
77 else if (*lhs > *rhs)
78 return 1;
79 return 0;
80 }
81
82 wchar_t utolower(wchar_t c) {
83 if (c == L'\0')
84 return c; /* this property needed by ustricmp */
85 /* FIXME: this doesn't even come close */
86 if (c >= 'A' && c <= 'Z')
87 c += 'a'-'A';
88 return c;
89 }
90
91 int uisalpha(wchar_t c) {
92 /* FIXME: this doesn't even come close */
93 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
94 }
95
96 int ustricmp(wchar_t *lhs, wchar_t *rhs) {
97 wchar_t lc, rc;
98 while ((lc = utolower(*lhs)) == (rc = utolower(*rhs)) && lc && rc)
99 lhs++, rhs++;
100 if (!lc && !rc)
101 return 0;
102 if (lc < rc)
103 return -1;
104 else
105 return 1;
106 }
107
108 wchar_t *ustrlow(wchar_t *s) {
109 wchar_t *p = s;
110 while (*p) {
111 *p = utolower(*p);
112 p++;
113 }
114 return s;
115 }
116
117 int utoi(wchar_t *s) {
118 int sign = +1;
119 int n;
120
121 if (*s == L'-') {
122 s++;
123 sign = -1;
124 }
125
126 n = 0;
127 while (*s && *s >= L'0' && *s <= L'9') {
128 n *= 10;
129 n += (*s - '0');
130 s++;
131 }
132
133 return n;
134 }
135
136 int utob(wchar_t *s) {
137 if (!ustricmp(s, L"yes") || !ustricmp(s, L"y") ||
138 !ustricmp(s, L"true") || !ustricmp(s, L"t"))
139 return TRUE;
140 return FALSE;
141 }
142
143 int uisdigit(wchar_t c) {
144 return c >= L'0' && c <= L'9';
145 }
146
147 #define USTRFTIME_DELTA 128
148 wchar_t *ustrftime(wchar_t *wfmt, struct tm *timespec) {
149 void *blk = NULL;
150 wchar_t *wblk, *wp;
151 char *fmt, *text, *p;
152 size_t size = 0;
153 size_t len;
154
155 /*
156 * strftime has the entertaining property that it returns 0
157 * _either_ on out-of-space _or_ on successful generation of
158 * the empty string. Hence we must ensure our format can never
159 * generate the empty string. Somebody throw a custard pie at
160 * whoever was responsible for that. Please?
161 */
162 if (wfmt) {
163 len = ustrlen(wfmt);
164 fmt = mknewa(char, 2+len);
165 ustrtoa(wfmt, fmt+1, len+1);
166 fmt[0] = ' ';
167 } else
168 fmt = " %c";
169
170 while (1) {
171 size += USTRFTIME_DELTA;
172 blk = resize((char *)blk, size);
173 len = strftime((char *)blk, size-1, fmt, timespec);
174 if (len > 0)
175 break;
176 }
177
178 /* Note: +1 for the terminating 0, -1 for the initial space in fmt */
179 wblk = resize((wchar_t *)blk, len);
180 text = mknewa(char, len);
181 strftime(text, len, fmt+1, timespec);
182 /*
183 * We operate in the C locale, so this all ought to be kosher
184 * ASCII. If we ever move outside ASCII machines, we may need
185 * to make this more portable...
186 */
187 for (wp = wblk, p = text; *p; p++, wp++)
188 *wp = *p;
189 *wp = 0;
190 if (wfmt)
191 sfree(fmt);
192 sfree(text);
193 return wblk;
194 }