fixes for escaping and printing - stagit-gopher - A git gopher frontend. (mirro… | |
git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2h… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit e46c746c435114ae3e7541ca93ffa7aacf4aaff3 | |
parent daa814e5c59ef7dcadfe779b46bd305e0d93f7a1 | |
Author: Hiltjo Posthuma <[email protected]> | |
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",… | |
/* 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) */ |