#include #include #include #include #include #include #include #include static int exitstatus = 0; static char *path = NULL; static size_t pathsize = 0; static size_t pathlen = 0; static char *buf = NULL; static size_t bufsize = 0; static void pushname(const char *name, size_t *old_len_out) { size_t len = pathlen + strlen(name) + 1; if (pathsize < len + 1) { pathsize = len + 1; path = realloc(path, pathsize); if (!path) { perror("find-errors"); exit(1); } } *old_len_out = pathlen; pathlen = (size_t)(stpcpy(pathlen ? stpcpy(&path[pathlen], "/") : path, name) - path); } static void popname(size_t old_len) { pathlen = old_len; path[pathlen] = '\0'; } static void checkfile(const char *name) { size_t old; int fd; size_t len = 0; ssize_t r; size_t off; size_t i; pushname(name, &old); fd = open(path, O_RDONLY); if (fd < 0) { fprintf(stderr, "find-errors: open %s O_RDONLY: %s\n", path, strerror(errno)); exit(1); } for (;;) { if (len == bufsize) { bufsize += 1024; buf = realloc(buf, bufsize); if (!buf) { perror("find-errors"); exit(1); } } r = read(fd, &buf[len], bufsize - len); if (r <= 0) { if (!r) break; fprintf(stderr, "find-errors: read %s: %s\n", path, strerror(errno)); exit(1); } len += (size_t)r; } close(fd); if (len < 7) goto out; for (off = 0; off < len - 6; off++) { if (buf[off] != '#') continue; for (i = 1; i <= 6; i++) { if ('A' <= buf[off + i] && buf[off + i] <= 'F') buf[off + i] ^= 'A' ^ 'a'; else if (!(('a' <= buf[off + i] && buf[off + i] <= 'f') || ('0' <= buf[off + i] && buf[off + i] <= '9'))) goto next; } if (!strncmp(&buf[off + 1], "bebebe", 6) || !strncmp(&buf[off + 1], "ef2929", 6) || !strncmp(&buf[off + 1], "f57900", 6) || !strncmp(&buf[off + 1], "32a678", 6) || !strncmp(&buf[off + 1], "cd656c", 6) || !strncmp(&buf[off + 1], "d69553", 6) || !strncmp(&buf[off + 1], "ccad47", 6) || !strncmp(&buf[off + 1], "32a679", 6) || !strncmp(&buf[off + 1], "00a09f", 6) || !strncmp(&buf[off + 1], "2495be", 6) || !strncmp(&buf[off + 1], "a46eb0", 6) || !strncmp(&buf[off + 1], "000000", 6)) continue; fprintf(stderr, "%s uses colour not defined in theme: %.7s\n", path, &buf[off]); exitstatus = 1; next:; } out: popname(old); } static void checkdir(const char *name) { size_t old; DIR *dir; static size_t old2; static struct dirent *f; static struct stat st; pushname(name, &old); dir = opendir(path); if (!dir) { fprintf(stderr, "find-errors: opendir %s: %s\n", path, strerror(errno)); exit(1); } errno = 0; while ((f = readdir(dir))) { if (f->d_name[0] == '.') continue; if (f->d_type == DT_DIR) { goto dir; } else if (f->d_type == DT_REG) { goto reg; } else if (f->d_type == DT_UNKNOWN) { pushname(f->d_name, &old2); if (lstat(path, &st)) { fprintf(stderr, "find-errors: lstat %s: %s\n", path, strerror(errno)); exit(1); } popname(old2); if (S_ISDIR(st.st_mode)) { dir: checkdir(f->d_name); } else if (S_ISREG(st.st_mode)) { reg: if (strlen(f->d_name) > 4 && !memcmp(&f->d_name[strlen(f->d_name) - 4], ".svg", 4)) checkfile(f->d_name); } } } if (errno) { fprintf(stderr, "find-errors: readdir %s: %s\n", path, strerror(errno)); exit(1); } closedir(dir); popname(old); } int main(void) { checkdir("scalable"); free(path); free(buf); return exitstatus; }