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 += -D_DEFAULT_SOURCE -DMAJOR=$(MAJOR) -DMINOR=$(MINOR) -DPATCH=$(PATCH) -DCHECK_LINK
|
||||||
CCFLAGS += $(INCFLAGS)
|
CCFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
|
LDFLAGS = -s
|
||||||
LDFLAGS += $(INCFLAGS)
|
LDFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
BIN = bin
|
BIN = bin
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
A terrible busybox/gnu coreutils clone.
|
A terrible busybox/gnu coreutils clone.
|
||||||
|
|
||||||
Currently the only supported commands are:
|
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
|
## How to
|
||||||
|
|
||||||
|
|
|
@ -33,3 +33,7 @@ COMMAND(whoami);
|
||||||
COMMAND(wc);
|
COMMAND(wc);
|
||||||
COMMAND(xargs);
|
COMMAND(xargs);
|
||||||
COMMAND(tac);
|
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;
|
flags.end_lines_dollar = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("error: unkown flag -%c", c);
|
return ARG_INVALID;
|
||||||
}
|
}
|
||||||
return ARG_UNUSED;
|
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;
|
char* str = argv[i] + 3;
|
||||||
bs = get_number(str);
|
bs = get_number(str);
|
||||||
if (bs < 1) {
|
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])) {
|
} else if (prefix("count=", argv[i])) {
|
||||||
char* str = argv[i] + 6;
|
char* str = argv[i] + 6;
|
||||||
count = get_number(str);
|
count = get_number(str);
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
error("error: count must be greather than 0");
|
error("count must be greather than 0");
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
while(true) {
|
||||||
c = *(index++);
|
c = *(index++);
|
||||||
if (c == '\0') {
|
if (c == '\0') {
|
||||||
fprintf(stderr, "error: missing regex after %c\n", dir == BEFORE ? '?' : '/');
|
error_s("missing regex after %c\n", dir == BEFORE ? '?' : '/');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (c == (dir == BEFORE ? '?' : '/')) {
|
if (c == (dir == BEFORE ? '?' : '/')) {
|
||||||
|
@ -170,7 +170,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
||||||
n_pre = -1;
|
n_pre = -1;
|
||||||
} else {
|
} else {
|
||||||
if (n_pre < 0) {
|
if (n_pre < 0) {
|
||||||
fprintf(stderr, "error: input cannot be negative\n");
|
error_s("input cannot be negative\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
index = end_pre;
|
index = end_pre;
|
||||||
|
@ -192,7 +192,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
||||||
char* end;
|
char* end;
|
||||||
long int n = strtol(index, &end, 10) - 1;
|
long int n = strtol(index, &end, 10) - 1;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
fprintf(stderr, "error: input cannot be negative\n");
|
error_s("input cannot be negative\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (index == end) {
|
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;
|
address.data.index.i = line_current - n;
|
||||||
}
|
}
|
||||||
if (address.data.index.i < 0) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -211,7 +211,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
||||||
char* end;
|
char* end;
|
||||||
long int n = strtol(index, &end, 10) - 1;
|
long int n = strtol(index, &end, 10) - 1;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
fprintf(stderr, "error: input cannot be negative\n");
|
error_s("input cannot be negative\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (index == end) {
|
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;
|
address.data.index.i = line_current + n;
|
||||||
}
|
}
|
||||||
if (address.data.index.i >= (long int) line_count) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -256,7 +256,7 @@ static bool read_address(char** command, bool whitespace, struct LineAddress* a)
|
||||||
address.data.index.i = n_pre;
|
address.data.index.i = n_pre;
|
||||||
}
|
}
|
||||||
if (address.data.index.i < 0 || address.data.index.i >= (long int) line_count) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,7 +404,7 @@ static void delete_lines(unsigned long a, unsigned long b) {
|
||||||
|
|
||||||
static bool handle_append(struct LineAddress* address) {
|
static bool handle_append(struct LineAddress* address) {
|
||||||
if (address->type != INDEX) {
|
if (address->type != INDEX) {
|
||||||
fprintf(stderr, "error: append command requires index addressing\n");
|
error_s("append command requires index addressing\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (line_count == 0) {
|
if (line_count == 0) {
|
||||||
|
@ -424,20 +424,20 @@ static bool handle_append(struct LineAddress* address) {
|
||||||
|
|
||||||
static bool handle_delete(struct LineAddress* address) {
|
static bool handle_delete(struct LineAddress* address) {
|
||||||
if (address->empty && address->data.index.i >= (long int) line_count) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
if (address->type == INDEX) {
|
if (address->type == INDEX) {
|
||||||
delete_lines(address->data.index.i, address->data.index.i);
|
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) {
|
} else if (address->type == RANGE) {
|
||||||
delete_lines(address->data.range.a, address->data.range.b);
|
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) {
|
} else if (address->type == SET) {
|
||||||
for (unsigned long i = 0; i < address->data.set.s; i++) {
|
for (unsigned long i = 0; i < address->data.set.s; i++) {
|
||||||
delete_lines(address->data.set.b[i], address->data.set.b[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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,7 @@ static bool get_file_name(char** filename) {
|
||||||
size_t len = strlen(*filename);
|
size_t len = strlen(*filename);
|
||||||
if (len < 1 || (len == 1 && **filename == '\n')) {
|
if (len < 1 || (len == 1 && **filename == '\n')) {
|
||||||
if (default_filename == NULL) {
|
if (default_filename == NULL) {
|
||||||
fprintf(stderr, "error: no default filename specified\n");
|
error_s("no default filename specified\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*filename = default_filename;
|
*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) {
|
static void write_file(char* filename, struct LineAddress* address, char* type) {
|
||||||
if (line_count < 1) {
|
if (line_count < 1) {
|
||||||
fprintf(stderr, "error: cannot write empty file\n");
|
error_s("cannot write empty file\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!get_file_name(&filename)) 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;
|
pending_writes = false;
|
||||||
fclose(file);
|
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) {
|
static void read_file(char* filename) {
|
||||||
|
@ -512,7 +512,7 @@ static void read_file(char* filename) {
|
||||||
|
|
||||||
if (size < 1) {
|
if (size < 1) {
|
||||||
free(buf);
|
free(buf);
|
||||||
fprintf(stderr, "error: attempted to read a empty file\n");
|
error_s("attempted to read a empty file\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ static void read_file(char* filename) {
|
||||||
}
|
}
|
||||||
append_lines(line, buf, size);
|
append_lines(line, buf, size);
|
||||||
free(buf);
|
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) {
|
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 (cmd == ',') {
|
||||||
if (address.type != INDEX) {
|
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);
|
free_address(address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -593,7 +593,7 @@ static void prompt(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (address2.type != INDEX) {
|
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(address);
|
||||||
free_address(address2);
|
free_address(address2);
|
||||||
return;
|
return;
|
||||||
|
@ -606,7 +606,7 @@ static void prompt(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address.type == RANGE && address.data.range.a > address.data.range.b) {
|
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);
|
free_address(address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -618,10 +618,10 @@ test:
|
||||||
case '\n':
|
case '\n':
|
||||||
if (address.empty) {
|
if (address.empty) {
|
||||||
if (line_current == line_count) {
|
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;
|
break;
|
||||||
} else if (line_current + 1 == line_count) {
|
} 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;
|
break;
|
||||||
} else {
|
} else {
|
||||||
line_current++;
|
line_current++;
|
||||||
|
@ -634,7 +634,7 @@ test:
|
||||||
} else if (address.type == RANGE) {
|
} else if (address.type == RANGE) {
|
||||||
line_current = address.data.range.b;
|
line_current = address.data.range.b;
|
||||||
} else if (address.type == SET) {
|
} else if (address.type == SET) {
|
||||||
fprintf(stderr, "error: unexpected range addressing\n");
|
error_s("unexpected range addressing\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
printf("%s", lines[line_current]);
|
printf("%s", lines[line_current]);
|
||||||
|
@ -656,7 +656,7 @@ test:
|
||||||
__attribute__((fallthrough));
|
__attribute__((fallthrough));
|
||||||
case 'p':
|
case 'p':
|
||||||
if (address.empty && address.data.index.i >= (long int) line_count) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (address.type == INDEX) {
|
if (address.type == INDEX) {
|
||||||
|
@ -686,7 +686,7 @@ test:
|
||||||
skip_whitespace(&index);
|
skip_whitespace(&index);
|
||||||
free_address(address);
|
free_address(address);
|
||||||
if (*(index++) != '/') {
|
if (*(index++) != '/') {
|
||||||
fprintf(stderr, "error: unexpected character at start of regex\n");
|
error_s("unexpected character at start of regex\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!parse_regex(&index, &address, ALL)) { return; }
|
if (!parse_regex(&index, &address, ALL)) { return; }
|
||||||
|
@ -701,18 +701,18 @@ test:
|
||||||
case 's':
|
case 's':
|
||||||
skip_whitespace(&index);
|
skip_whitespace(&index);
|
||||||
if (*(index++) != '/') {
|
if (*(index++) != '/') {
|
||||||
fprintf(stderr, "error: unexpected character at start of regex\n");
|
error_s("unexpected character at start of regex\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!parse_regex_lines(&index, &address)) { return; }
|
if (!parse_regex_lines(&index, &address)) { return; }
|
||||||
char* replace = index;
|
char* replace = index;
|
||||||
while(*index != '\0' && *index != '/') index++;
|
while(*index != '\0' && *index != '/') index++;
|
||||||
if (*index != '/') {
|
if (*index != '/') {
|
||||||
fprintf(stderr, "error: / missing after %c\n", *index);
|
error_s("/ missing after %c\n", *index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (address.data.set.s < 1) {
|
if (address.data.set.s < 1) {
|
||||||
printf("ed: no matches found\n");
|
error_s("no matches found\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*(index++) = '\0';
|
*(index++) = '\0';
|
||||||
|
@ -725,11 +725,11 @@ test:
|
||||||
char* end;
|
char* end;
|
||||||
matches = strtol(index, &end, 10);
|
matches = strtol(index, &end, 10);
|
||||||
if (end == index) {
|
if (end == index) {
|
||||||
fprintf(stderr, "error: invalid number: %s\n", index);
|
error_s("invalid number: %s\n", index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (matches < 1) {
|
if (matches < 1) {
|
||||||
fprintf(stderr, "error: matches cannot be less than 1\n");
|
error_s("matches cannot be less than 1\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -739,7 +739,7 @@ test:
|
||||||
for (unsigned long i = 0; i < address.data.set.s; i++) {
|
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);
|
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;
|
pending_writes = true;
|
||||||
break;
|
break;
|
||||||
case 'w': {
|
case 'w': {
|
||||||
|
@ -782,7 +782,7 @@ test:
|
||||||
printf("%ld\n", line_current + 1);
|
printf("%ld\n", line_current + 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "error: unimplemented command\n");
|
error_s("unimplemented command\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ COMMAND_EMPTY(groups) {
|
||||||
|
|
||||||
struct passwd* pw = getpwuid(uid);
|
struct passwd* pw = getpwuid(uid);
|
||||||
if(pw == NULL){
|
if(pw == NULL){
|
||||||
perror("error: failed to fetch groups: ");
|
error("failed to fetch groups: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
int ngroups = 0;
|
int ngroups = 0;
|
||||||
|
@ -21,7 +21,7 @@ COMMAND_EMPTY(groups) {
|
||||||
for (int i = 0; i < ngroups; i++){
|
for (int i = 0; i < ngroups; i++){
|
||||||
struct group* gr = getgrgid(groups[i]);
|
struct group* gr = getgrgid(groups[i]);
|
||||||
if(gr == NULL){
|
if(gr == NULL){
|
||||||
perror("error: failed to fetch groups: ");
|
error("failed to fetch groups: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
printf("%s ",gr->gr_name);
|
printf("%s ",gr->gr_name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ static int short_arg(char c, char* next) {
|
||||||
check_arg(next);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(next);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
return ARG_USED;
|
return ARG_USED;
|
||||||
|
@ -80,7 +80,7 @@ static int short_arg(char c, char* next) {
|
||||||
check_arg(next);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(next);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
return ARG_USED;
|
return ARG_USED;
|
||||||
|
@ -91,9 +91,8 @@ static int short_arg(char c, char* next) {
|
||||||
case 'v':
|
case 'v':
|
||||||
flags.print_headers = true;
|
flags.print_headers = true;
|
||||||
break;
|
break;
|
||||||
default: {
|
default:
|
||||||
error("error: unknown option -%c", c);
|
return ARG_INVALID;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ARG_UNUSED;
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ COMMAND_EMPTY(user_id) {
|
||||||
|
|
||||||
struct passwd* pw = getpwuid(uid);
|
struct passwd* pw = getpwuid(uid);
|
||||||
if(pw == NULL){
|
if(pw == NULL){
|
||||||
perror("error: failed to fetch groups: ");
|
error("failed to fetch groups: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
int ngroups = 0;
|
int ngroups = 0;
|
||||||
|
@ -30,7 +30,7 @@ COMMAND_EMPTY(user_id) {
|
||||||
for (int i = 0; i < ngroups; i++){
|
for (int i = 0; i < ngroups; i++){
|
||||||
struct group* gr = getgrgid(groups[i]);
|
struct group* gr = getgrgid(groups[i]);
|
||||||
if(gr == NULL){
|
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);
|
printf("%d(%s)", gr->gr_gid, gr->gr_name);
|
||||||
if (i + 1 < ngroups) putchar(',');
|
if (i + 1 < ngroups) putchar(',');
|
||||||
|
|
|
@ -55,9 +55,9 @@ static DIR* get_directory(char* path) {
|
||||||
DIR* d = opendir(path);
|
DIR* d = opendir(path);
|
||||||
if (d == NULL) {
|
if (d == NULL) {
|
||||||
if (errno == ENOTDIR) {
|
if (errno == ENOTDIR) {
|
||||||
printf("\x1b[0m%s is a a file\n", path);
|
error_s("`%s` is a a file\n", path);
|
||||||
} else {
|
} 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;
|
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);
|
int save = push_path_buffer(file_name);
|
||||||
|
|
||||||
if (lstat(get_path_buffer(), &s) < 0) {
|
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);
|
pop_path_buffer(save);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -156,14 +156,14 @@ static bool get_file_info(const char* file_name, struct FileInfo* info) {
|
||||||
|
|
||||||
info->usr = getpwuid(s.st_uid);
|
info->usr = getpwuid(s.st_uid);
|
||||||
if (info->usr == NULL) {
|
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);
|
pop_path_buffer(save);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->grp = getgrgid(s.st_gid);
|
info->grp = getgrgid(s.st_gid);
|
||||||
if (info->grp == NULL) {
|
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);
|
pop_path_buffer(save);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -288,10 +288,6 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo
|
||||||
if (!flags.more_info) printf("\n");
|
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) {
|
static int num_places (int n) {
|
||||||
int r = 1;
|
int r = 1;
|
||||||
if (n < 0) n = (n == INT_MIN) ? INT_MAX: -n;
|
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;
|
flags.more_info = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("error: unkown option -%c", c);
|
return ARG_INVALID;
|
||||||
}
|
}
|
||||||
return ARG_UNUSED;
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
@ -481,7 +477,7 @@ static int long_arg(char* cur, char* next) {
|
||||||
} else if (streql("no", arg) || streql("never", arg)) {
|
} else if (streql("no", arg) || streql("never", arg)) {
|
||||||
flags.colored = NO;
|
flags.colored = NO;
|
||||||
} else {
|
} else {
|
||||||
error("error: invalid color options: %s", arg);
|
error("invalid color options: %s", arg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return ARG_IGNORE;
|
return ARG_IGNORE;
|
||||||
|
@ -496,7 +492,7 @@ COMMAND(ls) {
|
||||||
flags.hide_dot = false;
|
flags.hide_dot = false;
|
||||||
flags.one_column = false;
|
flags.one_column = false;
|
||||||
flags.recurse = false;
|
flags.recurse = false;
|
||||||
flags.colored = AUTO;
|
flags.colored = NO;
|
||||||
|
|
||||||
int start = parse_args(argc, argv, help, short_arg, long_arg);
|
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) {
|
COMMAND(print) {
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
error("usage: printf FORMAT [ARG]...\n");
|
global_help(help);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_help(argc, argv, help);
|
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);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(next);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
return ARG_USED;
|
return ARG_USED;
|
||||||
|
@ -141,7 +141,7 @@ static int short_arg(char c, char* next) {
|
||||||
check_arg(next);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(next);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
return ARG_USED;
|
return ARG_USED;
|
||||||
|
@ -159,14 +159,13 @@ static int short_arg(char c, char* next) {
|
||||||
check_arg(next);
|
check_arg(next);
|
||||||
long int sec = get_number(next);
|
long int sec = get_number(next);
|
||||||
if (sec < 1) {
|
if (sec < 1) {
|
||||||
error("error: wait seconds cannot be less than 1");
|
error("wait seconds cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.grow_wait = sec;
|
flags.grow_wait = sec;
|
||||||
return ARG_USED;
|
return ARG_USED;
|
||||||
}
|
}
|
||||||
default: {
|
default:
|
||||||
error("error: unknown option -%c", c);
|
return ARG_INVALID;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ARG_UNUSED;
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ static int short_arg(char c, char* next) {
|
||||||
flags.handle_sigint = true;
|
flags.handle_sigint = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("error: unkown option: %c", c);
|
return ARG_INVALID;
|
||||||
}
|
}
|
||||||
return ARG_UNUSED;
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ static int short_arg(char c, char* next) {
|
||||||
flags.longest_line = true;
|
flags.longest_line = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("error: invald option -%c", c);
|
return ARG_INVALID;
|
||||||
}
|
}
|
||||||
flags.has_flags = true;
|
flags.has_flags = true;
|
||||||
return ARG_UNUSED;
|
return ARG_UNUSED;
|
||||||
|
|
|
@ -45,10 +45,12 @@ static int short_arg(char c, char* next) {
|
||||||
check_arg(next);
|
check_arg(next);
|
||||||
long int n = get_number(next);
|
long int n = get_number(next);
|
||||||
if (n < 1) {
|
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;
|
flags.max_args = n;
|
||||||
return ARG_USED;
|
return ARG_USED;
|
||||||
|
default:
|
||||||
|
return ARG_INVALID;
|
||||||
}
|
}
|
||||||
return ARG_UNUSED;
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
21
src/main.c
21
src/main.c
|
@ -8,9 +8,12 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
char* cmd;
|
||||||
|
|
||||||
int main (ARGUMENTS) {
|
int main (ARGUMENTS) {
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
error("error: argument 0 missing");
|
fprintf(stderr, "fatal: argument 0 missing");
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CHECK_LINK
|
#ifdef CHECK_LINK
|
||||||
|
@ -21,7 +24,7 @@ int main (ARGUMENTS) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("usage: lazysphere [function [arguments]...]\n\n");
|
printf("usage: lazysphere [function [arguments]...]\n\n");
|
||||||
printf("currently defined functions:\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;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
argc--;
|
argc--;
|
||||||
|
@ -29,7 +32,6 @@ int main (ARGUMENTS) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char* cmd;
|
|
||||||
if (strncmp("./", argv[0], 2) == 0) {
|
if (strncmp("./", argv[0], 2) == 0) {
|
||||||
cmd = argv[0] + 2;
|
cmd = argv[0] + 2;
|
||||||
} else {
|
} else {
|
||||||
|
@ -52,6 +54,8 @@ int main (ARGUMENTS) {
|
||||||
return user_id();
|
return user_id();
|
||||||
} else if (streql(cmd, "ls") || streql(cmd, "dir")) {
|
} else if (streql(cmd, "ls") || streql(cmd, "dir")) {
|
||||||
return ls(NEXT_ARGS);
|
return ls(NEXT_ARGS);
|
||||||
|
} else if (streql(cmd, "lsd")) {
|
||||||
|
printf("look at all the funny colors\n");
|
||||||
} else if (streql(cmd, "tail")) {
|
} else if (streql(cmd, "tail")) {
|
||||||
return tail(NEXT_ARGS);
|
return tail(NEXT_ARGS);
|
||||||
} else if (streql(cmd, "head")) {
|
} else if (streql(cmd, "head")) {
|
||||||
|
@ -72,8 +76,17 @@ int main (ARGUMENTS) {
|
||||||
return xargs(NEXT_ARGS);
|
return xargs(NEXT_ARGS);
|
||||||
} else if (streql(cmd, "tac")) {
|
} else if (streql(cmd, "tac")) {
|
||||||
return tac(NEXT_ARGS);
|
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 {
|
} else {
|
||||||
error("error: invalid command %s", cmd);
|
fprintf(stderr, "lazysphere: invalid command %s", cmd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
@ -10,15 +11,36 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
|
||||||
void error(const char* format, ...) {
|
extern char* cmd;
|
||||||
|
|
||||||
|
void error_s(const char *format, ...) {
|
||||||
va_list list;
|
va_list list;
|
||||||
va_start(list, format);
|
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);
|
vfprintf(stderr, format, list);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
exit(EXIT_FAILURE);
|
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) {
|
FILE* get_file_s(const char* path, const char* type) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
if (streql("-", path) && type[0] == 'r') {
|
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 (lstat(path, &s) < 0) {
|
||||||
if (type[0] != 'r') goto read;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (S_ISDIR(s.st_mode)) {
|
if (S_ISDIR(s.st_mode)) {
|
||||||
fprintf(stderr, "error: %s is a directory\n", path);
|
error_s("%s is a directory", path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +62,7 @@ FILE* get_file_s(const char* path, const char* type) {
|
||||||
read:
|
read:
|
||||||
file = fopen(path, type);
|
file = fopen(path, type);
|
||||||
if (file == NULL) {
|
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;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +77,7 @@ long int get_number(const char* text) {
|
||||||
char* end;
|
char* end;
|
||||||
long int n = strtol(text, &end, 10);
|
long int n = strtol(text, &end, 10);
|
||||||
if (text == end) {
|
if (text == end) {
|
||||||
error("error: %s is not a valid number", text);
|
error("%s is not a valid number", text);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +86,7 @@ long int get_blkm(const char* text) {
|
||||||
char* end;
|
char* end;
|
||||||
long int n = strtol(text, &end, 10);
|
long int n = strtol(text, &end, 10);
|
||||||
if (text == end) {
|
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;
|
if (*end == '\0') return n;
|
||||||
switch (*end) {
|
switch (*end) {
|
||||||
|
@ -78,12 +100,23 @@ long int get_blkm(const char* text) {
|
||||||
case 'm':
|
case 'm':
|
||||||
return n * 1024 * 1204;
|
return n * 1024 * 1204;
|
||||||
default:
|
default:
|
||||||
error("error: invalid bkm type %c", *end);
|
error("invalid bkm type %c", *end);
|
||||||
}
|
}
|
||||||
// shouldnt get here anyways
|
// shouldnt get here anyways
|
||||||
return 0;
|
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) {
|
bool streql(const char* a, const char* b) {
|
||||||
if (*a != *b) return false;
|
if (*a != *b) return false;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
@ -151,11 +184,11 @@ void print_date_time(time_t mills, char buf[13]) {
|
||||||
|
|
||||||
void check_arg (char* arg) {
|
void check_arg (char* arg) {
|
||||||
if (arg == NULL) {
|
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);
|
printf("LazySphere v%d.%d.%d multi-call binary.\n\n", MAJOR, MINOR, PATCH);
|
||||||
help();
|
help();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
@ -196,6 +229,8 @@ int parse_args(int argc, char** argv, void (*help)(void), int (*short_arg)(char,
|
||||||
start++;
|
start++;
|
||||||
} else if (r == ARG_IGNORE) {
|
} else if (r == ARG_IGNORE) {
|
||||||
goto exit;
|
goto exit;
|
||||||
|
} else if (r == ARG_INVALID) {
|
||||||
|
error("invalid argument %s", argv[current]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (short_arg == NULL) {
|
if (short_arg == NULL) {
|
||||||
|
@ -208,6 +243,8 @@ int parse_args(int argc, char** argv, void (*help)(void), int (*short_arg)(char,
|
||||||
start++;
|
start++;
|
||||||
} else if (r == ARG_IGNORE) {
|
} else if (r == ARG_IGNORE) {
|
||||||
goto exit;
|
goto exit;
|
||||||
|
} else if (r == ARG_INVALID) {
|
||||||
|
error("invalid argument -%c", argv[current][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +257,7 @@ exit:
|
||||||
|
|
||||||
int get_tty() {
|
int get_tty() {
|
||||||
int fd = open(_PATH_TTY, O_RDONLY);
|
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;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,11 +265,27 @@ FILE* get_tty_stream(char* type) {
|
||||||
int fd = get_tty();
|
int fd = get_tty();
|
||||||
FILE* file = fdopen(fd, type);
|
FILE* file = fdopen(fd, type);
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
error("error: failed to open tty stream: %s", strerror(errno));
|
error("failed to open tty stream: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
return file;
|
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 char path_buffer[PATH_MAX + 1];
|
||||||
static int path_buffer_index = 0;
|
static int path_buffer_index = 0;
|
||||||
|
|
||||||
|
@ -241,17 +294,28 @@ char* get_path_buffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int push_path_buffer(const char* string) {
|
int push_path_buffer(const char* string) {
|
||||||
int save = path_buffer_index;
|
return push_path_buffer_b(path_buffer, &path_buffer_index, string);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_path_buffer(int i) {
|
void pop_path_buffer(int i) {
|
||||||
path_buffer_index = i;
|
pop_path_buffer_b(path_buffer, &path_buffer_index, i);
|
||||||
path_buffer[path_buffer_index] = '\0';
|
}
|
||||||
|
|
||||||
|
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
|
AUTO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
__attribute__ ((__format__(printf, 1, 2)))
|
||||||
|
void error_s(const char* format, ...);
|
||||||
|
|
||||||
__attribute__ ((__format__(printf, 1, 2)))
|
__attribute__ ((__format__(printf, 1, 2)))
|
||||||
void error(const char* format, ...);
|
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_s(const char* path, const char* type);
|
||||||
FILE* get_file(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_number(const char* text);
|
||||||
long int get_blkm(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 streql(const char* a, const char* b);
|
||||||
bool prefix(const char* pre, const char* str);
|
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_UNUSED 0
|
||||||
#define ARG_USED 1
|
#define ARG_USED 1
|
||||||
#define ARG_IGNORE 2
|
#define ARG_IGNORE 2
|
||||||
|
#define ARG_INVALID 3
|
||||||
|
|
||||||
void check_arg (char* arg);
|
void check_arg (char* arg);
|
||||||
|
void global_help(void (*help)(void));
|
||||||
void parse_help (int argc, char** argv, 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*));
|
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);
|
int push_path_buffer(const char* string);
|
||||||
void pop_path_buffer(int i);
|
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