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("&lt;", stdout);   break;
          132                 case '>':  fputs("&gt;", stdout);   break;
          133                 case '\'': fputs("&#39;", stdout);  break;
          134                 case '&':  fputs("&amp;", stdout);  break;
          135                 case '"':  fputs("&quot;", 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 */