fixes for escaping and printing - stagit-gopher - A git gopher frontend. (mirror)
git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/stagit-gopher/
Log
Files
Refs
Tags
README
LICENSE
---
commit e46c746c435114ae3e7541ca93ffa7aacf4aaff3
parent daa814e5c59ef7dcadfe779b46bd305e0d93f7a1
Author: Hiltjo Posthuma 
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(-)
---
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:
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) */