util.c - frontends - front-ends for some sites (experiment) | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
util.c (4633B) | |
--- | |
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+… | |
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… | |
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 /* seconds to duration string: "%H:%M:%S" or "%H:%M:%S" */ | |
209 int | |
210 durationstr(long secs, char *buf, size_t bufsiz) | |
211 { | |
212 int h, m, s, r; | |
213 | |
214 h = secs / 3600; | |
215 m = secs / 60; | |
216 s = secs; | |
217 if (h <= 0) | |
218 r = snprintf(buf, bufsiz, "%02d:%02d", m % 60, s % 60); | |
219 else | |
220 r = snprintf(buf, bufsiz, "%d:%02d:%02d", h, m % 60, s %… | |
221 | |
222 return r; | |
223 } | |
224 | |
225 /* print views with thousand separators, returns printed characters */ | |
226 size_t | |
227 printnumsep(const char *s) | |
228 { | |
229 const char *p; | |
230 size_t n = 0, ndigits = 0; | |
231 | |
232 /* first count all digits */ | |
233 for (p = s; *p; p++) | |
234 if (*p >= '0' && *p <= '9') | |
235 ndigits++; | |
236 | |
237 for (p = s; *p; p++) { | |
238 if (!(*p >= '0' && *p <= '9')) | |
239 continue; | |
240 | |
241 putchar(*p); | |
242 n++; | |
243 ndigits--; | |
244 | |
245 /* show separator on every 3 digits and when there are | |
246 digits remaining */ | |
247 if ((ndigits % 3) == 0 && ndigits > 0) { | |
248 putchar(','); | |
249 n++; | |
250 } | |
251 } | |
252 | |
253 return n; | |
254 } |