Rename Buttress to Halibut. I _think_ I've caught everything in this pass.
[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 int ustrlen(wchar_t *s) {
37 int len = 0;
38 while (*s++) len++;
39 return len;
40 }
41
42 wchar_t *uadv(wchar_t *s) {
43 return s + 1 + ustrlen(s);
44 }
45
46 wchar_t *ustrcpy(wchar_t *dest, wchar_t *source) {
47 wchar_t *ret = dest;
48 do {
49 *dest++ = *source;
50 } while (*source++);
51 return ret;
52 }
53
54 int ustrcmp(wchar_t *lhs, wchar_t *rhs) {
55 if (!lhs && !rhs) return 0;
56 if (!lhs) return -1;
57 if (!rhs) return +1;
58 while (*lhs && *rhs && *lhs==*rhs)
59 lhs++, rhs++;
60 if (*lhs < *rhs)
61 return -1;
62 else if (*lhs > *rhs)
63 return 1;
64 return 0;
65 }
66
67 wchar_t utolower(wchar_t c) {
68 if (c == L'\0')
69 return c; /* this property needed by ustricmp */
70 /* FIXME: this doesn't even come close */
71 if (c >= 'A' && c <= 'Z')
72 c += 'a'-'A';
73 return c;
74 }
75
76 int ustricmp(wchar_t *lhs, wchar_t *rhs) {
77 wchar_t lc, rc;
78 while ((lc = utolower(*lhs)) == (rc = utolower(*rhs)) && lc && rc)
79 lhs++, rhs++;
80 if (!lc && !rc)
81 return 0;
82 if (lc < rc)
83 return -1;
84 else
85 return 1;
86 }
87
88 wchar_t *ustrlow(wchar_t *s) {
89 wchar_t *p = s;
90 while (*p) {
91 *p = utolower(*p);
92 p++;
93 }
94 return s;
95 }
96
97 int utoi(wchar_t *s) {
98 int sign = +1;
99 int n;
100
101 if (*s == L'-') {
102 s++;
103 sign = -1;
104 }
105
106 n = 0;
107 while (*s && *s >= L'0' && *s <= L'9') {
108 n *= 10;
109 n += (*s - '0');
110 s++;
111 }
112
113 return n;
114 }
115
116 int utob(wchar_t *s) {
117 if (!ustricmp(s, L"yes") || !ustricmp(s, L"y") ||
118 !ustricmp(s, L"true") || !ustricmp(s, L"t"))
119 return TRUE;
120 return FALSE;
121 }
122
123 int uisdigit(wchar_t c) {
124 return c >= L'0' && c <= L'9';
125 }
126
127 #define USTRFTIME_DELTA 128
128 wchar_t *ustrftime(wchar_t *wfmt, struct tm *timespec) {
129 void *blk = NULL;
130 wchar_t *wblk, *wp;
131 char *fmt, *text, *p;
132 size_t size = 0;
133 size_t len;
134
135 /*
136 * strftime has the entertaining property that it returns 0
137 * _either_ on out-of-space _or_ on successful generation of
138 * the empty string. Hence we must ensure our format can never
139 * generate the empty string. Somebody throw a custard pie at
140 * whoever was responsible for that. Please?
141 */
142 if (wfmt) {
143 len = ustrlen(wfmt);
144 fmt = mknewa(char, 2+len);
145 ustrtoa(wfmt, fmt+1, len+1);
146 fmt[0] = ' ';
147 } else
148 fmt = " %c";
149
150 while (1) {
151 size += USTRFTIME_DELTA;
152 blk = resize((char *)blk, size);
153 len = strftime((char *)blk, size-1, fmt, timespec);
154 if (len > 0)
155 break;
156 }
157
158 /* Note: +1 for the terminating 0, -1 for the initial space in fmt */
159 wblk = resize((wchar_t *)blk, len);
160 text = mknewa(char, len);
161 strftime(text, len, fmt+1, timespec);
162 /*
163 * We operate in the C locale, so this all ought to be kosher
164 * ASCII. If we ever move outside ASCII machines, we may need
165 * to make this more portable...
166 */
167 for (wp = wblk, p = text; *p; p++, wp++)
168 *wp = *p;
169 *wp = 0;
170 if (wfmt)
171 sfree(fmt);
172 sfree(text);
173 return wblk;
174 }