util.c - frontends - front-ends for some sites (experiment) (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- util.c (4560B) --- 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 */ 226 void 227 printnumsep(const char *s) 228 { 229 const char *p; 230 int 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 ndigits--; 243 244 /* show separator on every 3 digits and when there are 245 digits remaining */ 246 if ((ndigits % 3) == 0 && ndigits > 0) 247 putchar(','); 248 } 249 }