tutil.c - vote - simple cgi voting system for web and gopher
(HTM) git clone git://src.adamsgaard.dk/vote
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
tutil.c (4410B)
---
1 #include <sys/socket.h>
2 #include <sys/types.h>
3
4 #include <ctype.h>
5 #include <errno.h>
6 #include <netdb.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 #include <unistd.h>
13 #include <wchar.h>
14
15 int
16 uriencode(const char *s, char *buf, size_t bufsiz)
17 {
18 static char hex[] = "0123456789ABCDEF";
19 char *d = buf, *e = buf + bufsiz;
20 unsigned char c;
21
22 if (!bufsiz)
23 return 0;
24
25 for (; *s; ++s) {
26 c = (unsigned char)*s;
27 if (d + 4 >= e)
28 return 0;
29 if (c == ' ' || c == '#' || c == '%' || c == '?' || c == '"' ||
30 c == '&' || c == '<' || c <= 0x1f || c >= 0x7f) {
31 *d++ = '%';
32 *d++ = hex[c >> 4];
33 *d++ = hex[c & 0x0f];
34 } else {
35 *d++ = *s;
36 }
37 }
38 *d = '\0';
39
40 return 1;
41 }
42
43 int
44 hexdigit(int c)
45 {
46 if (c >= '0' && c <= '9')
47 return c - '0';
48 else if (c >= 'A' && c <= 'F')
49 return c - 'A' + 10;
50 else if (c >= 'a' && c <= 'f')
51 return c - 'a' + 10;
52
53 return 0;
54 }
55
56 /* decode until NUL separator or end of "key". */
57 int
58 decodeparam(char *buf, size_t bufsiz, const char *s)
59 {
60 size_t i;
61
62 if (!bufsiz)
63 return -1;
64
65 for (i = 0; *s && *s != '&'; s++) {
66 switch (*s) {
67 case '%':
68 if (i + 3 >= bufsiz)
69 return -1;
70 if (!isxdigit((unsigned char)*(s+1)) ||
71 !isxdigit((unsigned char)*(s+2)))
72 return -1;
73 buf[i++] = hexdigit(*(s+1)) * 16 + hexdigit(*(s+2));
74 s += 2;
75 break;
76 case '+':
77 if (i + 1 >= bufsiz)
78 return -1;
79 buf[i++] = ' ';
80 break;
81 default:
82 if (i + 1 >= bufsiz)
83 return -1;
84 buf[i++] = *s;
85 break;
86 }
87 }
88 buf[i] = '\0';
89
90 return i;
91 }
92
93 char *
94 getparam(const char *query, const char *s)
95 {
96 const char *p, *last = NULL;
97 size_t len;
98
99 len = strlen(s);
100 for (p = query; (p = strstr(p, s)); p += len) {
101 if (p[len] == '=' && (p == query || p[-1] == '&' || p[-1] == '?'))
102 last = p + len + 1;
103 }
104
105 return (char *)last;
106 }
107
108 int
109 friendlytime(time_t now, time_t t)
110 {
111 long long d = now - t;
112
113 if (d < 60) {
114 printf("just now");
115 } else if (d < 3600) {
116 printf("%lld minutes ago", d / 60);
117 } else if (d <= 24*3600) {
118 printf("%lld hours ago", d / 3600);
119 } else {
120 return 0;
121 }
122 return 1;
123 }
124
125 /* Escape characters below as HTML 2.0 / XML 1.0. */
126 void
127 xmlencode(const char *s)
128 {
129 for (; *s; s++) {
130 switch(*s) {
131 case '<': fputs("<", stdout); break;
132 case '>': fputs(">", stdout); break;
133 case '\'': fputs("'", stdout); break;
134 case '&': fputs("&", stdout); break;
135 case '"': fputs(""", stdout); break;
136 default: putchar(*s);
137 }
138 }
139 }
140
141 /* format `len' columns of characters. If string is shorter pad the rest
142 * with characters `pad`. */
143 int
144 utf8pad(char *buf, size_t bufsiz, const char *s, size_t len, int pad)
145 {
146 wchar_t wc;
147 size_t col = 0, i, slen, siz = 0;
148 int rl, w;
149
150 if (!len)
151 return -1;
152
153 slen = strlen(s);
154 for (i = 0; i < slen; i += rl) {
155 if ((rl = mbtowc(&wc, &s[i], slen - i < 4 ? slen - i : 4)) <= 0)
156 break;
157 if ((w = wcwidth(wc)) == -1)
158 continue;
159 if (col + w > len || (col + w == len && s[i + rl])) {
160 if (siz + 4 >= bufsiz)
161 return -1;
162 memcpy(&buf[siz], "\xe2\x80\xa6", 3);
163 siz += 3;
164 if (col + w == len && w > 1)
165 buf[siz++] = pad;
166 buf[siz] = '\0';
167 return 0;
168 }
169 if (siz + rl + 1 >= bufsiz)
170 return -1;
171 memcpy(&buf[siz], &s[i], rl);
172 col += w;
173 siz += rl;
174 buf[siz] = '\0';
175 }
176
177 len -= col;
178 if (siz + len + 1 >= bufsiz)
179 return -1;
180 memset(&buf[siz], pad, len);
181 siz += len;
182 buf[siz] = '\0';
183
184 return 0;
185 }
186
187 /* Escape characters in gopher, CR and LF are ignored */
188 void
189 gophertext(FILE *fp, const char *s, size_t len)
190 {
191 size_t i;
192
193 for (i = 0; *s && i < len; s++, i++) {
194 switch (*s) {
195 case '\r': /* ignore CR */
196 case '\n': /* ignore LF */
197 break;
198 case '\t':
199 fputs(" ", fp);
200 break;
201 default:
202 fputc(*s, fp);
203 break;
204 }
205 }
206 }
207
208 void
209 escapechars(char *s)
210 {
211 for (; *s; s++) {
212 switch (*s) {
213 case '#':
214 case ' ':
215 case '\t':
216 case ':':
217 case '.':
218 case '(':
219 case ')':
220 case '/':
221 *s = '_';
222 break;
223 case '\n':
224 *s = '\0';
225 return;
226 default:
227 break;
228 }
229 }
230 }
231
232 #ifdef NEED_STRLCPY /* OpenBSD implementation */
233 size_t
234 strlcpy(char *dst, const char *src, size_t dsize) {
235 const char *osrc = src;
236 size_t nleft = dsize;
237
238 if (nleft != 0) {
239 while (--nleft != 0) {
240 if ((*dst++= *src++) == '\0')
241 break;
242 }
243 }
244
245 if (nleft == 0) {
246 if (dsize != 0)
247 *dst = '\0';
248 while (*src++)
249 ;
250 }
251
252 return(src - osrc - 1);
253 }
254 #endif /* NEED_STRLCPY */