diff options
Diffstat (limited to 'CC/include_scan.c')
-rw-r--r-- | CC/include_scan.c | 449 |
1 files changed, 0 insertions, 449 deletions
diff --git a/CC/include_scan.c b/CC/include_scan.c deleted file mode 100644 index 8652fc0..0000000 --- a/CC/include_scan.c +++ /dev/null @@ -1,449 +0,0 @@ -/* Copyright 2024 Huawei Cloud Computing Technology Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Include scanner - * Parse file paths from command's space-separated stdout, select those that - * start with "include/", and copy them to the user-defined output directory. - * - * Usage: - * include_scan OUT_DIR ARGV... - * - * Example: - * ./include_scan out gcc -isystem include foo.c -E -M - * -> Generates output directory "out/include" from gcc's output - */ - -#include <assert.h> -#include <errno.h> -#include <error.h> -#include <fcntl.h> -#include <libgen.h> /* dirname */ -#include <linux/limits.h> /* PATH_MAX */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> /* mkdir */ -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#define READ_SIZE PATH_MAX /* support up to PATH_MAX path lengths */ -#define LIST_SIZE 1024 /* initial capacity of include list */ - -/* Buffer that can load in chunks, while maintaining previously unread data */ -struct ShiftBuffer { - char *pos; /* position in full buffer */ - char *start; /* start of buffer's second half */ - size_t size; /* size of data in buffer's second half */ - char buffer[READ_SIZE * 2 + 1]; -}; - -/* List of includes that dynamically resizes */ -struct IncludeList { - char **pos; /* position for reading */ - size_t size; /* number of list entries */ - size_t capacity; /* maximum capacity */ - char **list; -}; - -int helper_mkdir_p(char *path, mode_t mode); -int helper_pathcmp(const void *a, const void *b); -void helper_normpath(char *out_path, const char *in_path, size_t len); -int helper_copyfile(const char *from, const char *to, int wopen_mayfail); - -/* ShiftBuffer functions */ -void sbuf_init(struct ShiftBuffer *sbuf); -void sbuf_addpos(struct ShiftBuffer *sbuf, size_t offset); -char *sbuf_pos(struct ShiftBuffer *sbuf); -char *sbuf_end(struct ShiftBuffer *sbuf); -int sbuf_eof(struct ShiftBuffer *sbuf); -int sbuf_load(struct ShiftBuffer *sbuf, int fd); -int sbuf_shift(struct ShiftBuffer *sbuf); - -/* IncludeList functions */ -void incl_init(struct IncludeList *incl); -void incl_free(struct IncludeList *incl); -void incl_resize(struct IncludeList *incl, size_t new_cap); -void incl_append(struct IncludeList *incl, char *path); -void incl_setpos(struct IncludeList *incl, size_t pos); -char *incl_next(struct IncludeList *incl); - -/* Parse paths from fd's space-separated string, select those that start with - * pattern, and return normalized and deduplicated list. - */ -void parse_paths(struct IncludeList *incl, int fd, char const *pattern, - char const *prefix); - -int main(int argc, const char *argv[]) { - int fd[2]; - pid_t pid; - int status = 0; - int retval = 0; - char *path = NULL; - char *prefix; - char *outdir; - size_t prefix_len = 0; - size_t outdir_len = 0; - struct IncludeList incl; - - if (argc < 3) { - fprintf(stderr, "usage: %s OUT_DIR ARGV...\n", argv[0]); - fprintf(stderr, "Missing arguments\n"); - exit(EXIT_FAILURE); - } - if (pipe(fd) < 0) { - fprintf(stderr, "Failed to create pipe\n"); - return 1; - } - pid = fork(); - if (-1 == pid) { - fprintf(stderr, "Failed to fork process\n"); - return 1; - } - - if (pid == 0) { /* exec in child */ - dup2(fd[1], STDOUT_FILENO); - close(fd[1]); - close(fd[0]); - execvp(argv[2], (char *const *)(argv + 2)); - exit(EXIT_FAILURE); - } - - close(fd[1]); - - /* obtain include list from paths starting with "include/" */ - incl_init(&incl); - prefix_len = strlen(argv[1]); - prefix = (char *)calloc(prefix_len + 2, sizeof(char)); - strcat(prefix, argv[1]); - strcat(prefix + prefix_len, "/"); - prefix_len += 1; - parse_paths(&incl, fd[0], "include/", prefix); - close(fd[0]); - - /* create output directory "<prefix>/include" */ - outdir_len = prefix_len + 8 /* strlen("include/") */; - outdir = (char *)calloc(outdir_len + 1, sizeof(char)); - strcat(outdir, prefix); - strcat(outdir + prefix_len, "include/"); - if (helper_mkdir_p(outdir, 0755) != 0) { - fprintf(stderr, "Failed to create output directory\n"); - return 1; - } - free(prefix); - free(outdir); - - /* wait for child to finish */ - while (1) { - if (waitpid(pid, &status, 0) == -1) { - fprintf(stderr, "Waiting for child failed with: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - if (WIFEXITED(status)) { - retval = WEXITSTATUS(status); - break; - } else if (WIFSIGNALED(status)) { - const int kSignalBit = 128; - int sig = WTERMSIG(status); - retval = kSignalBit + sig; - fprintf(stderr, "Child got killed by signal %d\n", sig); - break; - } - } - - if (retval != 0) { - fprintf(stderr, "Include scanner received non-zero exit code from child\n"); - exit(EXIT_FAILURE); - } - - /* copy files from unprefixed path */ - incl_setpos(&incl, 0); - while ((path = incl_next(&incl)) != NULL) { - char *const to = path; - char *const from = to + prefix_len; - if (!helper_copyfile(from, to, /*wopen_mayfail=*/1)) { - if (helper_mkdir_p(to, 0755) != 0) { - fprintf(stderr, "mkdir failed: %s\n", to); - exit(EXIT_FAILURE); - } - if (!helper_copyfile(from, to, /*wopen_mayfail=*/0)) { - fprintf(stderr, "copy failed: %s\n", to); - exit(EXIT_FAILURE); - } - } - } - - incl_free(&incl); - - return 0; -} - -void parse_paths(struct IncludeList *incl, int fd, char const *pattern, - char const *prefix) { - size_t path_len; - size_t prefix_len = strlen(prefix); - size_t pattern_len = strlen(pattern); - - struct ShiftBuffer sbuf; - sbuf_init(&sbuf); - - while (sbuf_load(&sbuf, fd) || !sbuf_eof(&sbuf)) { - do { - char *pos = sbuf_pos(&sbuf); - char *end = strchr(pos, ' '); - if (end == NULL) { /* not found */ - if (!sbuf_shift(&sbuf)) { - fprintf(stderr, "File path too long for buffer\n"); - exit(EXIT_FAILURE); - } - break; /* read next chunk in sbuf */ - } - - if (end >= sbuf_end(&sbuf)) { /* eof */ - end = sbuf_end(&sbuf) - 1; - } - - /* match prefix */ - path_len = (size_t)end - (size_t)pos; - if (path_len >= pattern_len && strncmp(pattern, pos, pattern_len) == 0) { - size_t new_len = prefix_len + path_len + 1; - char *new_path = (char *)calloc(new_len, sizeof(char)); - strcat(new_path, prefix); - helper_normpath(new_path + prefix_len, pos, path_len); - new_path[new_len - 1] = '\0'; - incl_append(incl, new_path); - } - sbuf_addpos(&sbuf, path_len + 1); - } while (!sbuf_eof(&sbuf)); - } - - /* deduplicate */ - if (incl->size > 1) { - size_t cmp_pos = 0; - size_t next_pos = 1; - if (incl->size > 2) { - qsort(incl->list, incl->size, sizeof(char *), helper_pathcmp); - } - /* uniq */ - for (; next_pos < incl->size; ++next_pos) { - if (strcmp(incl->list[cmp_pos], incl->list[next_pos]) != 0) { - cmp_pos = next_pos; - } else { /* remove duplicate */ - free(incl->list[next_pos]); - incl->list[next_pos] = NULL; - } - } - incl->size = cmp_pos + 1; - } -} - -int helper_mkdir_p(char *path, mode_t mode) { - char *p = path; - while ((p = strchr(p + 1, '/'))) { - int ret; - *p = '\0'; - ret = mkdir(path, mode); - *p = '/'; - if (ret == -1 && errno != EEXIST) - return -1; - } - return 0; -} - -int helper_pathcmp(const void *a, const void *b) { - return strcmp(*(const char **)a, *(const char **)b); -} - -void helper_normpath(char *out_path, const char *in_path, size_t len) { - char *out_pos = out_path; - const char *in_pos = in_path; - - while (in_pos < in_path + len) { - size_t seg_len; - const char *seg_end = strchr(in_pos, '/'); - if (seg_end == NULL || seg_end > in_path + len - 1) { - seg_end = in_path + len - 1; /* last valid char */ - } - seg_len = (size_t)seg_end - (size_t)in_pos + 1; - if (seg_len == 2 && strncmp(in_pos, "./", 2) == 0) { - in_pos += 2; - } else if (seg_len == 3 && strncmp(in_pos, "../", 3) == 0) { - in_pos += 3; - if (out_pos > out_path) { - *(out_pos - 1) = '\0'; - out_pos = strrchr(out_path, '/') + 1; - } else { - out_pos = NULL; - } - if (out_pos == NULL) { - fprintf(stderr, "Cannot normalize upwards path %s\n", in_path); - exit(EXIT_FAILURE); - } - } else { - assert(out_pos + seg_len <= out_path + len); - strncpy(out_pos, in_pos, seg_len); - out_pos += seg_len; - in_pos += seg_len; - } - } -} - -int helper_copyfile(const char *from, const char *to, int wopen_mayfail) { - FILE *in, *out; - char buf[READ_SIZE] = {'\0'}; - size_t size; - - out = fopen(to, "w"); - if (out == NULL) { - if (errno == EEXIST) { - return 1; /* ok */ - } - if (!wopen_mayfail) { - fprintf(stderr, "Cannot open output file for writing %s\n", to); - } - return 0; - } - - in = fopen(from, "r"); - if (in == NULL) { - fclose(out); - fprintf(stderr, "Cannot open input file for reading %s\n", from); - return 0; - } - - while ((size = fread(buf, sizeof(*buf), sizeof(buf), in)) > 0) { - if (size != fwrite(buf, sizeof(*buf), size, out)) { - fclose(in); - fclose(out); - fprintf(stderr, "Failed writing output file %s\n", to); - return 0; - } - } - - if (!feof(in)) { - fclose(in); - fclose(out); - fprintf(stderr, "Failed reading input file %s\n", from); - return 0; - } - - fclose(in); - fclose(out); - - return 1; -} - -void sbuf_init(struct ShiftBuffer *sbuf) { - memset(sbuf->buffer, '\0', sizeof(sbuf->buffer)); - sbuf->start = sbuf->buffer + READ_SIZE; - sbuf->pos = sbuf->start; - sbuf->size = 0; -} - -void sbuf_addpos(struct ShiftBuffer *sbuf, size_t offset) { - sbuf->pos += offset; -} - -char *sbuf_pos(struct ShiftBuffer *sbuf) { return sbuf->pos; } - -char *sbuf_end(struct ShiftBuffer *sbuf) { return sbuf->start + sbuf->size; } - -int sbuf_eof(struct ShiftBuffer *sbuf) { return sbuf->pos >= sbuf_end(sbuf); } - -int sbuf_load(struct ShiftBuffer *sbuf, int fd) { - int buf_size = 0; - int read_size = 0; - char *buf_pos = sbuf->start; - if (sbuf->pos >= sbuf_end(sbuf)) { - sbuf->pos = sbuf->start; - } - assert(sbuf->pos <= sbuf->start); - do { - read_size = read(fd, buf_pos, READ_SIZE - buf_size); - if (read_size < 0) { - fprintf(stderr, "read fd failed\n"); - exit(EXIT_FAILURE); - } - buf_size += read_size; - buf_pos += read_size; - } while (buf_size < READ_SIZE && read_size != 0); - sbuf->size = buf_size; - if (read_size == 0) { /* finished, insert space to mark end of data */ - *(sbuf->start + sbuf->size) = ' '; - } - return buf_size; -} - -int sbuf_shift(struct ShiftBuffer *sbuf) { - if (!sbuf_eof(sbuf) && sbuf->pos >= sbuf->start) { - size_t size = (size_t)sbuf_end(sbuf) - (size_t)sbuf->pos; - char *new_pos = sbuf->start - size; - strncpy(new_pos, sbuf->pos, size); - sbuf->pos = new_pos; - return 1; - } - return 0; /* cannot shift, still valid data in buffer's first half */ -} - -void incl_init(struct IncludeList *incl) { - incl->list = (char **)calloc(LIST_SIZE + 1, sizeof(char *)); - incl->pos = incl->list; - incl->size = 0; - incl->capacity = LIST_SIZE; -} - -void incl_free(struct IncludeList *incl) { - char *path = NULL; - incl_setpos(incl, 0); - while ((path = incl_next(incl)) != NULL) { - free(path); - } - free(incl->list); -} - -void incl_resize(struct IncludeList *incl, size_t new_cap) { - char **new_list = (char **)calloc(new_cap + 1, sizeof(char *)); - assert(new_cap > incl->capacity); - memcpy(new_list, incl->list, sizeof(*incl->list) * incl->capacity); - incl_free(incl); - incl->list = new_list; - incl->capacity = new_cap; -} - -void incl_append(struct IncludeList *incl, char *path) { - if (incl->size == incl->capacity) { - incl_resize(incl, incl->capacity * 2); - } - incl->list[incl->size++] = path; -} - -void incl_setpos(struct IncludeList *incl, size_t pos) { - assert(pos <= incl->size); - incl->pos = incl->list + pos; -} - -char *incl_next(struct IncludeList *incl) { - char **pos = incl->pos; - char **end = incl->list + incl->size; - assert(pos <= end); - while (pos < end) { - pos = incl->pos++; - if (*pos != NULL) { - return *pos; - } - } - return NULL; -} |