| tutil.c - vote - simple cgi voting system for web and gopher | |
| git clone git://src.adamsgaard.dk/vote | |
| Log | |
| Files | |
| Refs | |
| README | |
| 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+… | |
| 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 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 */ |