aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Pipping <sebastian@pipping.org>2010-10-11 17:20:11 +0200
committerSebastian Pipping <sebastian@pipping.org>2010-10-11 17:20:11 +0200
commitf3fee983dd082266cc932df5b248d1a9b1bdd41a (patch)
tree547d2b6c7e6fc1afed5854568d1a18a2f8331b02 /helpers.c
parentZero (diff)
downloadconf-update-f3fee983dd082266cc932df5b248d1a9b1bdd41a.tar.gz
conf-update-f3fee983dd082266cc932df5b248d1a9b1bdd41a.tar.bz2
conf-update-f3fee983dd082266cc932df5b248d1a9b1bdd41a.zip
Add code of conf-update 1.01.0
Diffstat (limited to 'helpers.c')
-rw-r--r--helpers.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/helpers.c b/helpers.c
new file mode 100644
index 0000000..a56e65d
--- /dev/null
+++ b/helpers.c
@@ -0,0 +1,461 @@
+#include "conf-update.h"
+
+char **get_listing(char *cmd, char *delim) {
+ FILE *pipe;
+ char *buf = NULL;
+ size_t bufsize = 0;
+ ssize_t read;
+ char **listing;
+ int count = 1, i = 0;
+ unsigned int j;
+ char c;
+
+ pipe = popen(cmd, "r");
+ if (pipe) {
+ read = getdelim(&buf, &bufsize, '\0', pipe);
+ char *buf_backup = buf;
+ if (read != -1) {
+ // determine number of tokens
+ while ((c = buf[i]) != '\0') {
+ for (j=0;j<strlen(delim);j++) {
+ if (c == delim[j]) {
+ count++;
+ }
+ }
+ i++;
+ }
+
+ listing = (char **) malloc(sizeof(char *) * count);
+ char *str;
+ i=0;
+ while ((str = strsep(&buf, delim))) {
+ listing[i] = strdup(str);
+ i++;
+ }
+ free(buf_backup);
+ // make sure the last one is always LAST_ENTRY
+ listing[count-1] = LAST_ENTRY;
+ pclose(pipe);
+ return listing;
+ } else {
+ pclose(pipe);
+ listing = (char **)malloc(sizeof(char *));
+ listing[0] = LAST_ENTRY;
+ free(buf_backup);
+ return listing;
+ }
+ } else {
+ exit_error(0, cmd);
+ }
+ // just for gcc, that bitch
+ return NULL;
+}
+
+int compare_updates(const void *a, const void *b) {
+ char *real_a;
+ char *real_b;
+ int result;
+ signed mod = 1;
+
+ if (is_valid_entry(*(char **)a)) {
+ real_a = get_real_filename(*(char **)a);
+ } else {
+ real_a = NULL;
+ }
+ if (is_valid_entry(*(char **)b)) {
+ real_b = get_real_filename(*(char **)b);
+ } else {
+ real_b = NULL;
+ }
+
+ if (!real_a && !real_b) {
+ result = -1;
+ } else if (!real_a) {
+ result = 1;
+ } else if (!real_b) {
+ result = -1;
+ } else {
+ // both valid updates
+ if ((result = strcmp(real_a, real_b)) == 0) {
+ // same target
+ if ((result = strncmp(strstr(*(char **)a, "._cfg"), strstr(*(char **)b, "._cfg"), strlen("._cfg????"))) == 0) {
+ // same update number. interactively merged vs. predefined, 1:0 for the user.
+ mod = -1;
+ }
+ result = mod * strcmp(*(char **)a, *(char **)b);
+ }
+ }
+
+ free(real_a);
+ free(real_b);
+
+ return result;
+}
+
+struct node *fold_updates(char **list) {
+ struct node *root = malloc(sizeof(struct node));
+ struct node *mynode, *newnode;
+ char *endtok, *curtok;
+ int i;
+ int run;
+
+ root->name = strdup("/");
+ root->children = malloc(sizeof(struct node *));
+ root->ct_children = 0;
+ root->parent = NULL;
+ root->dir = TRUE;
+ root->link = NULL;
+
+ for (i=0;!is_last_entry(list[i]);i++) {
+ if (is_valid_entry(list[i])) {
+ endtok = list[i]+1;
+ run = 1;
+ while (run) {
+ if (run == 2) {
+ // 2 means we're on the last run
+ run = 0;
+ endtok = list[i] + strlen(list[i]) + 1;
+ } else {
+ if ((endtok = strchr(endtok+1, '/')) == NULL) {
+ run = 2;
+ }
+ }
+ curtok = strndup(list[i], endtok - list[i]);
+
+ mynode = find_node(root, curtok);
+ if (mynode == (struct node *)FALSE) {
+ mynode = root;
+ }
+ if (mynode != (struct node *)TRUE) {
+ // mynode is the parent of the new to be inserted node
+ newnode = malloc(sizeof(struct node));
+ newnode->name = strdup(curtok);
+ if (!strcmp(curtok,list[i])) {
+ // it's the file
+ newnode->dir = FALSE;
+ newnode->link = &list[i];
+ } else {
+ newnode->name = strdup(curtok);
+ newnode->dir = TRUE;
+ newnode->link = NULL;
+ }
+ newnode->children = malloc(sizeof(struct node *));
+ newnode->ct_children = 0;
+ newnode->parent = mynode;
+
+ mynode->ct_children++;
+ mynode->children = realloc(mynode->children, sizeof(struct node *) * mynode->ct_children);
+ mynode->children[mynode->ct_children-1] = newnode;
+ }
+
+ free(curtok);
+ }
+ }
+ }
+
+ return root;
+
+}
+
+struct node *find_node(struct node *root, char *path) {
+ int i;
+ struct node *mynode;
+
+ if (!strcmp(root->name, path)) {
+ // already exists
+ return (struct node *)TRUE;
+ } else if (!strncmp(root->name, path, strlen(root->name)) && root->dir == TRUE) {
+ // at least it's in the same direction, go through the list of children
+ for (i=0;i<root->ct_children;i++) {
+ mynode = find_node(root->children[i], path);
+ if (mynode == (struct node *)TRUE) {
+ return (struct node *)TRUE;
+ } else if (mynode != (struct node *)FALSE) {
+ return mynode;
+ }
+ }
+ // if we hit this point, nothing was found, meaning that it has to be a child of the current node
+ return root;
+ } else {
+ // completely wrong
+ return (struct node *)FALSE;
+ }
+}
+void sanity_checks() {
+ extern struct configuration config;
+ unsigned int i;
+ FILE *pipe;
+ char *cmd = NULL;
+ char *tools[] = {
+ "diff",
+ "portageq",
+ strndup(config.pager, strchrnul(config.pager, ' ') - config.pager),
+ strndup(config.diff_tool, strchrnul(config.diff_tool, ' ') - config.diff_tool),
+ strndup(config.merge_tool, strchrnul(config.merge_tool, ' ') - config.merge_tool),
+ strndup(config.edit_tool, strchrnul(config.edit_tool, ' ') - config.edit_tool)
+ };
+
+ if (getuid() != 0) {
+ fprintf(stderr, "!!! Oops, you're not root!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i=0;i<sizeof(tools)/sizeof(tools[0]);i++) {
+ // "" is okay for pager
+ if (strcmp(tools[i], "")) {
+ if (!g_find_program_in_path((gchar *)tools[i])) {
+ fprintf(stderr, "!!! ERROR: couldn't find necesary tool: %s\n", tools[i]);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ free(cmd);
+
+ mkdir (MD5SUM_INDEX_DIR, 0755);
+ if ((pipe = fopen(MD5SUM_INDEX, "a"))) {
+ fclose(pipe);
+ } else {
+ fprintf(stderr, "!!! ERROR: Can't write to %s; check permissions", MD5SUM_INDEX);
+ exit(EXIT_FAILURE);
+ }
+}
+
+void draw_legend(WINDOW *inner) {
+ int i;
+
+ wattron(inner, COLOR_PAIR(2));
+ wattron(inner, A_BOLD);
+ box(inner, 0, 0);
+ for (i=1;i<LINES-5;i++) {
+ mvwhline(inner, i, 1, ' ', COLS-6);
+ }
+
+ wattroff(inner, A_BOLD);
+ wattron(inner, COLOR_PAIR(3));
+ mvwprintw(inner, 1, 2, "Select current: !!!!!!! | !!!ll | !!!nselect all");
+ mvwprintw(inner, 2, 2, "Show diff: !!!!!!! | !!!dit update | !!!erge interactively");
+ mvwprintw(inner, 3, 2, "Actions for all selected: !!!eplace config file(s) | !!!elete update(s)"); // | merge !!!nteractively");
+ mvwprintw(inner, 4, 2, "Quit: !!!");
+
+ wattron(inner, COLOR_PAIR(4));
+ mvwprintw(inner, 1, 2 + strlen("Select current: "), "[SPACE]");
+ mvwprintw(inner, 1, 2 + strlen("Select current: !!!!!!! | "), "[A]");
+ mvwprintw(inner, 1, 2 + strlen("Select current: !!!!!!! | !!!ll | "), "[U]");
+
+ mvwprintw(inner, 2, 2 + strlen("Show diff: "), "[ENTER]");
+ mvwprintw(inner, 2, 2 + strlen("Show diff: !!!!!!! | "), "[E]");
+ mvwprintw(inner, 2, 2 + strlen("Show diff: !!!!!!! | !!!dit update | "), "[M]");
+
+ mvwprintw(inner, 3, 2 + strlen("Actions for all selected: "), "[R]");
+ mvwprintw(inner, 3, 2 + strlen("Actions for all selected: !!!eplace config file(s) | "), "[D]");
+ //mvwprintw(inner, 3, 2 + strlen("Action shortcuts: !!!erge | !!!elete update | merge "), "[I]");
+
+ mvwprintw(inner, 4, 2 + strlen("Quit: "), "[Q]");
+
+ wattron(inner, COLOR_PAIR(2) | A_BOLD);
+ // TODO: replace COLS - 4/LINES - 7 with a function to determine size of inner
+ mvwhline(inner, 5, 1, 0, COLS - 4 -2);
+ mvwhline(inner, LINES - 7, 1, 0, COLS - 4 -2);
+
+ wrefresh(inner);
+}
+
+void draw_background() {
+ int i;
+
+ attron(A_BOLD);
+ attron(COLOR_PAIR(1));
+ // why does clear() not work here?
+ for (i=0;i<LINES;i++) {
+ mvhline(i, 0, ' ', COLS);
+ }
+ attron(COLOR_PAIR(5));
+ mvhline(LINES-2, 3, ' ', COLS-4);
+ mvvline(3, COLS-2, ' ', LINES-4);
+ attron(COLOR_PAIR(1));
+ mvprintw(0,1, PROG_NAME);
+ mvprintw(0,strlen(PROG_NAME) + 2, PROG_VERSION);
+ mvhline(1, 1, ACS_HLINE, COLS - 2);
+
+ refresh();
+}
+
+char *get_indent_name(struct node *update, int width) {
+ int ct_indents = 0;
+ struct node *mynode = update;
+ char *start, *name;
+ char *indent_name;
+ char number[] = "0000";
+ int num, remainder, i;
+
+ while ((mynode = mynode->parent)) {
+ ct_indents++;
+ }
+ indent_name = calloc(width + 1, sizeof(char));
+ if ((start = strstr(update->name, "._cfg"))) {
+ name = start+strlen("._cfg????_");
+ while (ct_indents > 0) {
+ strcat(indent_name, INDENT_STR);
+ ct_indents--;
+ }
+ strcat(indent_name, name);
+ strcat(indent_name, " (");
+ strncpy(number, start+strlen("._cfg"), 4);
+ num = atoi(number) + 1;
+ snprintf(indent_name + strlen(indent_name), 4, "%d", num);
+ strcat(indent_name, ")");
+ if (*(name - 1) == '-') {
+ strcat(indent_name, "(merged)");
+ }
+ } else {
+ start = strrchr(update->name, '/') + 1;
+ while (ct_indents > 0) {
+ strcat(indent_name, INDENT_STR);
+ ct_indents--;
+ }
+ strcat(indent_name, start);
+ strcat(indent_name, "/");
+ }
+ remainder = width - strlen(indent_name);
+ for(i=0;i<remainder;i++) {
+ strcat(indent_name, " ");
+ }
+
+ return indent_name;
+}
+int count_array_items(struct node *root) {
+ int count = 0, i;
+
+ for (i=0;i<root->ct_children;i++) {
+ count += count_array_items(root->children[i]);
+ }
+ return 1 + count;
+}
+
+void build_item_array(ITEM **item_array, struct node *root, int menu_width) {
+ int i = 0;
+
+ // fast-forward to the next NULL entry
+ while (item_array[i]) {
+ i++;
+ }
+ item_array[i] = new_item(get_indent_name(root, menu_width), "");
+ set_item_userptr(item_array[i], root->link);
+
+ for (i=0;i<root->ct_children;i++) {
+ build_item_array(item_array, root->children[i], menu_width);
+ }
+}
+void free_folded(struct node *root) {
+ int i;
+
+ for (i=0;i<root->ct_children;i++) {
+ free_folded(root->children[i]);
+ }
+ if (root->dir) {
+ free(root->name);
+ }
+ free(root->children);
+ free(root);
+}
+
+bool get_confirmation(WINDOW *win, char *action) {
+ bool result;
+ echo();
+ nocbreak();
+ char ret[2] = " ";
+ wattron(win, COLOR_PAIR(4));
+ wattroff(win, A_BOLD);
+ // TODO: replace COLS - 4/LINES - 7 with a function to determine size of inner
+ mvwprintw(win, LINES - 6, 2, "Do you really want to ");
+ wprintw(win, action);
+ wprintw(win, " all selected updates? [y/n] ");
+ refresh();
+ wgetnstr(win, ret, 1);
+ if (!strcmp(ret,"y")) {
+ result = true;
+ } else {
+ result = false;
+ }
+ mvwhline(win, LINES - 6, 1, ' ', COLS - 4 -2);
+ noecho();
+ cbreak();
+ return result;
+}
+void exit_error(bool expr, char *hint) {
+ if (!expr) {
+ endwin();
+ char *mystring = calloc(sizeof(char), strlen("!!! ERROR: ") + strlen(hint) + 1);
+ sprintf(mystring, "!!! ERROR: %s", hint);
+ perror(mystring);
+ exit(EXIT_FAILURE);
+ }
+}
+
+char **get_files_list(char *searchpath, char **index, int *max) {
+ struct stat mystat, tmpstat;
+ int i = 0, j;
+ DIR *dirfd;
+ struct dirent *file = (struct dirent *)TRUE;
+ char *absfile;
+ char *myfile;
+ bool ignore;
+
+ lstat(searchpath, &mystat);
+ if (S_ISDIR(mystat.st_mode)) {
+ dirfd = opendir(searchpath);
+ if (dirfd) {
+ while (file) {
+ file = readdir(dirfd);
+ if (file && strcmp(file->d_name, ".") && strcmp(file->d_name, "..") && \
+ strcmp(file->d_name, ".svn") && strcmp(file->d_name, "CVS")) {
+ absfile = (char *)calloc((strlen(searchpath) + strlen("/") + strlen(file->d_name) + 1), sizeof(char *));
+ strcpy(absfile, searchpath);
+ strcat(absfile, "/");
+ strcat(absfile, file->d_name);
+ index = get_files_list(absfile, index, max);
+ free(absfile);
+ }
+ }
+ } else if (errno == ENOENT) {
+ return index;
+ } else {
+ exit_error(0, searchpath);
+ }
+ closedir(dirfd);
+ } else if (S_ISREG(mystat.st_mode)) {
+ if (!strncmp(strrchr(searchpath, '/')+1, "._cfg", strlen("._cfg"))) {
+ if (*(searchpath+strlen(searchpath)-1) != '~' && \
+ strcmp(searchpath+strlen(searchpath)-4,".bak")) {
+ myfile = get_real_filename(searchpath);
+ if (access(myfile, F_OK) != 0) {
+ // we don't want phantom updates
+ unlink(searchpath);
+ } else {
+ // we don't want duplicates either
+ ignore = FALSE;
+ for (j=0;j<(*max);j++) {
+ lstat(index[j], &tmpstat);
+ if (tmpstat.st_dev == mystat.st_dev && \
+ tmpstat.st_ino == mystat.st_ino) {
+ ignore = TRUE;
+ }
+ }
+ if (!ignore) {
+ while (i < (*max) && !is_last_entry(index[i])) {
+ i++;
+ }
+ if (i + 1 >= (*max)) {
+ (*max)++;
+ index = (char **)realloc(index, (*max) * sizeof(char *));
+ }
+ index[i] = strdup(searchpath);
+ index[i+1] = LAST_ENTRY;
+ }
+ }
+ free(myfile);
+ }
+ }
+ }
+ return index;
+}