add rm, cp, mkdir, mv
This commit is contained in:
parent
889b35ebd1
commit
f2606d0875
22 changed files with 718 additions and 93 deletions
1
Makefile
1
Makefile
|
@ -12,6 +12,7 @@ CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
|
|||
CCFLAGS += -D_DEFAULT_SOURCE -DMAJOR=$(MAJOR) -DMINOR=$(MINOR) -DPATCH=$(PATCH) -DCHECK_LINK
|
||||
CCFLAGS += $(INCFLAGS)
|
||||
|
||||
LDFLAGS = -s
|
||||
LDFLAGS += $(INCFLAGS)
|
||||
|
||||
BIN = bin
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
A terrible busybox/gnu coreutils clone.
|
||||
|
||||
Currently the only supported commands are:
|
||||
`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`, `xargs`, `tac`
|
||||
`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`, `xargs`, `tac`, `rm`, `cp`, `mkdir`, `mv`
|
||||
|
||||
## How to
|
||||
|
||||
|
|
|
@ -33,3 +33,7 @@ COMMAND(whoami);
|
|||
COMMAND(wc);
|
||||
COMMAND(xargs);
|
||||
COMMAND(tac);
|
||||
COMMAND(rm);
|
||||
COMMAND(cp);
|
||||
COMMAND(makedir);
|
||||
COMMAND(mv);
|
||||
|
|
|
@ -103,7 +103,7 @@ static int short_arg(char c, char* next) {
|
|||
flags.end_lines_dollar = true;
|
||||
break;
|
||||
default:
|
||||
error("error: unkown flag -%c", c);
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
|
232
src/commands/cp.c
Normal file
232
src/commands/cp.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
#include "../command.h"
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static struct {
|
||||
bool recurse;
|
||||
bool preserve;
|
||||
bool sym_link;
|
||||
bool hard_link;
|
||||
bool verbose;
|
||||
} flags;
|
||||
|
||||
static void help(void) {
|
||||
printf("Usage: cp [-rplsv] SOURCE... DEST\n\n");
|
||||
printf("Copy SOURCEs to DEST\n\n");
|
||||
printf("\t-R,-r\tRecurse\n");
|
||||
printf("\t-p\tPreserve file attributes if possible\n");
|
||||
printf("\t-l,-s\tCreate (sym)links\n");
|
||||
printf("\t-v\tVerbose\n");
|
||||
}
|
||||
|
||||
static int short_arg(char c, char* next) {
|
||||
UNUSED(next);
|
||||
switch (c) {
|
||||
case 'R':
|
||||
case 'r':
|
||||
flags.recurse = true;
|
||||
break;
|
||||
case 'p':
|
||||
flags.preserve = true;
|
||||
break;
|
||||
case 'l':
|
||||
flags.hard_link = true;
|
||||
flags.sym_link = false;
|
||||
break;
|
||||
case 's':
|
||||
flags.sym_link = true;
|
||||
flags.hard_link = false;
|
||||
break;
|
||||
case 'v':
|
||||
flags.verbose = true;
|
||||
break;
|
||||
default:
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
||||
static bool copy_file(char* from, char* to) {
|
||||
FILE* from_f = get_file_s(from, "r");
|
||||
if (from_f == NULL) { return false; }
|
||||
|
||||
FILE* to_f = get_file_s(to, "w");
|
||||
if (to_f == NULL) { fclose(from_f); return false; }
|
||||
|
||||
#define BS 1024
|
||||
|
||||
char buf[BS];
|
||||
int read;
|
||||
|
||||
while ((read = fread(buf, 1, BS, from_f)) > 0) {
|
||||
fwrite(buf, 1, read, to_f);
|
||||
}
|
||||
|
||||
if (flags.verbose) {
|
||||
output("copied '%s'", from);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool symlink_file(char* from, char* to) {
|
||||
if (symlink(from, to) < 0) {
|
||||
error_s("failed to symlink '%s': %s", from, strerror(errno));
|
||||
return false;
|
||||
} else if (flags.verbose) {
|
||||
output("symlinked '%s'", from);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hardlink_file(char* from, char* to) {
|
||||
if (link(from, to) < 0) {
|
||||
error_s("failed to hardlink '%s': %s", from, strerror(errno));
|
||||
return false;
|
||||
} else if (flags.verbose) {
|
||||
output("hardlinked '%s'", from);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void run_copy(struct stat* s) {
|
||||
|
||||
char* from = get_path_buffer();
|
||||
char* to = get_path_buffer_2();
|
||||
|
||||
bool result;
|
||||
if (flags.sym_link) {
|
||||
result = symlink_file(from, to);
|
||||
} else if (flags.hard_link) {
|
||||
result = hardlink_file(from, to);
|
||||
} else {
|
||||
result = copy_file(from, to);
|
||||
}
|
||||
|
||||
if (!result) return;
|
||||
if (!flags.preserve) return;
|
||||
|
||||
if (chmod(to, s->st_mode) < 0) {
|
||||
error_s("cannot chmod '%s': %s", to, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (chown(to, s->st_uid, s->st_gid) < 0) {
|
||||
error_s("cannot chown '%s': %s", to, strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void cp_file(char* path);
|
||||
|
||||
static void cp_directory(struct stat* s) {
|
||||
if (!flags.recurse) {
|
||||
error_s("-r not specified; omitting directory '%s'", get_path_buffer());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mkdir(get_path_buffer_2(), s->st_mode) < 0 && errno != EEXIST) {
|
||||
error_s("cannot create directory '%s': %s", get_path_buffer_2(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
DIR* d = opendir(get_path_buffer());
|
||||
|
||||
if (d == NULL) {
|
||||
error_s("cannot open directory '%s': %s", get_path_buffer(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
struct dirent* file;
|
||||
while ((file = readdir(d)) != NULL) {
|
||||
if (is_dot_dir(file->d_name)) continue;
|
||||
cp_file(file->d_name);
|
||||
}
|
||||
}
|
||||
|
||||
static char* get_file_name(char* path) {
|
||||
if (path[0] == '\0') return path;
|
||||
|
||||
int last = 0;
|
||||
int i = 0;
|
||||
while (true) {
|
||||
if (path[i+1] == '\0') break;
|
||||
if (path[i] == '/') {
|
||||
last = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (last == 0) return path;
|
||||
else return path + last + 1;
|
||||
}
|
||||
|
||||
static void cp_file(char* path) {
|
||||
|
||||
int save = push_path_buffer(path);
|
||||
int save2 = push_path_buffer_2(get_file_name(path));
|
||||
|
||||
struct stat s;
|
||||
if (lstat(get_path_buffer(), &s) < 0) {
|
||||
pop_path_buffer(save);
|
||||
error_s("cannot stat '%s': %s", get_path_buffer(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
cp_directory(&s);
|
||||
} else {
|
||||
run_copy(&s);
|
||||
}
|
||||
|
||||
pop_path_buffer(save);
|
||||
pop_path_buffer_2(save2);
|
||||
}
|
||||
|
||||
COMMAND(cp) {
|
||||
|
||||
flags.hard_link = false;
|
||||
flags.sym_link = false;
|
||||
flags.preserve = false;
|
||||
flags.recurse = false;
|
||||
flags.verbose = false;
|
||||
|
||||
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||
|
||||
if (argc - start < 2) {
|
||||
global_help(help);
|
||||
}
|
||||
|
||||
// only when 2 args and first is a file, the 2nd will be a file
|
||||
if (argc - start == 2) {
|
||||
struct stat s;
|
||||
if (lstat(argv[start], &s) < 0) {
|
||||
error("cannot stat '%s': %s", argv[start], strerror(errno));
|
||||
}
|
||||
push_path_buffer(argv[argc-2]);
|
||||
push_path_buffer_2(argv[argc-1]);
|
||||
if (!S_ISDIR(s.st_mode)) {
|
||||
run_copy(&s);
|
||||
} else {
|
||||
cp_directory(&s);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// push directory
|
||||
push_path_buffer_2(argv[argc-1]);
|
||||
|
||||
struct stat s;
|
||||
if (lstat(get_path_buffer_2(), &s) < 0) {
|
||||
error("target: '%s': %s", get_path_buffer_2(), strerror(errno));
|
||||
}
|
||||
|
||||
for (int i = start; i < argc - 1; i++) {
|
||||
cp_file(argv[i]);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -29,16 +29,16 @@ COMMAND(dd) {
|
|||
char* str = argv[i] + 3;
|
||||
bs = get_number(str);
|
||||
if (bs < 1) {
|
||||
error("error: block size must be greater than 0");
|
||||
error("block size must be greater than 0");
|
||||
}
|
||||
} else if (prefix("count=", argv[i])) {
|
||||
char* str = argv[i] + 6;
|
||||
count = get_number(str);
|
||||
if (count < 1) {
|
||||
error("error: count must be greather than 0");
|
||||
error("count must be greather than 0");
|
||||
}
|
||||
} else {
|
||||
error("error: unkown option %s", argv[i]);
|
||||
error("unkown option %s", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ static bool read_regex(char** end, re_t* regex, enum RegexDirection dir) {
|
|||
while(true) {
|
||||
c = *(index++);
|
||||
if (c == '\0') {
|
||||
fprintf(stderr, "error: missing regex after %c\n", dir == BEFORE ? '?' : '/');
|
||||
error_s("missing regex after %c\n", dir == BEFORE ? '?' : '/');
|
||||
return false;
|
||||
}
|
||||
if (c == (dir == BEFORE ? '?' : '/')) {
|
||||
|
@ -170,7 +170,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
|||
n_pre = -1;
|
||||
} else {
|
||||
if (n_pre < 0) {
|
||||
fprintf(stderr, "error: input cannot be negative\n");
|
||||
error_s("input cannot be negative\n");
|
||||
return false;
|
||||
}
|
||||
index = end_pre;
|
||||
|
@ -192,7 +192,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
|||
char* end;
|
||||
long int n = strtol(index, &end, 10) - 1;
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "error: input cannot be negative\n");
|
||||
error_s("input cannot be negative\n");
|
||||
return false;
|
||||
}
|
||||
if (index == end) {
|
||||
|
@ -201,7 +201,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
|||
address.data.index.i = line_current - n;
|
||||
}
|
||||
if (address.data.index.i < 0) {
|
||||
fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1);
|
||||
error_s("line number %ld does not exist\n", address.data.index.i + 1);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -211,7 +211,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
|||
char* end;
|
||||
long int n = strtol(index, &end, 10) - 1;
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "error: input cannot be negative\n");
|
||||
error_s("input cannot be negative\n");
|
||||
return false;
|
||||
}
|
||||
if (index == end) {
|
||||
|
@ -220,7 +220,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
|||
address.data.index.i = line_current + n;
|
||||
}
|
||||
if (address.data.index.i >= (long int) line_count) {
|
||||
fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1);
|
||||
error_s("line number %ld does not exist\n", address.data.index.i + 1);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -256,7 +256,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
|||
address.data.index.i = n_pre;
|
||||
}
|
||||
if (address.data.index.i < 0 || address.data.index.i >= (long int) line_count) {
|
||||
fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1);
|
||||
error_s("line number %ld does not exist\n", address.data.index.i + 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ static void delete_lines(unsigned long a, unsigned long b) {
|
|||
|
||||
static bool handle_append(struct LineAddress* address) {
|
||||
if (address->type != INDEX) {
|
||||
fprintf(stderr, "error: append command requires index addressing\n");
|
||||
error_s("append command requires index addressing\n");
|
||||
return false;
|
||||
}
|
||||
if (line_count == 0) {
|
||||
|
@ -424,20 +424,20 @@ static bool handle_append(struct LineAddress* address) {
|
|||
|
||||
static bool handle_delete(struct LineAddress* address) {
|
||||
if (address->empty && address->data.index.i >= (long int) line_count) {
|
||||
fprintf(stderr, "error: line number %ld does not exist\n", address->data.index.i + 1);
|
||||
error_s("line number %ld does not exist\n", address->data.index.i + 1);
|
||||
return false;
|
||||
}
|
||||
if (address->type == INDEX) {
|
||||
delete_lines(address->data.index.i, address->data.index.i);
|
||||
printf("ed: deleted line %ld\n", address->data.index.i+1);
|
||||
output("deleted line %ld\n", address->data.index.i+1);
|
||||
} else if (address->type == RANGE) {
|
||||
delete_lines(address->data.range.a, address->data.range.b);
|
||||
printf("ed: deleted lines %ld-%ld\n", address->data.range.a+1, address->data.range.b+1);
|
||||
output("deleted lines %ld-%ld\n", address->data.range.a+1, address->data.range.b+1);
|
||||
} else if (address->type == SET) {
|
||||
for (unsigned long i = 0; i < address->data.set.s; i++) {
|
||||
delete_lines(address->data.set.b[i], address->data.set.b[i]);
|
||||
}
|
||||
printf("ed: deleted %lu lines\n", address->data.set.s);
|
||||
output("deleted %lu lines\n", address->data.set.s);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -446,7 +446,7 @@ static bool get_file_name(char** filename) {
|
|||
size_t len = strlen(*filename);
|
||||
if (len < 1 || (len == 1 && **filename == '\n')) {
|
||||
if (default_filename == NULL) {
|
||||
fprintf(stderr, "error: no default filename specified\n");
|
||||
error_s("no default filename specified\n");
|
||||
return false;
|
||||
}
|
||||
*filename = default_filename;
|
||||
|
@ -468,7 +468,7 @@ static bool get_file_name(char** filename) {
|
|||
|
||||
static void write_file(char* filename, struct LineAddress* address, char* type) {
|
||||
if (line_count < 1) {
|
||||
fprintf(stderr, "error: cannot write empty file\n");
|
||||
error_s("cannot write empty file\n");
|
||||
return;
|
||||
}
|
||||
if (!get_file_name(&filename)) return;
|
||||
|
@ -497,7 +497,7 @@ static void write_file(char* filename, struct LineAddress* address, char* type)
|
|||
}
|
||||
pending_writes = false;
|
||||
fclose(file);
|
||||
printf("ed: wrote %d lines from %s\n", wrote, filename);
|
||||
output("wrote %d lines from %s\n", wrote, filename);
|
||||
}
|
||||
|
||||
static void read_file(char* filename) {
|
||||
|
@ -512,7 +512,7 @@ static void read_file(char* filename) {
|
|||
|
||||
if (size < 1) {
|
||||
free(buf);
|
||||
fprintf(stderr, "error: attempted to read a empty file\n");
|
||||
error_s("attempted to read a empty file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -522,7 +522,7 @@ static void read_file(char* filename) {
|
|||
}
|
||||
append_lines(line, buf, size);
|
||||
free(buf);
|
||||
printf("ed: read and appended %lu lines from %s\n", size, filename);
|
||||
output("read and appended %lu lines from %s\n", size, filename);
|
||||
}
|
||||
|
||||
static void expand_string(char** buf, int* capacity, int* size, char* text, int len) {
|
||||
|
@ -582,7 +582,7 @@ static void prompt(void) {
|
|||
|
||||
if (cmd == ',') {
|
||||
if (address.type != INDEX) {
|
||||
fprintf(stderr, "error: comma range addressing requires two index addresses\n");
|
||||
error_s("comma range addressing requires two index addresses\n");
|
||||
free_address(address);
|
||||
return;
|
||||
}
|
||||
|
@ -593,7 +593,7 @@ static void prompt(void) {
|
|||
return;
|
||||
}
|
||||
if (address2.type != INDEX) {
|
||||
fprintf(stderr, "error: comma range addressing requires two index addresses\n");
|
||||
error_s("comma range addressing requires two index addresses\n");
|
||||
free_address(address);
|
||||
free_address(address2);
|
||||
return;
|
||||
|
@ -606,7 +606,7 @@ static void prompt(void) {
|
|||
}
|
||||
|
||||
if (address.type == RANGE && address.data.range.a > address.data.range.b) {
|
||||
fprintf(stderr, "error: range addressing must be in ascending order\n");
|
||||
error_s("range addressing must be in ascending order\n");
|
||||
free_address(address);
|
||||
return;
|
||||
}
|
||||
|
@ -618,10 +618,10 @@ test:
|
|||
case '\n':
|
||||
if (address.empty) {
|
||||
if (line_current == line_count) {
|
||||
fprintf(stderr, "error: line number %ld does not exist\n", line_current + 1);
|
||||
error_s("line number %ld does not exist\n", line_current + 1);
|
||||
break;
|
||||
} else if (line_current + 1 == line_count) {
|
||||
fprintf(stderr, "error: line number %ld does not exist\n", line_current + 2);
|
||||
error_s("line number %ld does not exist\n", line_current + 2);
|
||||
break;
|
||||
} else {
|
||||
line_current++;
|
||||
|
@ -634,7 +634,7 @@ test:
|
|||
} else if (address.type == RANGE) {
|
||||
line_current = address.data.range.b;
|
||||
} else if (address.type == SET) {
|
||||
fprintf(stderr, "error: unexpected range addressing\n");
|
||||
error_s("unexpected range addressing\n");
|
||||
break;
|
||||
}
|
||||
printf("%s", lines[line_current]);
|
||||
|
@ -656,7 +656,7 @@ test:
|
|||
__attribute__((fallthrough));
|
||||
case 'p':
|
||||
if (address.empty && address.data.index.i >= (long int) line_count) {
|
||||
fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1);
|
||||
error_s("line number %ld does not exist\n", address.data.index.i + 1);
|
||||
break;
|
||||
}
|
||||
if (address.type == INDEX) {
|
||||
|
@ -686,7 +686,7 @@ test:
|
|||
skip_whitespace(&index);
|
||||
free_address(address);
|
||||
if (*(index++) != '/') {
|
||||
fprintf(stderr, "error: unexpected character at start of regex\n");
|
||||
error_s("unexpected character at start of regex\n");
|
||||
break;
|
||||
}
|
||||
if (!parse_regex(&index, &address, ALL)) { return; }
|
||||
|
@ -701,18 +701,18 @@ test:
|
|||
case 's':
|
||||
skip_whitespace(&index);
|
||||
if (*(index++) != '/') {
|
||||
fprintf(stderr, "error: unexpected character at start of regex\n");
|
||||
error_s("unexpected character at start of regex\n");
|
||||
break;
|
||||
}
|
||||
if (!parse_regex_lines(&index, &address)) { return; }
|
||||
char* replace = index;
|
||||
while(*index != '\0' && *index != '/') index++;
|
||||
if (*index != '/') {
|
||||
fprintf(stderr, "error: / missing after %c\n", *index);
|
||||
error_s("/ missing after %c\n", *index);
|
||||
break;
|
||||
}
|
||||
if (address.data.set.s < 1) {
|
||||
printf("ed: no matches found\n");
|
||||
error_s("no matches found\n");
|
||||
break;
|
||||
}
|
||||
*(index++) = '\0';
|
||||
|
@ -725,11 +725,11 @@ test:
|
|||
char* end;
|
||||
matches = strtol(index, &end, 10);
|
||||
if (end == index) {
|
||||
fprintf(stderr, "error: invalid number: %s\n", index);
|
||||
error_s("invalid number: %s\n", index);
|
||||
break;
|
||||
}
|
||||
if (matches < 1) {
|
||||
fprintf(stderr, "error: matches cannot be less than 1\n");
|
||||
error_s("matches cannot be less than 1\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -739,7 +739,7 @@ test:
|
|||
for (unsigned long i = 0; i < address.data.set.s; i++) {
|
||||
matches_found += substute_string(address.data.set.b[i], matches, last_regex, replace, sub_len);
|
||||
}
|
||||
printf("ed: replaced %ld matches over %ld lines\n", matches_found, address.data.set.s);
|
||||
output("replaced %ld matches over %ld lines\n", matches_found, address.data.set.s);
|
||||
pending_writes = true;
|
||||
break;
|
||||
case 'w': {
|
||||
|
@ -782,7 +782,7 @@ test:
|
|||
printf("%ld\n", line_current + 1);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "error: unimplemented command\n");
|
||||
error_s("unimplemented command\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ COMMAND_EMPTY(groups) {
|
|||
|
||||
struct passwd* pw = getpwuid(uid);
|
||||
if(pw == NULL){
|
||||
perror("error: failed to fetch groups: ");
|
||||
error("failed to fetch groups: %s", strerror(errno));
|
||||
}
|
||||
|
||||
int ngroups = 0;
|
||||
|
@ -21,7 +21,7 @@ COMMAND_EMPTY(groups) {
|
|||
for (int i = 0; i < ngroups; i++){
|
||||
struct group* gr = getgrgid(groups[i]);
|
||||
if(gr == NULL){
|
||||
perror("error: failed to fetch groups: ");
|
||||
error("failed to fetch groups: %s", strerror(errno));
|
||||
}
|
||||
printf("%s ",gr->gr_name);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ static int short_arg(char c, char* next) {
|
|||
check_arg(next);
|
||||
long int bkm = get_blkm(next);
|
||||
if (bkm < 1) {
|
||||
error("error: bkm cannot be less than 1");
|
||||
error("bkm cannot be less than 1");
|
||||
}
|
||||
flags.count = bkm;
|
||||
return ARG_USED;
|
||||
|
@ -80,7 +80,7 @@ static int short_arg(char c, char* next) {
|
|||
check_arg(next);
|
||||
long int bkm = get_blkm(next);
|
||||
if (bkm < 1) {
|
||||
error("error: bkm cannot be less than 1");
|
||||
error("bkm cannot be less than 1");
|
||||
}
|
||||
flags.count = bkm;
|
||||
return ARG_USED;
|
||||
|
@ -91,9 +91,8 @@ static int short_arg(char c, char* next) {
|
|||
case 'v':
|
||||
flags.print_headers = true;
|
||||
break;
|
||||
default: {
|
||||
error("error: unknown option -%c", c);
|
||||
}
|
||||
default:
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ COMMAND_EMPTY(user_id) {
|
|||
|
||||
struct passwd* pw = getpwuid(uid);
|
||||
if(pw == NULL){
|
||||
perror("error: failed to fetch groups: ");
|
||||
error("failed to fetch groups: %s", strerror(errno));
|
||||
}
|
||||
|
||||
int ngroups = 0;
|
||||
|
@ -30,7 +30,7 @@ COMMAND_EMPTY(user_id) {
|
|||
for (int i = 0; i < ngroups; i++){
|
||||
struct group* gr = getgrgid(groups[i]);
|
||||
if(gr == NULL){
|
||||
perror("error: failed to fetch groups: ");
|
||||
error("failed to fetch groups: %s", strerror(errno));
|
||||
}
|
||||
printf("%d(%s)", gr->gr_gid, gr->gr_name);
|
||||
if (i + 1 < ngroups) putchar(',');
|
||||
|
|
|
@ -55,9 +55,9 @@ static DIR* get_directory(char* path) {
|
|||
DIR* d = opendir(path);
|
||||
if (d == NULL) {
|
||||
if (errno == ENOTDIR) {
|
||||
printf("\x1b[0m%s is a a file\n", path);
|
||||
error_s("`%s` is a a file\n", path);
|
||||
} else {
|
||||
printf("\x1b[0merror: failed to open directory '%s': %s\n", path, strerror(errno));
|
||||
error_s("failed to open directory '%s': %s\n", path, strerror(errno));
|
||||
}
|
||||
}
|
||||
return d;
|
||||
|
@ -74,7 +74,7 @@ static bool get_file_info(const char* file_name, struct FileInfo* info) {
|
|||
int save = push_path_buffer(file_name);
|
||||
|
||||
if (lstat(get_path_buffer(), &s) < 0) {
|
||||
printf("\x1b[0merror: failed to read file '%s': %s\n", get_path_buffer(), strerror(errno));
|
||||
error_s("failed to read file '%s': %s\n", get_path_buffer(), strerror(errno));
|
||||
pop_path_buffer(save);
|
||||
return false;
|
||||
}
|
||||
|
@ -156,14 +156,14 @@ static bool get_file_info(const char* file_name, struct FileInfo* info) {
|
|||
|
||||
info->usr = getpwuid(s.st_uid);
|
||||
if (info->usr == NULL) {
|
||||
fprintf(stderr, "error: failed to get user from %s\n", get_path_buffer());
|
||||
error_s("failed to get user from `%s`\n", get_path_buffer());
|
||||
pop_path_buffer(save);
|
||||
return false;
|
||||
}
|
||||
|
||||
info->grp = getgrgid(s.st_gid);
|
||||
if (info->grp == NULL) {
|
||||
fprintf(stderr, "error: failed to get user from %s\n", get_path_buffer());
|
||||
error_s("failed to get user from `%s`\n", get_path_buffer());
|
||||
pop_path_buffer(save);
|
||||
return false;
|
||||
}
|
||||
|
@ -288,10 +288,6 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo
|
|||
if (!flags.more_info) printf("\n");
|
||||
}
|
||||
|
||||
static bool is_dot_dir(const char* path) {
|
||||
return streql(path, ".") || streql(path, "..");
|
||||
}
|
||||
|
||||
static int num_places (int n) {
|
||||
int r = 1;
|
||||
if (n < 0) n = (n == INT_MIN) ? INT_MAX: -n;
|
||||
|
@ -465,7 +461,7 @@ static int short_arg(char c, char* next) {
|
|||
flags.more_info = true;
|
||||
break;
|
||||
default:
|
||||
error("error: unkown option -%c", c);
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
@ -481,7 +477,7 @@ static int long_arg(char* cur, char* next) {
|
|||
} else if (streql("no", arg) || streql("never", arg)) {
|
||||
flags.colored = NO;
|
||||
} else {
|
||||
error("error: invalid color options: %s", arg);
|
||||
error("invalid color options: %s", arg);
|
||||
}
|
||||
} else {
|
||||
return ARG_IGNORE;
|
||||
|
@ -496,7 +492,7 @@ COMMAND(ls) {
|
|||
flags.hide_dot = false;
|
||||
flags.one_column = false;
|
||||
flags.recurse = false;
|
||||
flags.colored = AUTO;
|
||||
flags.colored = NO;
|
||||
|
||||
int start = parse_args(argc, argv, help, short_arg, long_arg);
|
||||
|
||||
|
|
60
src/commands/mkdir.c
Normal file
60
src/commands/mkdir.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "../command.h"
|
||||
|
||||
static struct {
|
||||
bool make_parent;
|
||||
mode_t mode;
|
||||
} flags;
|
||||
|
||||
static int short_arg(char c, char* next) {
|
||||
switch (c) {
|
||||
case 'p':
|
||||
flags.make_parent = true;
|
||||
break;
|
||||
case 'm':
|
||||
check_arg(next);
|
||||
flags.mode = get_mode(next);
|
||||
return ARG_USED;
|
||||
default:
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
||||
static void help(void) {
|
||||
printf("Usage: mkdir [-m MODE] [-p] DIRECTORY...\n\n");
|
||||
printf("Create DIRECTORY\n\n");
|
||||
printf("\t-m\tMODE\n");
|
||||
printf("\t-p\tNo error if exists; make parent directories as needed\n");
|
||||
}
|
||||
|
||||
static bool mkdir_parents(char* path) {
|
||||
for (size_t i = 1; i < strlen(path); i++) {
|
||||
if (path[i] != '/') continue;
|
||||
path[i] = '\0';
|
||||
if (mkdir(path, flags.mode) < 0 && errno != EEXIST) {
|
||||
error_s("failed to create directory '%s': %s", path, strerror(errno));
|
||||
return false;
|
||||
};
|
||||
path[i] = '/';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
COMMAND(makedir) {
|
||||
if (argc < 1) global_help(help);
|
||||
|
||||
flags.make_parent = false;
|
||||
flags.mode = 0755;
|
||||
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||
|
||||
for (int i = start; i < argc; i++) {
|
||||
if (flags.make_parent && !mkdir_parents(argv[i])) {
|
||||
continue;
|
||||
}
|
||||
if (mkdir(argv[i], flags.mode) < 0) {
|
||||
error_s("failed to create directory '%s': %s", argv[i], strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
108
src/commands/mv.c
Normal file
108
src/commands/mv.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "../command.h"
|
||||
|
||||
static struct {
|
||||
bool prompt;
|
||||
bool dont_overwrite;
|
||||
bool refuse_if_dir;
|
||||
bool verbose;
|
||||
} flags;
|
||||
|
||||
static void help(void) {
|
||||
printf("Usage: mv [-inT] SOURCE... DIRECTORY\n\n");
|
||||
printf("Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n");
|
||||
printf("\t-i\tInteractive, prompt before overwriting\n");
|
||||
printf("\t-n\tDon't overwrite an existing file\n");
|
||||
printf("\t-T\tRefuse to move if DEST is a directory\n");
|
||||
printf("\t-v\tVerbose\n");
|
||||
}
|
||||
|
||||
static int short_arg(char c, char* next) {
|
||||
UNUSED(next);
|
||||
switch (c) {
|
||||
case 't':
|
||||
flags.prompt = true;
|
||||
break;
|
||||
case 'n':
|
||||
flags.dont_overwrite = true;
|
||||
break;
|
||||
case 'T':
|
||||
flags.refuse_if_dir = true;
|
||||
break;
|
||||
case 'v':
|
||||
flags.verbose = true;
|
||||
break;
|
||||
default:
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
return ARG_USED;
|
||||
}
|
||||
|
||||
static void mv_dir(bool exists) {
|
||||
if (exists && flags.dont_overwrite) {
|
||||
if (flags.verbose) output("skipping '%s'; overwrise is false", get_path_buffer_2());
|
||||
return;
|
||||
}
|
||||
if (exists && flags.prompt) {
|
||||
fprintf(stderr, "overwrite '%s'? ", get_path_buffer_2());
|
||||
fflush(stderr);
|
||||
char c = getchar();
|
||||
if (c != 'y' && c != 'Y') {
|
||||
if (flags.verbose) output("skipping...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rename(get_path_buffer(), get_path_buffer_2()) < 0) {
|
||||
error_s("cannot move '%s': %s", get_path_buffer(), strerror(errno));
|
||||
} else if (flags.verbose) {
|
||||
output("moved '%s'", get_path_buffer());
|
||||
}
|
||||
}
|
||||
|
||||
COMMAND(mv) {
|
||||
|
||||
flags.refuse_if_dir = false;
|
||||
flags.dont_overwrite = false;
|
||||
flags.prompt = false;
|
||||
flags.verbose = false;
|
||||
|
||||
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||
|
||||
if (argc - start < 2) {
|
||||
global_help(help);
|
||||
}
|
||||
|
||||
push_path_buffer_2(argv[argc-1]);
|
||||
|
||||
bool dest = true;
|
||||
struct stat s;
|
||||
if (lstat(get_path_buffer_2(), &s) < 0 && argc - start > 2) {
|
||||
dest = false;
|
||||
error("cannot stat '%s': %s", get_path_buffer_2(), strerror(errno));
|
||||
}
|
||||
|
||||
if (dest && flags.refuse_if_dir) {
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
error("target '%s': Is A Directory", get_path_buffer_2());
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - start == 2) {
|
||||
push_path_buffer(argv[argc-2]);
|
||||
mv_dir(dest);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (dest && !S_ISDIR(s.st_mode)) {
|
||||
error("target '%s': Is Not A Directory", get_path_buffer_2());
|
||||
}
|
||||
|
||||
for (int i = start; i < argc - 1; i++) {
|
||||
int save = push_path_buffer(argv[i]);
|
||||
bool exists = lstat(get_path_buffer(), &s) >= 0;
|
||||
mv_dir(exists);
|
||||
pop_path_buffer(save);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -96,7 +96,8 @@ static void help(void) {
|
|||
|
||||
COMMAND(print) {
|
||||
if (argc < 1) {
|
||||
error("usage: printf FORMAT [ARG]...\n");
|
||||
global_help(help);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
parse_help(argc, argv, help);
|
||||
|
|
132
src/commands/rm.c
Normal file
132
src/commands/rm.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include "../command.h"
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct {
|
||||
bool force;
|
||||
bool prompt;
|
||||
bool verbose;
|
||||
bool recurse;
|
||||
} flags;
|
||||
|
||||
#ifdef FRENCH
|
||||
static bool get_frenched;
|
||||
#endif
|
||||
|
||||
static void help(void) {
|
||||
printf("Usage: rm [-irfv] FILE...\n\n");
|
||||
printf("Remove (unlink) FILESs\n\n");
|
||||
printf("\t-i\tAlways prompt before removing\n");
|
||||
printf("\t-f\tForce, never prompt\n");
|
||||
printf("\t-v\tVerbose\n");
|
||||
printf("\t-R,-r\tRecurse\n");
|
||||
}
|
||||
|
||||
static int short_arg(char c, char* next) {
|
||||
UNUSED(next);
|
||||
switch (c) {
|
||||
case 'i':
|
||||
flags.prompt = true;
|
||||
break;
|
||||
case 'f':
|
||||
flags.force = true;
|
||||
break;
|
||||
case 'v':
|
||||
flags.verbose = true;
|
||||
break;
|
||||
case 'R':
|
||||
case 'r':
|
||||
flags.recurse = true;
|
||||
break;
|
||||
default:
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
||||
static void rm_file(char* path);
|
||||
|
||||
static bool rm_dir() {
|
||||
DIR* d = opendir(get_path_buffer());
|
||||
if (d == NULL) {
|
||||
error_s("failed to stat '%s': %s\n", get_path_buffer(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct dirent* file;
|
||||
while ((file = readdir(d)) != NULL) {
|
||||
if (is_dot_dir(file->d_name)) continue;
|
||||
rm_file(file->d_name);
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rm_file(char* path) {
|
||||
int save = push_path_buffer(path);
|
||||
|
||||
struct stat s;
|
||||
if (lstat(get_path_buffer(), &s) < 0) {
|
||||
pop_path_buffer(save);
|
||||
error_s("failed to stat '%s': %s\n", get_path_buffer(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
if (!flags.force) {
|
||||
error_s("cannot delete '%s': Is a directory\n", get_path_buffer());
|
||||
pop_path_buffer(save);
|
||||
return;
|
||||
}
|
||||
if (flags.recurse && !rm_dir()) {
|
||||
pop_path_buffer(save);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.prompt) {
|
||||
fprintf(stderr, "delete '%s'? ", get_path_buffer());
|
||||
fflush(stderr);
|
||||
char c = getchar();
|
||||
if (c != 'y' && c != 'Y') {
|
||||
fprintf(stderr, "Skipping...\n");
|
||||
pop_path_buffer(save);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove(get_path_buffer()) < 0) {
|
||||
error_s("failed to delete '%s': %s\n", get_path_buffer(), strerror(errno));
|
||||
} else if (flags.verbose) {
|
||||
output("deleted '%s'\n", get_path_buffer());
|
||||
}
|
||||
|
||||
pop_path_buffer(save);
|
||||
}
|
||||
|
||||
COMMAND(rm) {
|
||||
if (argc < 1) {
|
||||
global_help(help);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
flags.prompt = false;
|
||||
flags.force = false;
|
||||
flags.verbose = false;
|
||||
flags.recurse = false;
|
||||
|
||||
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||
|
||||
#ifdef FRENCH
|
||||
if (streql(argv[0], "-rf")) {
|
||||
printf("\x1b[94mremoving \x1b[97mthe \x1b[91mfrench \x1b[93m(beguette noises)\x1b[0m\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = start; i < argc; i++) {
|
||||
rm_file(argv[i]);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -131,7 +131,7 @@ static int short_arg(char c, char* next) {
|
|||
check_arg(next);
|
||||
long int bkm = get_blkm(next);
|
||||
if (bkm < 1) {
|
||||
error("error: bkm cannot be less than 1");
|
||||
error("bkm cannot be less than 1");
|
||||
}
|
||||
flags.count = bkm;
|
||||
return ARG_USED;
|
||||
|
@ -141,7 +141,7 @@ static int short_arg(char c, char* next) {
|
|||
check_arg(next);
|
||||
long int bkm = get_blkm(next);
|
||||
if (bkm < 1) {
|
||||
error("error: bkm cannot be less than 1");
|
||||
error("bkm cannot be less than 1");
|
||||
}
|
||||
flags.count = bkm;
|
||||
return ARG_USED;
|
||||
|
@ -159,14 +159,13 @@ static int short_arg(char c, char* next) {
|
|||
check_arg(next);
|
||||
long int sec = get_number(next);
|
||||
if (sec < 1) {
|
||||
error("error: wait seconds cannot be less than 1");
|
||||
error("wait seconds cannot be less than 1");
|
||||
}
|
||||
flags.grow_wait = sec;
|
||||
return ARG_USED;
|
||||
}
|
||||
default: {
|
||||
error("error: unknown option -%c", c);
|
||||
}
|
||||
default:
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ static int short_arg(char c, char* next) {
|
|||
flags.handle_sigint = true;
|
||||
break;
|
||||
default:
|
||||
error("error: unkown option: %c", c);
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ static int short_arg(char c, char* next) {
|
|||
flags.longest_line = true;
|
||||
break;
|
||||
default:
|
||||
error("error: invald option -%c", c);
|
||||
return ARG_INVALID;
|
||||
}
|
||||
flags.has_flags = true;
|
||||
return ARG_UNUSED;
|
||||
|
|
|
@ -45,10 +45,12 @@ static int short_arg(char c, char* next) {
|
|||
check_arg(next);
|
||||
long int n = get_number(next);
|
||||
if (n < 1) {
|
||||
error("error: max arg count must be at least 1");
|
||||
error("max arg count must be at least 1");
|
||||
}
|
||||
flags.max_args = n;
|
||||
return ARG_USED;
|
||||
default:
|
||||
return ARG_INVALID;
|
||||
}
|
||||
return ARG_UNUSED;
|
||||
}
|
||||
|
|
21
src/main.c
21
src/main.c
|
@ -8,9 +8,12 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
char* cmd;
|
||||
|
||||
int main (ARGUMENTS) {
|
||||
if (argc < 1) {
|
||||
error("error: argument 0 missing");
|
||||
fprintf(stderr, "fatal: argument 0 missing");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef CHECK_LINK
|
||||
|
@ -21,7 +24,7 @@ int main (ARGUMENTS) {
|
|||
if (argc < 2) {
|
||||
printf("usage: lazysphere [function [arguments]...]\n\n");
|
||||
printf("currently defined functions:\n");
|
||||
printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc, xargs, tac\n");
|
||||
printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc, xargs, tac, rm, cp, mkdir, mv\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
argc--;
|
||||
|
@ -29,7 +32,6 @@ int main (ARGUMENTS) {
|
|||
}
|
||||
#endif
|
||||
|
||||
const char* cmd;
|
||||
if (strncmp("./", argv[0], 2) == 0) {
|
||||
cmd = argv[0] + 2;
|
||||
} else {
|
||||
|
@ -52,6 +54,8 @@ int main (ARGUMENTS) {
|
|||
return user_id();
|
||||
} else if (streql(cmd, "ls") || streql(cmd, "dir")) {
|
||||
return ls(NEXT_ARGS);
|
||||
} else if (streql(cmd, "lsd")) {
|
||||
printf("look at all the funny colors\n");
|
||||
} else if (streql(cmd, "tail")) {
|
||||
return tail(NEXT_ARGS);
|
||||
} else if (streql(cmd, "head")) {
|
||||
|
@ -72,8 +76,17 @@ int main (ARGUMENTS) {
|
|||
return xargs(NEXT_ARGS);
|
||||
} else if (streql(cmd, "tac")) {
|
||||
return tac(NEXT_ARGS);
|
||||
} else if (streql(cmd, "rm")) {
|
||||
return rm(NEXT_ARGS);
|
||||
} else if (streql(cmd, "cp")) {
|
||||
return cp(NEXT_ARGS);
|
||||
} else if (streql(cmd, "mkdir")) {
|
||||
return makedir(NEXT_ARGS);
|
||||
} else if (streql(cmd, "mv")) {
|
||||
return mv(NEXT_ARGS);
|
||||
} else {
|
||||
error("error: invalid command %s", cmd);
|
||||
fprintf(stderr, "lazysphere: invalid command %s", cmd);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "shared.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -10,15 +11,36 @@
|
|||
#include <sys/stat.h>
|
||||
#include <paths.h>
|
||||
|
||||
extern char* cmd;
|
||||
|
||||
void error_s(const char *format, ...) {
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
|
||||
fprintf(stderr, "%s: ", cmd);
|
||||
vfprintf(stderr, format, list);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void error(const char *format, ...) {
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
|
||||
fprintf(stderr, "%s: ", cmd);
|
||||
vfprintf(stderr, format, list);
|
||||
fprintf(stderr, "\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void output(const char *format, ...) {
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
|
||||
fprintf(stdout, "%s: ", cmd);
|
||||
vfprintf(stdout, format, list);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
FILE* get_file_s(const char* path, const char* type) {
|
||||
struct stat s;
|
||||
if (streql("-", path) && type[0] == 'r') {
|
||||
|
@ -28,11 +50,11 @@ FILE* get_file_s(const char* path, const char* type) {
|
|||
}
|
||||
if (lstat(path, &s) < 0) {
|
||||
if (type[0] != 'r') goto read;
|
||||
fprintf(stderr, "error: failed to read %s: %s\n", path, strerror(errno));
|
||||
error_s("failed to read %s: %s", path, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
fprintf(stderr, "error: %s is a directory\n", path);
|
||||
error_s("%s is a directory", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -40,7 +62,7 @@ FILE* get_file_s(const char* path, const char* type) {
|
|||
read:
|
||||
file = fopen(path, type);
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "error: failed to %s file %s: %s\n", type[0] == 'r' ? "read" : "write", path, strerror(errno));
|
||||
error_s("failed to %s file %s: %s", type[0] == 'r' ? "read" : "write", path, strerror(errno));
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
@ -55,7 +77,7 @@ long int get_number(const char* text) {
|
|||
char* end;
|
||||
long int n = strtol(text, &end, 10);
|
||||
if (text == end) {
|
||||
error("error: %s is not a valid number", text);
|
||||
error("%s is not a valid number", text);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@ -64,7 +86,7 @@ long int get_blkm(const char* text) {
|
|||
char* end;
|
||||
long int n = strtol(text, &end, 10);
|
||||
if (text == end) {
|
||||
error("error: %s is not a valid bkm", text);
|
||||
error("%s is not a valid bkm", text);
|
||||
}
|
||||
if (*end == '\0') return n;
|
||||
switch (*end) {
|
||||
|
@ -78,12 +100,23 @@ long int get_blkm(const char* text) {
|
|||
case 'm':
|
||||
return n * 1024 * 1204;
|
||||
default:
|
||||
error("error: invalid bkm type %c", *end);
|
||||
error("invalid bkm type %c", *end);
|
||||
}
|
||||
// shouldnt get here anyways
|
||||
return 0;
|
||||
}
|
||||
|
||||
mode_t get_mode(const char* next) {
|
||||
char* end = NULL;
|
||||
mode_t mode = (mode_t)strtol(next, &end, 8);
|
||||
if (!end) return 0;
|
||||
while(isspace(*end)) end++;
|
||||
if (*end != '\0' || (unsigned) mode < 010000) {
|
||||
error("invalid file mode: `%s`", next);
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
bool streql(const char* a, const char* b) {
|
||||
if (*a != *b) return false;
|
||||
int n = 0;
|
||||
|
@ -151,11 +184,11 @@ void print_date_time(time_t mills, char buf[13]) {
|
|||
|
||||
void check_arg (char* arg) {
|
||||
if (arg == NULL) {
|
||||
error("error: expected another argument after option");
|
||||
error("expected another argument after option");
|
||||
}
|
||||
}
|
||||
|
||||
static void global_help(void (*help)(void)) {
|
||||
void global_help(void (*help)(void)) {
|
||||
printf("LazySphere v%d.%d.%d multi-call binary.\n\n", MAJOR, MINOR, PATCH);
|
||||
help();
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -196,6 +229,8 @@ int parse_args(int argc, char** argv, void (*help)(void), int (*short_arg)(char,
|
|||
start++;
|
||||
} else if (r == ARG_IGNORE) {
|
||||
goto exit;
|
||||
} else if (r == ARG_INVALID) {
|
||||
error("invalid argument %s", argv[current]);
|
||||
}
|
||||
} else {
|
||||
if (short_arg == NULL) {
|
||||
|
@ -208,6 +243,8 @@ int parse_args(int argc, char** argv, void (*help)(void), int (*short_arg)(char,
|
|||
start++;
|
||||
} else if (r == ARG_IGNORE) {
|
||||
goto exit;
|
||||
} else if (r == ARG_INVALID) {
|
||||
error("invalid argument -%c", argv[current][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,7 +257,7 @@ exit:
|
|||
|
||||
int get_tty() {
|
||||
int fd = open(_PATH_TTY, O_RDONLY);
|
||||
if (fd < 0) error("error: failed to get tty: %s", strerror(errno));
|
||||
if (fd < 0) error("failed to get tty: %s", strerror(errno));
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -228,11 +265,27 @@ FILE* get_tty_stream(char* type) {
|
|||
int fd = get_tty();
|
||||
FILE* file = fdopen(fd, type);
|
||||
if (file == NULL) {
|
||||
error("error: failed to open tty stream: %s", strerror(errno));
|
||||
error("failed to open tty stream: %s", strerror(errno));
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
static int push_path_buffer_b(char* buf, int* index, const char* string) {
|
||||
int save = *index;
|
||||
if (*index > 1 || (*index == 1 && buf[0] != '/')) {
|
||||
buf[(*index)++] = '/';
|
||||
}
|
||||
int string_len = strlen(string);
|
||||
memcpy(buf + *index, string, string_len + 1);
|
||||
*index += string_len;
|
||||
return save;
|
||||
}
|
||||
|
||||
static void pop_path_buffer_b(char* buf, int* index, int i) {
|
||||
*index = i;
|
||||
buf[*index] = '\0';
|
||||
}
|
||||
|
||||
static char path_buffer[PATH_MAX + 1];
|
||||
static int path_buffer_index = 0;
|
||||
|
||||
|
@ -241,17 +294,28 @@ char* get_path_buffer() {
|
|||
}
|
||||
|
||||
int push_path_buffer(const char* string) {
|
||||
int save = path_buffer_index;
|
||||
if (path_buffer_index > 1 || (path_buffer_index == 1 && path_buffer[0] != '/')) {
|
||||
path_buffer[path_buffer_index++] = '/';
|
||||
}
|
||||
int string_len = strlen(string);
|
||||
memcpy(path_buffer + path_buffer_index, string, string_len + 1);
|
||||
path_buffer_index += string_len;
|
||||
return save;
|
||||
return push_path_buffer_b(path_buffer, &path_buffer_index, string);
|
||||
}
|
||||
|
||||
void pop_path_buffer(int i) {
|
||||
path_buffer_index = i;
|
||||
path_buffer[path_buffer_index] = '\0';
|
||||
pop_path_buffer_b(path_buffer, &path_buffer_index, i);
|
||||
}
|
||||
|
||||
static char path_buffer_2[PATH_MAX + 1];
|
||||
static int path_buffer_index_2 = 0;
|
||||
|
||||
char* get_path_buffer_2() {
|
||||
return path_buffer_2;
|
||||
}
|
||||
|
||||
int push_path_buffer_2(const char* string) {
|
||||
return push_path_buffer_b(path_buffer_2, &path_buffer_index_2, string);
|
||||
}
|
||||
|
||||
void pop_path_buffer_2(int i) {
|
||||
pop_path_buffer_b(path_buffer_2, &path_buffer_index_2, i);
|
||||
}
|
||||
|
||||
bool is_dot_dir(const char* path) {
|
||||
return streql(path, ".") || streql(path, "..");
|
||||
}
|
||||
|
|
|
@ -32,13 +32,20 @@ enum When {
|
|||
AUTO
|
||||
};
|
||||
|
||||
__attribute__ ((__format__(printf, 1, 2)))
|
||||
void error_s(const char* format, ...);
|
||||
|
||||
__attribute__ ((__format__(printf, 1, 2)))
|
||||
void error(const char* format, ...);
|
||||
|
||||
__attribute__ ((__format__(printf, 1, 2)))
|
||||
void output(const char* format, ...);
|
||||
|
||||
FILE* get_file_s(const char* path, const char* type);
|
||||
FILE* get_file(const char* path, const char* type);
|
||||
long int get_number(const char* text);
|
||||
long int get_blkm(const char* text);
|
||||
mode_t get_mode(const char* next);
|
||||
|
||||
bool streql(const char* a, const char* b);
|
||||
bool prefix(const char* pre, const char* str);
|
||||
|
@ -50,8 +57,10 @@ void print_date_time(time_t mills, char buf[13]);
|
|||
#define ARG_UNUSED 0
|
||||
#define ARG_USED 1
|
||||
#define ARG_IGNORE 2
|
||||
#define ARG_INVALID 3
|
||||
|
||||
void check_arg (char* arg);
|
||||
void global_help(void (*help)(void));
|
||||
void parse_help (int argc, char** argv, void (*help)(void));
|
||||
int parse_args (int argc, char** argv, void (*help)(void), int (*short_arg)(char, char*), int (*long_arg)(char*, char*));
|
||||
|
||||
|
@ -62,3 +71,8 @@ char* get_path_buffer();
|
|||
int push_path_buffer(const char* string);
|
||||
void pop_path_buffer(int i);
|
||||
|
||||
char* get_path_buffer_2();
|
||||
int push_path_buffer_2(const char* string);
|
||||
void pop_path_buffer_2(int i);
|
||||
|
||||
bool is_dot_dir(const char* path);
|
||||
|
|
Loading…
Reference in a new issue