cmd-cat.c (4238B)
1 /* 2 * Copyright (c) 2014 Mohamed Aslan <maslan@sce.carleton.ca> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <stdio.h> /* printf(3) */ 18 #include <stdlib.h> /* EXIT_SUCCESS */ 19 #include <string.h> /* strdup(3) */ 20 #include <sys/stat.h> /* S_ISDIR */ 21 #include <unistd.h> /* getopt(3) */ 22 #include <err.h> /* errx(3) */ 23 24 #include "cmd.h" 25 #include "session.h" 26 27 #include "objects.h" 28 29 30 static struct dirent* 31 lookup(struct dir *dir, const char *name) 32 { 33 struct dirent *ent; 34 35 ent = dir->children; 36 while (ent != NULL) { 37 if (!strcmp(ent->name, name)) 38 return ent; 39 ent = ent->next; 40 } 41 return NULL; 42 } 43 44 int 45 cmd_cat(int argc, char **argv) 46 { 47 char *comm_id = NULL, *path; 48 char *id = NULL, *p1, *p2; 49 char buf[1024]; 50 int ch, n; 51 struct session s; 52 struct commit *comm; 53 struct dir *dir; 54 struct dirent *ent; 55 struct file *file; 56 57 baseline_session_begin(&s, 0); 58 59 /* parse command line options */ 60 while ((ch = getopt(argc, argv, "c:")) != -1) { 61 switch(ch) { 62 case 'c': 63 comm_id = strdup(optarg); 64 break; 65 default: 66 return EXIT_FAILURE; 67 } 68 } 69 argc -= optind; 70 argv += optind; 71 72 if (argc == 0) 73 errx(EXIT_FAILURE, "error, no file is specified."); 74 if (argc > 1) 75 errx(EXIT_FAILURE, "error, incorrect number of arguments specified."); 76 77 /* no commit specified, use current branch head */ 78 if (comm_id == NULL) { 79 if (s.db_ops->branch_get_head(s.db_ctx, s.branch, &comm_id) == EXIT_FAILURE) 80 errx(EXIT_FAILURE, "error, branch \'%s\' was not found.", s.branch); 81 if (comm_id == NULL) 82 errx(EXIT_FAILURE, "error, branch \'%s\' has zero commits.", s.branch); 83 } 84 85 path = strdup(argv[0]); 86 87 comm = baseline_commit_new(); 88 if (s.db_ops->select_commit(s.db_ctx, comm_id, comm) == EXIT_FAILURE) 89 errx(EXIT_FAILURE, "error, commit \'%s\' was not found.", comm_id); 90 91 dir = baseline_dir_new(); 92 s.db_ops->select_dir(s.db_ctx, comm->dir, dir); 93 94 p1 = p2 = path; 95 while (1) { 96 /* skip leading '/' */ 97 if (*p1 == '/') { 98 p1++; 99 p2++; 100 continue; 101 } 102 if (*p2 == '/') { 103 /* should be a directory */ 104 *p2 = '\0'; 105 #ifdef DEBUG 106 printf("[DEBUG] looking up directory \'%s\'.\n", p1); 107 #endif 108 if ((ent = lookup(dir, p1)) == NULL) 109 errx(EXIT_FAILURE, "error, no such a file or directory \'%s\'.", argv[0]); 110 if (!S_ISDIR(ent->mode)) 111 errx(EXIT_FAILURE, "error, \'%s\' is not a directory.", p1); 112 free(id); 113 id = strdup(ent->id); 114 115 baseline_dir_free(dir); 116 dir = baseline_dir_new(); 117 s.db_ops->select_dir(s.db_ctx, id, dir); 118 119 p1 = ++p2; 120 p2 = p1; 121 } 122 else if (*p2 == '\0') { 123 /* found a directory (ending with '/', skipped by above code) */ 124 if (p1 == p2) 125 errx(EXIT_FAILURE, "error, to list directories use \'ls\' command instead."); 126 /* should be a file */ 127 #ifdef DEBUG 128 printf("[DEBUG] lookuping up file \'%s\'\n", p1); 129 #endif 130 if ((ent = lookup(dir, p1)) == NULL) 131 errx(EXIT_FAILURE, "error, no such a file or directory \'%s\'.", argv[0]); 132 if (S_ISDIR(ent->mode)) 133 errx(EXIT_FAILURE, "error, \'%s\' is a directory, to list directories use \'ls\' command instead.", p1); 134 135 file = baseline_file_new(); 136 s.db_ops->select_file(s.db_ctx, ent->id, file); 137 #ifdef DEBUG 138 printf("[DEBUG] file found with id \'%s\'.\n", file->id); 139 #endif 140 break; 141 } 142 else { 143 p2++; 144 } 145 } 146 147 /* output file to stdout */ 148 while ((n = read(file->fd, buf, sizeof(buf))) > 0) { 149 write(1, buf, n); 150 } 151 if (n == -1) 152 errx(EXIT_FAILURE, "error, failed to read file."); 153 close(file->fd); 154 155 free(path); 156 baseline_dir_free(dir); 157 baseline_file_free(file); 158 159 baseline_session_end(&s); 160 return EXIT_SUCCESS; 161 } 162