fixes for escaping and printing - stagit-gopher - A git gopher frontend. (mirror)
 (HTM) git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/stagit-gopher/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit e46c746c435114ae3e7541ca93ffa7aacf4aaff3
 (DIR) parent daa814e5c59ef7dcadfe779b46bd305e0d93f7a1
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Fri, 17 Nov 2017 16:06:51 +0100
       
       fixes for escaping and printing
       
       - if the index or project description is empty don't print an empty line.
       - escape | in gph links.
       - when a column is not set / empty print it aligned.
       - pad text, then print it escaped.
       - print left-aligned headers of last column in a simpler way.
       
       Diffstat:
         M stagit-gopher-index.c               |     107 ++++++++++++++++++++-----------
         M stagit-gopher.c                     |     130 ++++++++++++++-----------------
       
       2 files changed, 127 insertions(+), 110 deletions(-)
       ---
 (DIR) diff --git a/stagit-gopher-index.c b/stagit-gopher-index.c
       @@ -25,17 +25,17 @@ static char *name = "";
        #define pledge(p1,p2) 0
        #endif
        
       -/* print `len' columns of characters. If string is shorter pad the rest
       +/* format `len' columns of characters. If string is shorter pad the rest
         * with characters `pad`. */
       -void
       -printutf8pad(FILE *fp, const char *s, size_t len, int pad)
       +int
       +utf8pad(char *buf, size_t bufsiz, const char *s, size_t len, int pad)
        {
                wchar_t w;
       -        size_t col = 0, i, slen;
       +        size_t col = 0, i, slen, siz = 0;
                int rl, wc;
        
                if (!len)
       -                return;
       +                return -1;
        
                slen = strlen(s);
                for (i = 0; i < slen && col < len + 1; i += rl) {
       @@ -43,43 +43,74 @@ printutf8pad(FILE *fp, const char *s, size_t len, int pad)
                                break;
                        if ((wc = wcwidth(w)) == -1)
                                wc = 1;
       -                col += (size_t)wc;
       +                col += wc;
                        if (col >= len && s[i + rl]) {
       -                        fputs("\xe2\x80\xa6", fp);
       +                        if (siz + 4 >= bufsiz)
       +                                return -1;
       +                        memcpy(&buf[siz], "\xe2\x80\xa6", 4);
       +                        return 0;
       +                }
       +                if (siz + rl + 1 >= bufsiz)
       +                        return -1;
       +                memcpy(&buf[siz], &s[i], rl);
       +                siz += rl;
       +                buf[siz] = '\0';
       +        }
       +
       +        len -= col;
       +        if (siz + len + 1 >= bufsiz)
       +                return -1;
       +        memset(&buf[siz], pad, len);
       +        siz += len;
       +        buf[siz] = '\0';
       +
       +        return 0;
       +}
       +
       +/* Escape characters in text in geomyidae .gph format,
       +   newlines are ignored */
       +void
       +gphtext(FILE *fp, const char *s, size_t len)
       +{
       +        size_t i;
       +
       +        for (i = 0; *s && i < len; i++) {
       +                switch (s[i]) {
       +                case '\r': /* ignore CR */
       +                case '\n': /* ignore LF */
       +                        break;
       +                case '\t':
       +                        fputs("        ", fp);
       +                        break;
       +                default:
       +                        fputc(s[i], fp);
                                break;
                        }
       -                fwrite(&s[i], 1, rl, fp);
                }
       -        for (; col < len; col++)
       -                putc(pad, fp);
        }
        
       +/* Escape characters in links in geomyidae .gph format */
        void
       -trim(char *buf, size_t bufsiz, const char *src)
       +gphlink(FILE *fp, const char *s, size_t len)
        {
       -        size_t d = 0, i, len, s;
       +        size_t i;
        
       -        len = strlen(src);
       -        for (s = 0; s < len && d < bufsiz - 1; s++) {
       -                switch (src[s]) {
       +        for (i = 0; *s && i < len; i++) {
       +                switch (s[i]) {
       +                case '\r': /* ignore CR */
       +                case '\n': /* ignore LF */
       +                        break;
                        case '\t':
       -                        if (d + 8 >= bufsiz - 1)
       -                                goto end;
       -                        for (i = 0; i < 8; i++)
       -                                buf[d++] = ' ';
       +                        fputs("        ", fp);
                                break;
       -                case '|':
       -                case '\n':
       -                case '\r':
       -                        buf[d++] = ' ';
       +                case '|': /* escape separators */
       +                        fputs("\\|", fp);
                                break;
                        default:
       -                        buf[d++] = src[s];
       +                        fputc(s[i], fp);
                                break;
                        }
                }
       -end:
       -        buf[d] = '\0';
        }
        
        void
       @@ -111,16 +142,15 @@ printtimeshort(FILE *fp, const git_time *intime)
        void
        writeheader(FILE *fp)
        {
       -        char buf[256];
       -
       -        trim(buf, sizeof(buf), description);
       -        if (buf[0] == 't' || buf[0] == '[')
       -                fputc('t', fp);
       -        fprintf(fp, "%s\n\n", buf);
       +        if (description[0]) {
       +                putchar('t');
       +                gphtext(fp, description, strlen(description));
       +                fputs("\n\n", fp);
       +        }
        
                fprintf(fp, "%-20.20s  ", "Name");
                fprintf(fp, "%-50.50s  ", "Description");
       -        fprintf(fp, "%-16.16s\n", "Last commit");
       +        fprintf(fp, "%s\n", "Last commit");
        }
        
        int
       @@ -155,16 +185,15 @@ writelog(FILE *fp)
                                *p = '\0';
        
                fputs("[1|", fp);
       -        trim(buf, sizeof(buf), stripped_name);
       -        printutf8pad(fp, buf, 20, ' ');
       +        utf8pad(buf, sizeof(buf), stripped_name, 20, ' ');
       +        gphlink(fp, buf, strlen(buf));
                fputs("  ", fp);
       -        trim(buf, sizeof(buf), description);
       -        printutf8pad(fp, buf, 50, ' ');
       +        utf8pad(buf, sizeof(buf), description, 50, ' ');
       +        gphlink(fp, buf, strlen(buf));
                fputs("  ", fp);
                if (author)
                        printtimeshort(fp, &(author->when));
       -        trim(buf, sizeof(buf), stripped_name);
       -        fprintf(fp, "|%s/%s/log.gph|server|port]\n", relpath, buf);
       +        fprintf(fp, "|%s/%s/log.gph|server|port]\n", relpath, stripped_name);
        
                git_commit_free(commit);
        err:
 (DIR) diff --git a/stagit-gopher.c b/stagit-gopher.c
       @@ -69,17 +69,17 @@ static const char *cachefile;
        #define pledge(p1,p2) 0
        #endif
        
       -/* print `len' columns of characters. If string is shorter pad the rest
       +/* format `len' columns of characters. If string is shorter pad the rest
         * with characters `pad`. */
       -void
       -printutf8pad(FILE *fp, const char *s, size_t len, int pad)
       +int
       +utf8pad(char *buf, size_t bufsiz, const char *s, size_t len, int pad)
        {
                wchar_t w;
       -        size_t col = 0, i, slen;
       +        size_t col = 0, i, slen, siz = 0;
                int rl, wc;
        
                if (!len)
       -                return;
       +                return -1;
        
                slen = strlen(s);
                for (i = 0; i < slen && col < len + 1; i += rl) {
       @@ -87,15 +87,28 @@ printutf8pad(FILE *fp, const char *s, size_t len, int pad)
                                break;
                        if ((wc = wcwidth(w)) == -1)
                                wc = 1;
       -                col += (size_t)wc;
       +                col += wc;
                        if (col >= len && s[i + rl]) {
       -                        fputs("\xe2\x80\xa6", fp);
       -                        break;
       +                        if (siz + 4 >= bufsiz)
       +                                return -1;
       +                        memcpy(&buf[siz], "\xe2\x80\xa6", 4);
       +                        return 0;
                        }
       -                fwrite(&s[i], 1, rl, fp);
       +                if (siz + rl + 1 >= bufsiz)
       +                        return -1;
       +                memcpy(&buf[siz], &s[i], rl);
       +                siz += rl;
       +                buf[siz] = '\0';
                }
       -        for (; col < len; col++)
       -                putc(pad, fp);
       +
       +        len -= col;
       +        if (siz + len + 1 >= bufsiz)
       +                return -1;
       +        memset(&buf[siz], pad, len);
       +        siz += len;
       +        buf[siz] = '\0';
       +
       +        return 0;
        }
        
        void
       @@ -277,35 +290,6 @@ xmlencode(FILE *fp, const char *s, size_t len)
                }
        }
        
       -void
       -trim(char *buf, size_t bufsiz, const char *src)
       -{
       -        size_t d = 0, i, len, s;
       -
       -        len = strlen(src);
       -        for (s = 0; s < len && d < bufsiz - 1; s++) {
       -                switch (src[s]) {
       -                case '\t':
       -                        if (d + 8 >= bufsiz - 1)
       -                                goto end;
       -                        for (i = 0; i < 8; i++)
       -                                buf[d++] = ' ';
       -                        break;
       -                case '\r': /* ignore CR */
       -                case '|': /* ignore separators here */
       -                        break;
       -                case '\n':
       -                        buf[d++] = ' ';
       -                        break;
       -                default:
       -                        buf[d++] = src[s];
       -                        break;
       -                }
       -        }
       -end:
       -        buf[d] = '\0';
       -}
       -
        /* Escape characters in text in geomyidae .gph format, with newlines */
        void
        gphtextnl(FILE *fp, const char *s, size_t len)
       @@ -316,7 +300,7 @@ gphtextnl(FILE *fp, const char *s, size_t len)
                        if (s[i] == '\n')
                                n = 0;
        
       -                /* escape 't' at the start of a line */
       +                /* escape with 't' at the start of a line */
                        if (!n && (s[i] == 't' || s[i] == '[')) {
                                fputc('t', fp);
                                n = 1;
       @@ -340,10 +324,15 @@ gphtext(FILE *fp, const char *s, size_t len)
        
                for (i = 0; *s && i < len; i++) {
                        switch (s[i]) {
       -                case '\r':
       -                case '\n': break;
       -                case '\t': fputs("        ", fp); break;
       -                default: fputc(s[i], fp);
       +                case '\r': /* ignore CR */
       +                case '\n': /* ignore LF */
       +                        break;
       +                case '\t':
       +                        fputs("        ", fp);
       +                        break;
       +                default:
       +                        fputc(s[i], fp);
       +                        break;
                        }
                }
        }
       @@ -356,16 +345,15 @@ gphlink(FILE *fp, const char *s, size_t len)
        
                for (i = 0; *s && i < len; i++) {
                        switch (s[i]) {
       -                case '\n':
       -                        /* in this context replace newline with space */
       -                        fputc(' ', fp);
       -                        break;
                        case '\r': /* ignore CR */
       -                case '|': /* ignore separators here */
       +                case '\n': /* ignore LF */
                                break;
                        case '\t':
                                fputs("        ", fp);
                                break;
       +                case '|': /* escape separators */
       +                        fputs("\\|", fp);
       +                        break;
                        default:
                                fputc(s[i], fp);
                                break;
       @@ -575,12 +563,12 @@ printshowfile(FILE *fp, struct commitinfo *ci)
                        if (strcmp(delta->old_file.path, delta->new_file.path)) {
                                snprintf(filename, sizeof(filename), "%s -> %s",
                                        delta->old_file.path, delta->new_file.path);
       -                        trim(buf, sizeof(buf), filename);
       +                        utf8pad(buf, sizeof(buf), filename, 35, ' ');
                        } else {
       -                        trim(buf, sizeof(buf), delta->old_file.path);
       +                        utf8pad(buf, sizeof(buf), delta->old_file.path, 35, ' ');
                        }
                        fputs("  ", fp);
       -                printutf8pad(fp, buf, 35, ' ');
       +                gphtext(fp, buf, strlen(buf));
        
                        add = ci->deltas[i]->addcount;
                        del = ci->deltas[i]->delcount;
       @@ -655,16 +643,14 @@ writelogline(FILE *fp, struct commitinfo *ci)
                fputs("[1|", fp);
                if (ci->author)
                        printtimeshort(fp, &(ci->author->when));
       +        else
       +                fputs("                ", fp);
                fputs("  ", fp);
       -        if (ci->summary) {
       -                trim(buf, sizeof(buf), ci->summary);
       -                printutf8pad(fp, buf, 50, ' ');
       -        }
       +        utf8pad(buf, sizeof(buf), ci->summary ? ci->summary : "", 50, ' ');
       +        gphlink(fp, buf, strlen(buf));
                fputs("  ", fp);
       -        if (ci->author) {
       -                trim(buf, sizeof(buf), ci->author->name);
       -                printutf8pad(fp, buf, 25, ' ');
       -        }
       +        utf8pad(buf, sizeof(buf), ci->author ? ci->author->name : "", 25, ' ');
       +        gphlink(fp, buf, strlen(buf));
                fprintf(fp, "|%s/commit/%s.gph", relpath, ci->oid);
                fputs("|server|port]\n", fp);
        }
       @@ -926,8 +912,8 @@ writefilestree(FILE *fp, git_tree *tree, const char *path)
                                fputs("[1|", fp);
                                fputs(filemode(git_tree_entry_filemode(entry)), fp);
                                fputs("  ", fp);
       -                        trim(buf, sizeof(buf), entrypath);
       -                        printutf8pad(fp, buf, 50, ' ');
       +                        utf8pad(buf, sizeof(buf), entrypath, 50, ' ');
       +                        gphlink(fp, buf, strlen(buf));
                                fputs("  ", fp);
                                if (lc > 0)
                                        fprintf(fp, "%7dL", lc);
       @@ -938,8 +924,8 @@ writefilestree(FILE *fp, git_tree *tree, const char *path)
                                git_object_free(obj);
                        } else if (!git_submodule_lookup(&module, repo, entryname)) {
                                fputs("[1|m---------  ", fp);
       -                        trim(buf, sizeof(buf), entrypath);
       -                        printutf8pad(fp, buf, 50, ' ');
       +                        utf8pad(buf, sizeof(buf), entrypath, 50, ' ');
       +                        gphlink(fp, buf, strlen(buf));
                                fprintf(fp, "|%s/file/.gitmodules.gph|server|port]\n", relpath);
                                /* NOTE: linecount omitted */
                                git_submodule_free(module);
       @@ -1042,21 +1028,23 @@ writerefs(FILE *fp)
                                        fprintf(fp, "%s\n", titles[j]);
                                        fprintf(fp, "  %-20.20s", "Name");
                                        fprintf(fp, "  %-16.16s", "Last commit date");
       -                                fprintf(fp, "  %-25.25s\n", "Author");
       +                                fprintf(fp, "  %s\n", "Author");
                                }
        
                                name = git_reference_shorthand(r);
        
                                fputs("  ", fp);
       -                        trim(buf, sizeof(buf), name);
       -                        printutf8pad(fp, buf, 20, ' ');
       +                        utf8pad(buf, sizeof(buf), name, 20, ' ');
       +                        gphlink(fp, buf, strlen(buf));
                                fputs("  ", fp);
                                if (ci->author)
                                        printtimeshort(fp, &(ci->author->when));
       +                        else
       +                                fputs("                ", fp);
                                fputs("  ", fp);
                                if (ci->author) {
       -                                trim(buf, sizeof(buf), ci->author->name);
       -                                printutf8pad(fp, buf, 25, ' ');
       +                                utf8pad(buf, sizeof(buf), ci->author->name, 25, ' ');
       +                                gphlink(fp, buf, strlen(buf));
                                }
                                fputs("\n", fp);
        
       @@ -1204,7 +1192,7 @@ main(int argc, char *argv[])
        
                fprintf(fp, "%-16.16s  ", "Date");
                fprintf(fp, "%-50.50s  ", "Commit message");
       -        fprintf(fp, "%-25.25s\n", "Author");
       +        fprintf(fp, "%s\n", "Author");
        
                if (cachefile) {
                        /* read from cache file (does not need to exist) */