istagit-gopher-index.c - stagit-gopher - A git gopher frontend. (mirror) Err bitreich.org 70 hgit clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/stagit-gopher/ URL:git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/stagit-gopher/ bitreich.org 70 1Log /scm/stagit-gopher/log.gph bitreich.org 70 1Files /scm/stagit-gopher/files.gph bitreich.org 70 1Refs /scm/stagit-gopher/refs.gph bitreich.org 70 1Tags /scm/stagit-gopher/tag bitreich.org 70 1README /scm/stagit-gopher/file/README.gph bitreich.org 70 1LICENSE /scm/stagit-gopher/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 istagit-gopher-index.c (6805B) Err bitreich.org 70 i--- Err bitreich.org 70 i 1 #include Err bitreich.org 70 i 2 #include Err bitreich.org 70 i 3 #include Err bitreich.org 70 i 4 #include Err bitreich.org 70 i 5 #include Err bitreich.org 70 i 6 #include Err bitreich.org 70 i 7 #include Err bitreich.org 70 i 8 #include Err bitreich.org 70 i 9 #include Err bitreich.org 70 i 10 Err bitreich.org 70 i 11 #include Err bitreich.org 70 i 12 Err bitreich.org 70 i 13 #define PAD_TRUNCATE_SYMBOL "\xe2\x80\xa6" /* symbol: "ellipsis" */ Err bitreich.org 70 i 14 #define UTF_INVALID_SYMBOL "\xef\xbf\xbd" /* symbol: "replacement" */ Err bitreich.org 70 i 15 Err bitreich.org 70 i 16 static git_repository *repo; Err bitreich.org 70 i 17 Err bitreich.org 70 i 18 static const char *relpath = ""; Err bitreich.org 70 i 19 Err bitreich.org 70 i 20 static char description[255] = "Repositories"; Err bitreich.org 70 i 21 static char *name = ""; Err bitreich.org 70 i 22 Err bitreich.org 70 i 23 /* Handle read or write errors for a FILE * stream */ Err bitreich.org 70 i 24 void Err bitreich.org 70 i 25 checkfileerror(FILE *fp, const char *name, int mode) Err bitreich.org 70 i 26 { Err bitreich.org 70 i 27 if (mode == 'r' && ferror(fp)) Err bitreich.org 70 i 28 errx(1, "read error: %s", name); Err bitreich.org 70 i 29 else if (mode == 'w' && (fflush(fp) || ferror(fp))) Err bitreich.org 70 i 30 errx(1, "write error: %s", name); Err bitreich.org 70 i 31 } Err bitreich.org 70 i 32 Err bitreich.org 70 i 33 /* Format `len' columns of characters. If string is shorter pad the rest Err bitreich.org 70 i 34 * with characters `pad`. */ Err bitreich.org 70 i 35 int Err bitreich.org 70 i 36 utf8pad(char *buf, size_t bufsiz, const char *s, size_t len, int pad) Err bitreich.org 70 i 37 { Err bitreich.org 70 i 38 wchar_t wc; Err bitreich.org 70 i 39 size_t col = 0, i, slen, siz = 0; Err bitreich.org 70 i 40 int inc, rl, w; Err bitreich.org 70 i 41 Err bitreich.org 70 i 42 if (!bufsiz) Err bitreich.org 70 i 43 return -1; Err bitreich.org 70 i 44 if (!len) { Err bitreich.org 70 i 45 buf[0] = '\0'; Err bitreich.org 70 i 46 return 0; Err bitreich.org 70 i 47 } Err bitreich.org 70 i 48 Err bitreich.org 70 i 49 slen = strlen(s); Err bitreich.org 70 i 50 for (i = 0; i < slen; i += inc) { Err bitreich.org 70 i 51 inc = 1; /* next byte */ Err bitreich.org 70 i 52 if ((unsigned char)s[i] < 32) Err bitreich.org 70 i 53 continue; Err bitreich.org 70 i 54 Err bitreich.org 70 i 55 rl = mbtowc(&wc, &s[i], slen - i < 4 ? slen - i : 4); Err bitreich.org 70 i 56 inc = rl; Err bitreich.org 70 i 57 if (rl < 0) { Err bitreich.org 70 i 58 mbtowc(NULL, NULL, 0); /* reset state */ Err bitreich.org 70 i 59 inc = 1; /* invalid, seek next byte */ Err bitreich.org 70 i 60 w = 1; /* replacement char is one width */ Err bitreich.org 70 i 61 } else if ((w = wcwidth(wc)) == -1) { Err bitreich.org 70 i 62 continue; Err bitreich.org 70 i 63 } Err bitreich.org 70 i 64 Err bitreich.org 70 i 65 if (col + w > len || (col + w == len && s[i + inc])) { Err bitreich.org 70 i 66 if (siz + 4 >= bufsiz) Err bitreich.org 70 i 67 return -1; Err bitreich.org 70 i 68 memcpy(&buf[siz], PAD_TRUNCATE_SYMBOL, sizeof(PAD_TRUNCATE_SYMBOL) - 1); Err bitreich.org 70 i 69 siz += sizeof(PAD_TRUNCATE_SYMBOL) - 1; Err bitreich.org 70 i 70 buf[siz] = '\0'; Err bitreich.org 70 i 71 col++; Err bitreich.org 70 i 72 break; Err bitreich.org 70 i 73 } else if (rl < 0) { Err bitreich.org 70 i 74 if (siz + 4 >= bufsiz) Err bitreich.org 70 i 75 return -1; Err bitreich.org 70 i 76 memcpy(&buf[siz], UTF_INVALID_SYMBOL, sizeof(UTF_INVALID_SYMBOL) - 1); Err bitreich.org 70 i 77 siz += sizeof(UTF_INVALID_SYMBOL) - 1; Err bitreich.org 70 i 78 buf[siz] = '\0'; Err bitreich.org 70 i 79 col++; Err bitreich.org 70 i 80 continue; Err bitreich.org 70 i 81 } Err bitreich.org 70 i 82 if (siz + inc + 1 >= bufsiz) Err bitreich.org 70 i 83 return -1; Err bitreich.org 70 i 84 memcpy(&buf[siz], &s[i], inc); Err bitreich.org 70 i 85 siz += inc; Err bitreich.org 70 i 86 buf[siz] = '\0'; Err bitreich.org 70 i 87 col += w; Err bitreich.org 70 i 88 } Err bitreich.org 70 i 89 Err bitreich.org 70 i 90 len -= col; Err bitreich.org 70 i 91 if (siz + len + 1 >= bufsiz) Err bitreich.org 70 i 92 return -1; Err bitreich.org 70 i 93 memset(&buf[siz], pad, len); Err bitreich.org 70 i 94 siz += len; Err bitreich.org 70 i 95 buf[siz] = '\0'; Err bitreich.org 70 i 96 Err bitreich.org 70 i 97 return 0; Err bitreich.org 70 i 98 } Err bitreich.org 70 i 99 Err bitreich.org 70 i 100 /* Escape characters in text in geomyidae .gph format, Err bitreich.org 70 i 101 newlines are ignored */ Err bitreich.org 70 i 102 void Err bitreich.org 70 i 103 gphtext(FILE *fp, const char *s, size_t len) Err bitreich.org 70 i 104 { Err bitreich.org 70 i 105 size_t i; Err bitreich.org 70 i 106 Err bitreich.org 70 i 107 for (i = 0; *s && i < len; s++, i++) { Err bitreich.org 70 i 108 switch (*s) { Err bitreich.org 70 i 109 case '\r': /* ignore CR */ Err bitreich.org 70 i 110 case '\n': /* ignore LF */ Err bitreich.org 70 i 111 break; Err bitreich.org 70 i 112 case '\t': Err bitreich.org 70 i 113 fputs(" ", fp); Err bitreich.org 70 i 114 break; Err bitreich.org 70 i 115 default: Err bitreich.org 70 i 116 putc(*s, fp); Err bitreich.org 70 i 117 break; Err bitreich.org 70 i 118 } Err bitreich.org 70 i 119 } Err bitreich.org 70 i 120 } Err bitreich.org 70 i 121 Err bitreich.org 70 i 122 /* Escape characters in links in geomyidae .gph format */ Err bitreich.org 70 i 123 void Err bitreich.org 70 i 124 gphlink(FILE *fp, const char *s, size_t len) Err bitreich.org 70 i 125 { Err bitreich.org 70 i 126 size_t i; Err bitreich.org 70 i 127 Err bitreich.org 70 i 128 for (i = 0; *s && i < len; s++, i++) { Err bitreich.org 70 i 129 switch (*s) { Err bitreich.org 70 i 130 case '\r': /* ignore CR */ Err bitreich.org 70 i 131 case '\n': /* ignore LF */ Err bitreich.org 70 i 132 break; Err bitreich.org 70 i 133 case '\t': Err bitreich.org 70 i 134 fputs(" ", fp); Err bitreich.org 70 i 135 break; Err bitreich.org 70 i 136 case '|': /* escape separators */ Err bitreich.org 70 i 137 fputs("\\|", fp); Err bitreich.org 70 i 138 break; Err bitreich.org 70 i 139 default: Err bitreich.org 70 i 140 putc(*s, fp); Err bitreich.org 70 i 141 break; Err bitreich.org 70 i 142 } Err bitreich.org 70 i 143 } Err bitreich.org 70 i 144 } Err bitreich.org 70 i 145 Err bitreich.org 70 i 146 void Err bitreich.org 70 i 147 joinpath(char *buf, size_t bufsiz, const char *path, const char *path2) Err bitreich.org 70 i 148 { Err bitreich.org 70 i 149 int r; Err bitreich.org 70 i 150 Err bitreich.org 70 i 151 r = snprintf(buf, bufsiz, "%s%s%s", Err bitreich.org 70 i 152 path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2); Err bitreich.org 70 i 153 if (r < 0 || (size_t)r >= bufsiz) Err bitreich.org 70 i 154 errx(1, "path truncated: '%s%s%s'", Err bitreich.org 70 i 155 path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2); Err bitreich.org 70 i 156 } Err bitreich.org 70 i 157 Err bitreich.org 70 i 158 void Err bitreich.org 70 i 159 printtimeshort(FILE *fp, const git_time *intime) Err bitreich.org 70 i 160 { Err bitreich.org 70 i 161 struct tm *intm; Err bitreich.org 70 i 162 time_t t; Err bitreich.org 70 i 163 char out[32]; Err bitreich.org 70 i 164 Err bitreich.org 70 i 165 t = (time_t)intime->time; Err bitreich.org 70 i 166 if (!(intm = gmtime(&t))) Err bitreich.org 70 i 167 return; Err bitreich.org 70 i 168 strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm); Err bitreich.org 70 i 169 fputs(out, fp); Err bitreich.org 70 i 170 } Err bitreich.org 70 i 171 Err bitreich.org 70 i 172 void Err bitreich.org 70 i 173 writeheader(FILE *fp) Err bitreich.org 70 i 174 { Err bitreich.org 70 i 175 if (description[0]) { Err bitreich.org 70 i 176 if (description[0] == '[') Err bitreich.org 70 i 177 fputs("[|", fp); Err bitreich.org 70 i 178 gphtext(fp, description, strlen(description)); Err bitreich.org 70 i 179 fputs("\n\n", fp); Err bitreich.org 70 i 180 } Err bitreich.org 70 i 181 Err bitreich.org 70 i 182 fprintf(fp, "%-20.20s ", "Name"); Err bitreich.org 70 i 183 fprintf(fp, "%-39.39s ", "Description"); Err bitreich.org 70 i 184 fprintf(fp, "%s\n", "Last commit"); Err bitreich.org 70 i 185 } Err bitreich.org 70 i 186 Err bitreich.org 70 i 187 int Err bitreich.org 70 i 188 writelog(FILE *fp) Err bitreich.org 70 i 189 { Err bitreich.org 70 i 190 git_commit *commit = NULL; Err bitreich.org 70 i 191 const git_signature *author; Err bitreich.org 70 i 192 git_revwalk *w = NULL; Err bitreich.org 70 i 193 git_oid id; Err bitreich.org 70 i 194 char *stripped_name = NULL, *p; Err bitreich.org 70 i 195 char buf[1024]; Err bitreich.org 70 i 196 int ret = 0; Err bitreich.org 70 i 197 Err bitreich.org 70 i 198 git_revwalk_new(&w, repo); Err bitreich.org 70 i 199 git_revwalk_push_head(w); Err bitreich.org 70 i 200 Err bitreich.org 70 i 201 if (git_revwalk_next(&id, w) || Err bitreich.org 70 i 202 git_commit_lookup(&commit, repo, &id)) { Err bitreich.org 70 i 203 ret = -1; Err bitreich.org 70 i 204 goto err; Err bitreich.org 70 i 205 } Err bitreich.org 70 i 206 Err bitreich.org 70 i 207 author = git_commit_author(commit); Err bitreich.org 70 i 208 Err bitreich.org 70 i 209 /* strip .git suffix */ Err bitreich.org 70 i 210 if (!(stripped_name = strdup(name))) Err bitreich.org 70 i 211 err(1, "strdup"); Err bitreich.org 70 i 212 if ((p = strrchr(stripped_name, '.'))) Err bitreich.org 70 i 213 if (!strcmp(p, ".git")) Err bitreich.org 70 i 214 *p = '\0'; Err bitreich.org 70 i 215 Err bitreich.org 70 i 216 fputs("[1|", fp); Err bitreich.org 70 i 217 utf8pad(buf, sizeof(buf), stripped_name, 20, ' '); Err bitreich.org 70 i 218 gphlink(fp, buf, strlen(buf)); Err bitreich.org 70 i 219 fputs(" ", fp); Err bitreich.org 70 i 220 utf8pad(buf, sizeof(buf), description, 39, ' '); Err bitreich.org 70 i 221 gphlink(fp, buf, strlen(buf)); Err bitreich.org 70 i 222 fputs(" ", fp); Err bitreich.org 70 i 223 if (author) Err bitreich.org 70 i 224 printtimeshort(fp, &(author->when)); Err bitreich.org 70 i 225 fprintf(fp, "|%s/%s/log.gph|server|port]\n", relpath, stripped_name); Err bitreich.org 70 i 226 Err bitreich.org 70 i 227 git_commit_free(commit); Err bitreich.org 70 i 228 err: Err bitreich.org 70 i 229 git_revwalk_free(w); Err bitreich.org 70 i 230 free(stripped_name); Err bitreich.org 70 i 231 Err bitreich.org 70 i 232 return ret; Err bitreich.org 70 i 233 } Err bitreich.org 70 i 234 Err bitreich.org 70 i 235 void Err bitreich.org 70 i 236 usage(const char *argv0) Err bitreich.org 70 i 237 { Err bitreich.org 70 i 238 fprintf(stderr, "usage: %s [-b baseprefix] [repodir...]\n", argv0); Err bitreich.org 70 i 239 exit(1); Err bitreich.org 70 i 240 } Err bitreich.org 70 i 241 Err bitreich.org 70 i 242 int Err bitreich.org 70 i 243 main(int argc, char *argv[]) Err bitreich.org 70 i 244 { Err bitreich.org 70 i 245 FILE *fp; Err bitreich.org 70 i 246 char path[PATH_MAX], repodirabs[PATH_MAX + 1]; Err bitreich.org 70 i 247 const char *repodir = NULL; Err bitreich.org 70 i 248 int i, r, ret = 0; Err bitreich.org 70 i 249 Err bitreich.org 70 i 250 setlocale(LC_CTYPE, ""); Err bitreich.org 70 i 251 Err bitreich.org 70 i 252 /* do not search outside the git repository: Err bitreich.org 70 i 253 GIT_CONFIG_LEVEL_APP is the highest level currently */ Err bitreich.org 70 i 254 git_libgit2_init(); Err bitreich.org 70 i 255 for (i = 1; i <= GIT_CONFIG_LEVEL_APP; i++) Err bitreich.org 70 i 256 git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, i, ""); Err bitreich.org 70 i 257 /* do not require the git repository to be owned by the current user */ Err bitreich.org 70 i 258 git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 0); Err bitreich.org 70 i 259 Err bitreich.org 70 i 260 #ifdef __OpenBSD__ Err bitreich.org 70 i 261 if (pledge("stdio rpath", NULL) == -1) Err bitreich.org 70 i 262 err(1, "pledge"); Err bitreich.org 70 i 263 #endif Err bitreich.org 70 i 264 Err bitreich.org 70 i 265 for (i = 1, r = 0; i < argc; i++) { Err bitreich.org 70 i 266 if (argv[i][0] == '-') { Err bitreich.org 70 i 267 if (argv[i][1] != 'b' || i + 1 >= argc) Err bitreich.org 70 i 268 usage(argv[0]); Err bitreich.org 70 i 269 relpath = argv[++i]; Err bitreich.org 70 i 270 continue; Err bitreich.org 70 i 271 } Err bitreich.org 70 i 272 Err bitreich.org 70 i 273 if (r++ == 0) Err bitreich.org 70 i 274 writeheader(stdout); Err bitreich.org 70 i 275 Err bitreich.org 70 i 276 repodir = argv[i]; Err bitreich.org 70 i 277 if (!realpath(repodir, repodirabs)) Err bitreich.org 70 i 278 err(1, "realpath"); Err bitreich.org 70 i 279 Err bitreich.org 70 i 280 if (git_repository_open_ext(&repo, repodir, Err bitreich.org 70 i 281 GIT_REPOSITORY_OPEN_NO_SEARCH, NULL)) { Err bitreich.org 70 i 282 fprintf(stderr, "%s: cannot open repository\n", argv[0]); Err bitreich.org 70 i 283 ret = 1; Err bitreich.org 70 i 284 continue; Err bitreich.org 70 i 285 } Err bitreich.org 70 i 286 Err bitreich.org 70 i 287 /* use directory name as name */ Err bitreich.org 70 i 288 if ((name = strrchr(repodirabs, '/'))) Err bitreich.org 70 i 289 name++; Err bitreich.org 70 i 290 else Err bitreich.org 70 i 291 name = ""; Err bitreich.org 70 i 292 Err bitreich.org 70 i 293 /* read description or .git/description */ Err bitreich.org 70 i 294 joinpath(path, sizeof(path), repodir, "description"); Err bitreich.org 70 i 295 if (!(fp = fopen(path, "r"))) { Err bitreich.org 70 i 296 joinpath(path, sizeof(path), repodir, ".git/description"); Err bitreich.org 70 i 297 fp = fopen(path, "r"); Err bitreich.org 70 i 298 } Err bitreich.org 70 i 299 description[0] = '\0'; Err bitreich.org 70 i 300 if (fp) { Err bitreich.org 70 i 301 if (fgets(description, sizeof(description), fp)) Err bitreich.org 70 i 302 description[strcspn(description, "\t\r\n")] = '\0'; Err bitreich.org 70 i 303 else Err bitreich.org 70 i 304 description[0] = '\0'; Err bitreich.org 70 i 305 checkfileerror(fp, "description", 'r'); Err bitreich.org 70 i 306 fclose(fp); Err bitreich.org 70 i 307 } Err bitreich.org 70 i 308 Err bitreich.org 70 i 309 writelog(stdout); Err bitreich.org 70 i 310 } Err bitreich.org 70 i 311 if (!repodir) Err bitreich.org 70 i 312 usage(argv[0]); Err bitreich.org 70 i 313 Err bitreich.org 70 i 314 /* cleanup */ Err bitreich.org 70 i 315 git_repository_free(repo); Err bitreich.org 70 i 316 git_libgit2_shutdown(); Err bitreich.org 70 i 317 Err bitreich.org 70 i 318 checkfileerror(stdout, "", 'w'); Err bitreich.org 70 i 319 Err bitreich.org 70 i 320 return ret; Err bitreich.org 70 i 321 } Err bitreich.org 70 .