baseline

yet another open-source distributed versioning control system
Log | Files | Refs

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