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("&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 /* 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 }