util.c - frontends - front-ends for some sites (experiment)
DIR Log
DIR Files
DIR Refs
DIR README
DIR 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+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 /* 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 % 60);
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 }