fixed
This commit is contained in:
parent
ea0004c11f
commit
2980f205df
@ -5,8 +5,9 @@ License: wtfpl
|
||||
https://trivial.technology/
|
||||
|
||||
Unportable:
|
||||
proc_parser
|
||||
proc_parser.h
|
||||
ps
|
||||
kill
|
||||
dmesg
|
||||
mount
|
||||
umount
|
||||
|
60
TODO
60
TODO
@ -1,55 +1,33 @@
|
||||
With "micro-" prefix
|
||||
|
||||
*Todo:
|
||||
tail
|
||||
expr
|
||||
uniq
|
||||
od
|
||||
tr
|
||||
cut
|
||||
shuf
|
||||
stty
|
||||
sort
|
||||
test
|
||||
tar
|
||||
sha*
|
||||
md5
|
||||
|
||||
Other:
|
||||
sysctl
|
||||
ping
|
||||
ncat
|
||||
ntpd
|
||||
ifconfig
|
||||
dhcp-client
|
||||
getopt
|
||||
fdisk
|
||||
less
|
||||
free
|
||||
swapon
|
||||
swapoff
|
||||
hexdump
|
||||
sed
|
||||
|
||||
Loginutils:
|
||||
usersctl
|
||||
getty
|
||||
|
||||
Modutils:
|
||||
insmod
|
||||
rmmod
|
||||
lsmod
|
||||
|
||||
Findutils:
|
||||
grep
|
||||
find
|
||||
|
||||
BUGS:
|
||||
ls (-l flag with long group/user name)
|
||||
xargs (getopt with glibc)
|
||||
sysctl
|
||||
ping
|
||||
ncat
|
||||
ntpd
|
||||
ifconfig
|
||||
ipconfig
|
||||
dhcp-client
|
||||
getopt
|
||||
fdisk
|
||||
less
|
||||
free
|
||||
sed
|
||||
usersctl
|
||||
getty
|
||||
insmod
|
||||
rmmod
|
||||
lsmod
|
||||
grep
|
||||
find
|
||||
|
||||
FIX:
|
||||
xargs (-d)
|
||||
echo (escape)
|
||||
que (unicode)
|
||||
ps (-o)
|
||||
|
4
build.sh
4
build.sh
@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
./clean.sh
|
||||
|
||||
if [ -z $CC ]; then
|
||||
CC="cc"
|
||||
@ -9,7 +8,8 @@ if [ -z $CFLAGS ]; then
|
||||
CFLAGS="-s -Os -Wextra -Wall -pedantic"
|
||||
fi
|
||||
|
||||
chmod +x ./libmu/build-libmu.sh
|
||||
chmod -v +x clean.sh ./scripts/build-box.sh ./libmu/build-libmu.sh
|
||||
./clean.sh
|
||||
./libmu/build-libmu.sh
|
||||
|
||||
if [[ $1 == "box" ]]; then
|
||||
|
@ -26,23 +26,6 @@
|
||||
#define MOUNT_OPT_SIZE 512
|
||||
#endif
|
||||
|
||||
#ifdef _LS_C
|
||||
/* colors for ls */
|
||||
#define LS_DIR_COLOR "\033[1;34m"
|
||||
#define LS_LINK_COLOR "\033[1;35m"
|
||||
#define LS_SOCK_COLOR "\033[35m"
|
||||
#define LS_FIFO_COLOR "\033[1;35m"
|
||||
#define LS_BLOCK_COLOR "\033[1;33m"
|
||||
#define LS_EXE_COLOR "\033[1;32m"
|
||||
#endif
|
||||
|
||||
#ifdef INIT
|
||||
/* Init scripts */
|
||||
char *INIT_POWEROFF[] = {"/etc/rc.poweroff", NULL};
|
||||
char *INIT_START[] = {"/etc/rc.init", NULL};
|
||||
#define INIT_MSG "Starting micro-init..."
|
||||
#endif
|
||||
|
||||
#ifdef _UNAME_C
|
||||
/* Os name for uname */
|
||||
/* #define OS_NAME "unknow" */
|
||||
|
@ -50,5 +50,5 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
EOF
|
||||
|
||||
echo $CFLAGS | xargs $CC -Iconfigs -Ilibmu mutils.c obj/*.o bin/*.c -o mutils
|
||||
echo $CFLAGS | xargs $CC -D_BOX -Iconfigs -Ilibmu mutils.c obj/*.o bin/*.c -o mutils
|
||||
echo $CFLAGS | xargs $CC -Iconfigs scripts/musuid.c -o musuid
|
||||
|
@ -32,7 +32,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("bdname [sd] [str]\n\t-s SFX Set suffix\n\t-d Use dirname instead of basename");
|
||||
puts("bdname [sd] [str]\n\t-s STR Set suffix\n\t-d Use dirname instead of basename");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
13
src/cat.c
13
src/cat.c
@ -31,21 +31,12 @@ static int cat(const char *path) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "")) != -1) {
|
||||
puts("cat [file1 file2...]");
|
||||
return 0;
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc == 0)
|
||||
if (argc == 1)
|
||||
return cat("-");
|
||||
|
||||
else {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < argc; i++)
|
||||
for (int i = 1; i < argc; i++)
|
||||
if (cat(argv[i]))
|
||||
ret = 1;
|
||||
|
||||
|
93
src/chgrp.c
93
src/chgrp.c
@ -1,93 +0,0 @@
|
||||
#include <grp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "make_path.h"
|
||||
#include "get_stat.h"
|
||||
#include "recurse.h"
|
||||
|
||||
static char r_flag;
|
||||
static char *f_flag = "chgrp";
|
||||
static char H_flag;
|
||||
static char v_flag;
|
||||
|
||||
static int change(const char *path, void *p) {
|
||||
struct group *grp = (struct group *)p;
|
||||
|
||||
struct stat stat_path;
|
||||
if (mu_get_stat(f_flag, path, &stat_path))
|
||||
return 1;
|
||||
|
||||
if (lchown(path, stat_path.st_uid, grp->gr_gid)) {
|
||||
if (f_flag)
|
||||
fprintf(stderr, "chgrp: %s: %s\n", path, strerror(errno));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (v_flag)
|
||||
printf("chgrp: %s: changed group to %s\n", path, grp->gr_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "RfHv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'R':
|
||||
r_flag = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
f_flag = NULL;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
H_flag = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
v_flag = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("chgrp [RfHv] [group] [file1 file2...]\n\t-H Symbolic link\n\t-R Recursive\n\t-f Silent\n\t-v Verbose");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc == 0) {
|
||||
fprintf(stderr, "chgrp: missing operand\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct group *grp = getgrnam(argv[0]);
|
||||
if (!grp) {
|
||||
if (f_flag)
|
||||
fprintf(stderr, "chgrp: unknow group\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (r_flag) {
|
||||
if (mu_recurse(f_flag, H_flag, argv[i], (void *)grp, change, change))
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
else
|
||||
ret = change(argv[i], grp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
64
src/chown.c
64
src/chown.c
@ -12,18 +12,26 @@
|
||||
#include "unused.h"
|
||||
|
||||
static char r_flag;
|
||||
static char *f_flag = "chown";
|
||||
static char *s_flag = "chown";
|
||||
static char H_flag;
|
||||
static char v_flag;
|
||||
static char g_flag;
|
||||
static int (*chown_func)(const char *pathname, uid_t owner, gid_t group);
|
||||
static long gid;
|
||||
static long uid;
|
||||
static long gid = -1;
|
||||
static long uid = -1;
|
||||
|
||||
static int change(const char *path, void *p) {
|
||||
char *name = (char *)p;
|
||||
|
||||
if (chown_func(path, uid, gid)) {
|
||||
if (f_flag)
|
||||
struct stat sb;
|
||||
if (mu_get_lstat(s_flag, path, &sb))
|
||||
return 1;
|
||||
|
||||
long gid_priv = (gid == -1) ? sb.st_gid : gid;
|
||||
long uid_priv = (uid == -1) ? sb.st_uid : uid;
|
||||
|
||||
if (chown_func(path, uid_priv, gid_priv)) {
|
||||
if (s_flag)
|
||||
fprintf(stderr, "chown: unable to chown %s: %s\n", path, strerror(errno));
|
||||
|
||||
return 1;
|
||||
@ -35,25 +43,31 @@ static int change(const char *path, void *p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_owner(const char *arg) {
|
||||
static void get_owner(char *arg) {
|
||||
char *group = strchr(arg, ':');
|
||||
char gg_flag = 1;
|
||||
char gu_flag = 1;
|
||||
|
||||
char g_flag = 1;
|
||||
char u_flag = 1;
|
||||
if (group == NULL) {
|
||||
if (g_flag)
|
||||
gu_flag = 0;
|
||||
|
||||
if (group == arg)
|
||||
u_flag = 0;
|
||||
else
|
||||
gg_flag = 0;
|
||||
}
|
||||
|
||||
else if (!group)
|
||||
g_flag = 0;
|
||||
|
||||
if (g_flag) {
|
||||
if (gg_flag) {
|
||||
if (g_flag == 0) {
|
||||
group[0] = '\0';
|
||||
group++;
|
||||
}
|
||||
|
||||
else
|
||||
group = arg;
|
||||
|
||||
struct group *grp = getgrnam(group);
|
||||
if (!grp) {
|
||||
if (f_flag)
|
||||
if (s_flag)
|
||||
fprintf(stderr, "chown: invalid group: %s\n", group);
|
||||
|
||||
exit(1);
|
||||
@ -62,10 +76,10 @@ static void get_owner(const char *arg) {
|
||||
gid = grp->gr_gid;
|
||||
}
|
||||
|
||||
if (u_flag) {
|
||||
if (gu_flag) {
|
||||
struct passwd *pwd = getpwnam(arg);
|
||||
if (!pwd) {
|
||||
if (f_flag)
|
||||
if (s_flag)
|
||||
fprintf(stderr, "chown: invalid user: %s\n", arg);
|
||||
|
||||
exit(1);
|
||||
@ -79,14 +93,14 @@ int main(int argc, char **argv) {
|
||||
chown_func = lchown;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "RfHv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "RsHvg")) != -1) {
|
||||
switch (opt) {
|
||||
case 'R':
|
||||
r_flag = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
f_flag = NULL;
|
||||
case 's':
|
||||
s_flag = NULL;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
@ -98,8 +112,12 @@ int main(int argc, char **argv) {
|
||||
v_flag = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
g_flag = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("chown [RfHf] USER[:[GRP]] [file1 file2...]\n\t-H Symbolic link\n\t-R Recursive\n\t-f Silent\n\t-v Verbose\n");
|
||||
puts("chown [RsHvg] USER[:[GRP]]/GRP [file1 file2...]\n\t-H Symbolic link\n\t-R Recursive\n\t-s Silent\n\t-v Verbose\n\t-g Change only group");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -112,14 +130,12 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
gid = -1;
|
||||
uid = -1;
|
||||
get_owner(argv[0]);
|
||||
|
||||
int ret = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (r_flag) {
|
||||
if (mu_recurse(f_flag, H_flag, argv[i], argv[0], change, change))
|
||||
if (mu_recurse(s_flag, H_flag, argv[i], argv[0], change, change))
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
|
@ -60,8 +60,6 @@ int main(int argc, char **argv) {
|
||||
if (write(STDOUT_FILENO, buf, n) != n)
|
||||
fprintf(stderr, "dmesg: %s\n", strerror(errno));
|
||||
|
||||
putchar('\n');
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
12
src/du.c
12
src/du.c
@ -12,6 +12,7 @@
|
||||
static char h_flag;
|
||||
static char s_flag;
|
||||
static char c_flag;
|
||||
static char a_flag;
|
||||
static off_t total;
|
||||
|
||||
static void print(off_t size, const char *filename) {
|
||||
@ -67,13 +68,16 @@ static off_t du(const char *path, int recurs_flag) {
|
||||
else if (!recurs_flag)
|
||||
print(sum, path);
|
||||
|
||||
else if (a_flag && !s_flag)
|
||||
print(sb.st_blocks, path);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "hsc")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "hsca")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
h_flag = 1;
|
||||
@ -87,8 +91,12 @@ int main(int argc, char **argv) {
|
||||
c_flag = 1;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
a_flag = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("du [hsc] [src1 src2...]\n\t-h Sizes in human readable format\n\t-s Display only a total for each argument\n\t-c produce a grand total");
|
||||
puts("du [hsca] [src1 src2...]\n\t-h Sizes in human readable format\n\t-s Display only a total for each argument\n\t-c produce a grand total\n\t-a Show file sizes too");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
19
src/head.c
19
src/head.c
@ -45,7 +45,6 @@ static int print(const char *file, FILE *fp, long lines, long bytes) {
|
||||
long lmax = 0;
|
||||
long bmax = 0;
|
||||
|
||||
/* Make buffer */
|
||||
size_t buf_size = 0;
|
||||
char *buf = malloc(1);
|
||||
if (buf == NULL) {
|
||||
@ -54,11 +53,8 @@ static int print(const char *file, FILE *fp, long lines, long bytes) {
|
||||
}
|
||||
|
||||
/* Fill buffer */
|
||||
while (1) {
|
||||
int c = getc(fp);
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
int c = 0;
|
||||
while ((c = getc(fp)) != EOF) {
|
||||
char *tmp = realloc(buf, buf_size + 2);
|
||||
if (tmp == NULL) {
|
||||
fprintf(stderr, "%s: realloc: %s\n", PROG_NAME, strerror(errno));
|
||||
@ -79,12 +75,7 @@ static int print(const char *file, FILE *fp, long lines, long bytes) {
|
||||
|
||||
/* Print buffer */
|
||||
for (size_t i = 0; i < buf_size; i++) {
|
||||
if (buf[i] == '\n')
|
||||
lcount++;
|
||||
|
||||
bcount++;
|
||||
|
||||
if ((c_flag && bmax - bcount < bytes) || (n_flag && lmax - lcount < lines))
|
||||
if ((c_flag && bmax - bcount <= bytes) || (n_flag && lmax - lcount <= lines))
|
||||
putchar(buf[i]);
|
||||
|
||||
else if (!_TAIL_C) {
|
||||
@ -92,6 +83,10 @@ static int print(const char *file, FILE *fp, long lines, long bytes) {
|
||||
if ((n_flag && lcount == lmax + lines) || (c_flag && bcount == bmax + bytes))
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf[i] == '\n')
|
||||
lcount++;
|
||||
bcount++;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
@ -30,10 +30,10 @@ static SIG signals[] = {
|
||||
{"ALRM", SIGALRM},
|
||||
{"TERM", SIGTERM},
|
||||
{"CHLD", SIGCHLD},
|
||||
{"STOP", SIGSTOP}
|
||||
{"STOP", SIGSTOP},
|
||||
{"WINCH", SIGWINCH}
|
||||
};
|
||||
|
||||
|
||||
static int parse_sig(char *arg) {
|
||||
int sig = atoi(arg);
|
||||
if (sig > 0 && sig <= NSIG)
|
||||
|
28
src/ls.c
28
src/ls.c
@ -24,7 +24,6 @@ static char O_flag;
|
||||
static char a_flag;
|
||||
static char l_flag;
|
||||
static char F_flag;
|
||||
static char c_flag;
|
||||
static char R_flag;
|
||||
static char d_flag;
|
||||
static char L_flag;
|
||||
@ -145,7 +144,6 @@ static char *get_date(const time_t mtime) {
|
||||
/* Print */
|
||||
static int print(const struct d_node *node) {
|
||||
char suf = ' ';
|
||||
char *color = "";
|
||||
|
||||
char *mode = mu_mode_2_str(node->stats.st_mode);
|
||||
if (S_ISDIR(node->stats.st_mode)) {
|
||||
@ -153,36 +151,28 @@ static int print(const struct d_node *node) {
|
||||
suf = '/';
|
||||
|
||||
mode[0] = 'd';
|
||||
color = LS_DIR_COLOR;
|
||||
}
|
||||
|
||||
else if (S_ISLNK(node->stats.st_mode)) {
|
||||
suf = '@';
|
||||
mode[0] = 'l';
|
||||
color = LS_LINK_COLOR;
|
||||
}
|
||||
|
||||
else if (S_ISSOCK(node->stats.st_mode)) {
|
||||
suf = '=';
|
||||
mode[0] = 's';
|
||||
color = LS_SOCK_COLOR;
|
||||
}
|
||||
|
||||
else if (S_ISBLK(node->stats.st_mode)) {
|
||||
else if (S_ISBLK(node->stats.st_mode))
|
||||
mode[0] = 'b';
|
||||
color = LS_BLOCK_COLOR;
|
||||
}
|
||||
|
||||
else if (S_ISFIFO(node->stats.st_mode)) {
|
||||
suf = '|';
|
||||
mode[0] = 'p';
|
||||
color = LS_FIFO_COLOR;
|
||||
}
|
||||
|
||||
else if ((node->stats.st_mode & S_IXUSR) || (node->stats.st_mode & S_IXGRP) || (node->stats.st_mode & S_IXOTH)) {
|
||||
else if ((node->stats.st_mode & S_IXUSR) || (node->stats.st_mode & S_IXGRP) || (node->stats.st_mode & S_IXOTH))
|
||||
suf = '*';
|
||||
color = LS_EXE_COLOR;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
if (i_flag)
|
||||
@ -214,15 +204,9 @@ static int print(const struct d_node *node) {
|
||||
ret += printf(" %4ju %4s %6s %10ld %s ", (uintmax_t)node->stats.st_nlink, pw->pw_name, gr->gr_name, node->stats.st_size, get_date(node->stats.st_mtime));
|
||||
}
|
||||
|
||||
if (c_flag && p_flag)
|
||||
printf("%s", color);
|
||||
|
||||
printf("%s", node->name);
|
||||
ret += mu_strlen(node->name);
|
||||
|
||||
if (c_flag && p_flag)
|
||||
printf("\033[0m");
|
||||
|
||||
if (F_flag)
|
||||
printf("%c", suf);
|
||||
|
||||
@ -410,7 +394,7 @@ static int ls_files(int argc, char **argv, const struct winsize w) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "1alFcRdLhistS0")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "1alFRdLhistS0")) != -1) {
|
||||
switch (opt) {
|
||||
case '1':
|
||||
O_flag = 1;
|
||||
@ -428,10 +412,6 @@ int main(int argc, char **argv) {
|
||||
F_flag = 1;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
c_flag = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
d_flag = 0;
|
||||
R_flag = 1;
|
||||
@ -471,7 +451,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("ls [1alFcRdLhistS0] [dir1 file2...]\n\t-a Show hidden files\n\t-l Use a long listing format\n\t-F Append indicator to names\n\t-c Color mode\n\t-R Recursive\n\t-1 One column\n\t-d Print only dir names\n\t-L Follow symlinks\n\t-h Sizes in human readable format\n\t-i Listen inodes\n\t-t Sort by mtime\n\t-S Sort by size\n\t-s Print file size\n\t-0 End line with \\0");
|
||||
puts("ls [1alFcRdLhistS0] [dir1 file2...]\n\t-a Show hidden files\n\t-l Use a long listing format\n\t-F Append indicator to names\n\t-R Recursive\n\t-1 One column\n\t-d Print only dir names\n\t-L Follow symlinks\n\t-h Sizes in human readable format\n\t-i Listen inodes\n\t-t Sort by mtime\n\t-S Sort by size\n\t-s Print file size\n\t-0 End line with \\0");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
619
src/que.c
619
src/que.c
@ -1,619 +0,0 @@
|
||||
/* Safe variant of kilo editor */
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define CTRL_KEY(k) ((k) & 0x1f)
|
||||
#define TAB_SIZE 8
|
||||
|
||||
static struct termios orig_termios;
|
||||
static struct winsize ws;
|
||||
|
||||
static char *scr_buf;
|
||||
static size_t scr_buf_size;
|
||||
|
||||
struct row {
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
||||
char *render;
|
||||
size_t rlen;
|
||||
};
|
||||
|
||||
static struct row *row_s;
|
||||
static size_t row_size;
|
||||
|
||||
/* Cursors */
|
||||
static unsigned int curx;
|
||||
static unsigned int cury;
|
||||
static unsigned int renx;
|
||||
|
||||
static unsigned int rowoff;
|
||||
static unsigned int coloff;
|
||||
|
||||
static char *file_path;
|
||||
|
||||
enum {
|
||||
FAILED_SAVE = 1,
|
||||
SUCCESS_SAVE
|
||||
};
|
||||
static char status_type;
|
||||
static char modified_flag;
|
||||
|
||||
/* Cleaners */
|
||||
static void bufFree(void) {
|
||||
if (scr_buf != NULL)
|
||||
free(scr_buf);
|
||||
|
||||
scr_buf = NULL;
|
||||
scr_buf_size = 0;
|
||||
}
|
||||
|
||||
static void fileBufFree(void) {
|
||||
if (row_s != NULL) {
|
||||
if (row_size > 0)
|
||||
for (size_t i = 0; i < row_size; i++) {
|
||||
if (row_s[i].buf)
|
||||
free(row_s[i].buf);
|
||||
|
||||
if (row_s[i].render)
|
||||
free(row_s[i].render);
|
||||
}
|
||||
|
||||
free(row_s);
|
||||
}
|
||||
|
||||
row_s = NULL;
|
||||
row_size = 0;
|
||||
}
|
||||
|
||||
static void die(int ret, char *msg) {
|
||||
write(STDOUT_FILENO, "\033[H\033[J", 6);
|
||||
|
||||
bufFree();
|
||||
fileBufFree();
|
||||
|
||||
if (msg != NULL)
|
||||
fprintf(stderr, "que: %s: %s\n", msg, strerror(errno));
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/* Save */
|
||||
static char *buf2str(size_t *len) {
|
||||
size_t totalen = 0;
|
||||
for (size_t i = 0; i < row_size; i++)
|
||||
totalen += row_s[i].len + 1;
|
||||
|
||||
*len = totalen;
|
||||
char *buf = malloc(totalen + 1);
|
||||
if (buf == NULL)
|
||||
die(1, "malloc in buf2str: Fatal error");
|
||||
|
||||
char *p = buf;
|
||||
for (size_t i = 0; i < row_size; i++) {
|
||||
memcpy(p, row_s[i].buf, row_s[i].len);
|
||||
|
||||
p += row_s[i].len;
|
||||
*p = '\n';
|
||||
p++;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void save(void) {
|
||||
size_t len = 0;
|
||||
char *buf = buf2str(&len);
|
||||
|
||||
int fd = open(file_path, O_RDWR, 0644);
|
||||
if (fd < 0)
|
||||
goto BAD_SAVE;
|
||||
|
||||
if (ftruncate(fd, len) < 0)
|
||||
goto BAD_SAVE;
|
||||
|
||||
ssize_t ret = write(fd, buf, len);
|
||||
if (ret == -1)
|
||||
goto BAD_SAVE;
|
||||
|
||||
else if ((size_t)ret != len)
|
||||
goto BAD_SAVE;
|
||||
|
||||
close(fd);
|
||||
free(buf);
|
||||
status_type = SUCCESS_SAVE;
|
||||
modified_flag = 0;
|
||||
return;
|
||||
|
||||
BAD_SAVE:
|
||||
free(buf);
|
||||
status_type = FAILED_SAVE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Funcs */
|
||||
static void bufAppend(const char *str, const size_t len) {
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
char *buf = NULL;
|
||||
if (scr_buf_size == 0 || scr_buf == NULL)
|
||||
buf = malloc(len);
|
||||
|
||||
else
|
||||
buf = realloc(scr_buf, scr_buf_size + len);
|
||||
|
||||
if (buf == NULL) {
|
||||
if (scr_buf)
|
||||
free(scr_buf);
|
||||
|
||||
scr_buf_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
scr_buf = buf;
|
||||
|
||||
memcpy(&scr_buf[scr_buf_size], str, len);
|
||||
scr_buf_size += len;
|
||||
}
|
||||
|
||||
static int updateRenderStr(const unsigned int row) {
|
||||
int tabs = 0;
|
||||
for (size_t i = 0; i < row_s[row].len; i++)
|
||||
if (row_s[row].buf[i] == '\t')
|
||||
tabs++;
|
||||
|
||||
if (row_s[row].render)
|
||||
free(row_s[row].render);
|
||||
|
||||
char *buf = malloc(row_s[row].len + tabs * TAB_SIZE + 1);
|
||||
if (buf == NULL)
|
||||
return 1;
|
||||
row_s[row].render = buf;
|
||||
|
||||
int j = 0;
|
||||
for (size_t i = 0; i < row_s[row].len; i++) {
|
||||
if (row_s[row].buf[i] == '\t') {
|
||||
row_s[row].render[j++] = ' ';
|
||||
while (j % TAB_SIZE != 0)
|
||||
row_s[row].render[j++] = ' ';
|
||||
}
|
||||
|
||||
else
|
||||
row_s[row].render[j++] = row_s[row].buf[i];
|
||||
}
|
||||
|
||||
row_s[row].render[j] = '\0';
|
||||
row_s[row].rlen = j;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int addRow(const unsigned int at, const char *buf, const size_t len) {
|
||||
struct row *row_s2 = realloc(row_s, sizeof(struct row) * (row_size + 1));
|
||||
if (row_s2 == NULL)
|
||||
return 1;
|
||||
row_s = row_s2;
|
||||
|
||||
memmove(&row_s[at + 1], &row_s[at], sizeof(struct row) * (row_size - at));
|
||||
|
||||
char *buf2 = malloc(len + 1);
|
||||
if (buf2 == NULL)
|
||||
return 1;
|
||||
row_s[at].buf = buf2;
|
||||
|
||||
memcpy(row_s[at].buf, buf, len);
|
||||
row_s[at].len = len;
|
||||
row_s[at].buf[len] = '\0';
|
||||
|
||||
row_s[at].render = NULL;
|
||||
if (updateRenderStr(at))
|
||||
return 1;
|
||||
|
||||
row_size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void readFile(const char *path) {
|
||||
row_s = malloc(sizeof(struct row));
|
||||
if (row_s == NULL)
|
||||
die(1, "malloc in readFIle");
|
||||
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (fp == NULL)
|
||||
die(1, "fopen in readFile");
|
||||
|
||||
char *buf = NULL;
|
||||
size_t n = 0;
|
||||
ssize_t len = 0;
|
||||
while ((len = getline(&buf, &n, fp)) != -1) {
|
||||
while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
|
||||
len--;
|
||||
|
||||
if (addRow(row_size, buf, len)) {
|
||||
fclose(fp);
|
||||
free(buf);
|
||||
die(1, "addRow in readFile");
|
||||
}
|
||||
}
|
||||
|
||||
if (buf)
|
||||
free(buf);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void insertChar(char c) {
|
||||
if ((size_t)cury == row_size) {
|
||||
if (addRow(row_size, "", 0)) {
|
||||
save();
|
||||
die(1, "addRow in insertChar: Fatal error");
|
||||
}
|
||||
}
|
||||
|
||||
size_t i = (size_t)curx;
|
||||
if (i > row_s[cury].len)
|
||||
i = row_s[cury].len;
|
||||
|
||||
char *buf = realloc(row_s[cury].buf, row_s[cury].len + 2);
|
||||
if (buf == NULL) {
|
||||
save();
|
||||
die(1, "realloc in insertChar: Fatal error");
|
||||
}
|
||||
row_s[cury].buf = buf;
|
||||
|
||||
memmove(&row_s[cury].buf[i + 1], &row_s[cury].buf[i], row_s[cury].len - i + 1);
|
||||
|
||||
row_s[cury].len++;
|
||||
row_s[cury].buf[i] = c;
|
||||
if (updateRenderStr(cury)) {
|
||||
save();
|
||||
die(1, "updateRenderStr in insertChar: Fatal error");
|
||||
}
|
||||
|
||||
curx++;
|
||||
}
|
||||
|
||||
static void insertNewline(void) {
|
||||
if (curx == 0) {
|
||||
if (addRow(cury, "", 0)) {
|
||||
save();
|
||||
die(1, "addRow in insertNewline: Fatal error");
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (addRow(cury + 1, &row_s[cury].buf[curx], row_s[cury].len - curx)) {
|
||||
save();
|
||||
die(1, "addRow in insertNewline: Fatal error");
|
||||
}
|
||||
|
||||
/* Resize */
|
||||
row_s[cury].len = (size_t)curx;
|
||||
row_s[cury].buf[curx] = '\0';
|
||||
|
||||
char *buf = strdup(row_s[cury].buf);
|
||||
if (buf == NULL) {
|
||||
save();
|
||||
die(1, "strdup in insertNewline: Fatal error");
|
||||
}
|
||||
|
||||
free(row_s[cury].buf);
|
||||
row_s[cury].buf = buf;
|
||||
|
||||
if (updateRenderStr(cury)) {
|
||||
save();
|
||||
die(1, "updateRenderStr in insertNewline: Fatal error");
|
||||
}
|
||||
}
|
||||
|
||||
cury++;
|
||||
curx = 0;
|
||||
}
|
||||
|
||||
static void delChar(void) {
|
||||
if ((curx == 0 && cury == 0) || cury == (unsigned int)row_size)
|
||||
return;
|
||||
|
||||
else if (curx > 0) {
|
||||
if (curx - 1 >= (unsigned int)row_s[cury].len)
|
||||
return;
|
||||
|
||||
memmove(&row_s[cury].buf[curx - 1], &row_s[cury].buf[curx], row_s[cury].len - curx);
|
||||
|
||||
row_s[cury].len--;
|
||||
curx--;
|
||||
}
|
||||
|
||||
else {
|
||||
curx = (unsigned int)row_s[cury - 1].len;
|
||||
|
||||
char *buf = realloc(row_s[cury - 1].buf, row_s[cury - 1].len + row_s[cury].len + 1);
|
||||
if (buf == NULL) {
|
||||
save();
|
||||
die(1, "realloc in delChar: Fatal error");
|
||||
}
|
||||
row_s[cury - 1].buf = buf;
|
||||
|
||||
memcpy(&row_s[cury - 1].buf[row_s[cury - 1].len], row_s[cury].buf, row_s[cury].len);
|
||||
row_s[cury - 1].len += row_s[cury].len;
|
||||
row_s[cury - 1].buf[row_s[cury - 1].len] = '\0';
|
||||
|
||||
if (cury < (unsigned int)row_size) {
|
||||
free(row_s[cury].buf);
|
||||
free(row_s[cury].render);
|
||||
|
||||
memmove(&row_s[cury], &row_s[cury + 1], sizeof(struct row) * (row_size - cury - 1));
|
||||
struct row *buf2 = realloc(row_s, sizeof(struct row) * row_size - 1);
|
||||
if (buf == NULL) {
|
||||
save();
|
||||
die(1, "relloc in delChar: Fatal error");
|
||||
}
|
||||
|
||||
row_s = buf2;
|
||||
row_size--;
|
||||
}
|
||||
|
||||
cury--;
|
||||
}
|
||||
|
||||
if (updateRenderStr(cury)) {
|
||||
save();
|
||||
die(1, "updateRenderStr in delChar: Fatal error");
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminal */
|
||||
static void DRawMode(void) {
|
||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios) < 0)
|
||||
die(1, "tcsetattr");
|
||||
}
|
||||
|
||||
static void ERawMode(void) {
|
||||
if (tcgetattr(STDIN_FILENO, &orig_termios) < 0)
|
||||
die(1, "tcgetattr");
|
||||
|
||||
struct termios raw = orig_termios;
|
||||
raw.c_oflag &= ~(OPOST);
|
||||
raw.c_cflag |= (CS8);
|
||||
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
raw.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
|
||||
|
||||
raw.c_cc[VMIN] = 0;
|
||||
raw.c_cc[VTIME] = 1;
|
||||
|
||||
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) < 0)
|
||||
die(1, "tcsetattr");
|
||||
}
|
||||
|
||||
static void winsize(void) {
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0)
|
||||
die(1, "ioctl");
|
||||
|
||||
if (ws.ws_col == 0 || ws.ws_row <= 1)
|
||||
die(1, "winsize");
|
||||
|
||||
ws.ws_row--;
|
||||
}
|
||||
|
||||
static void statusBar(const char *path) {
|
||||
char info[124];
|
||||
int ret = 0;
|
||||
|
||||
if (status_type == 0)
|
||||
ret = snprintf(info, sizeof(info), "LINE: %u/%zu %s [%s]", cury + 1, row_size + 1, (modified_flag) ? "[modified]" : "", path);
|
||||
|
||||
else if (status_type == FAILED_SAVE)
|
||||
ret = snprintf(info, sizeof(info), "Failed save to %s: %s", path, strerror(errno));
|
||||
|
||||
else if (status_type == SUCCESS_SAVE)
|
||||
ret = snprintf(info, sizeof(info), "File %s success saved", path);
|
||||
|
||||
status_type = 0;
|
||||
bufAppend(info, ret);
|
||||
}
|
||||
|
||||
/* Keyboard */
|
||||
static char readkey(void) {
|
||||
char c;
|
||||
int ret;
|
||||
|
||||
while ((ret = read(STDIN_FILENO, &c, 1)) != 1) {
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
save();
|
||||
die(1, "read");
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void moveCursor(char c) {
|
||||
switch (c) {
|
||||
case 'A':
|
||||
if (cury != 0)
|
||||
cury--;
|
||||
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
if (cury < row_size)
|
||||
cury++;
|
||||
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
if (curx < row_s[cury].len)
|
||||
curx++;
|
||||
|
||||
else if (curx == row_s[cury].len) {
|
||||
cury++;
|
||||
curx = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if (curx != 0)
|
||||
curx--;
|
||||
|
||||
|
||||
else if (cury > 0) {
|
||||
cury--;
|
||||
curx = row_s[cury].len;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '5':
|
||||
if (readkey() == '~') {
|
||||
cury = rowoff;
|
||||
|
||||
size_t t = ws.ws_row;
|
||||
while (t--)
|
||||
if (cury != 0)
|
||||
moveCursor('A');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '6':
|
||||
if (readkey() == '~') {
|
||||
cury = rowoff + ws.ws_row + 1;
|
||||
|
||||
if (cury > (unsigned int)row_size)
|
||||
cury = row_size;
|
||||
|
||||
size_t t = ws.ws_row;
|
||||
while (t--)
|
||||
moveCursor('B');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
curx = 0;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
curx = row_s[cury].len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (curx > row_s[cury].len)
|
||||
curx = row_s[cury].len;
|
||||
}
|
||||
|
||||
static void keyboard(void) {
|
||||
char key = readkey();
|
||||
switch (key) {
|
||||
case '\033':
|
||||
if (readkey() != '[')
|
||||
break;
|
||||
|
||||
moveCursor(readkey());
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
modified_flag = 1;
|
||||
insertNewline();
|
||||
break;
|
||||
|
||||
case CTRL_KEY('q'):
|
||||
die(0, NULL);
|
||||
break;
|
||||
|
||||
case CTRL_KEY('s'):
|
||||
save();
|
||||
break;
|
||||
|
||||
case 127:
|
||||
case CTRL_KEY('h'):
|
||||
delChar();
|
||||
modified_flag = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
modified_flag = 1;
|
||||
insertChar(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
printf("que [file]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_path = argv[1];
|
||||
readFile(file_path);
|
||||
winsize();
|
||||
atexit(DRawMode);
|
||||
ERawMode();
|
||||
|
||||
while (1) {
|
||||
bufAppend("\033[H\033[J", 6);
|
||||
|
||||
renx = 0;
|
||||
|
||||
if (cury < row_size) {
|
||||
/* Buffer coord to Render buffer coord */
|
||||
for (unsigned int i = 0; i < curx; i++) {
|
||||
if (row_s[cury].buf[i] == '\t')
|
||||
renx += (TAB_SIZE - 1) - (renx % TAB_SIZE);
|
||||
|
||||
renx++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cury < rowoff)
|
||||
rowoff = cury;
|
||||
|
||||
else if (cury >= rowoff + ws.ws_row)
|
||||
rowoff = cury - ws.ws_row + 1;
|
||||
|
||||
if (renx < coloff)
|
||||
coloff = renx;
|
||||
|
||||
else if (renx >= coloff + ws.ws_col)
|
||||
coloff = renx - ws.ws_col + 1;
|
||||
|
||||
for (size_t i = 0; i < ws.ws_row; i++) {
|
||||
unsigned int row = rowoff + i;
|
||||
|
||||
if (row_size > row) {
|
||||
int len = row_s[row].rlen - coloff;
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
|
||||
else if (len > ws.ws_col)
|
||||
len = ws.ws_col;
|
||||
|
||||
bufAppend(&row_s[row].render[coloff], (size_t)len);
|
||||
}
|
||||
|
||||
bufAppend("\r\n", 2);
|
||||
}
|
||||
|
||||
statusBar(file_path);
|
||||
|
||||
char buf[32];
|
||||
int ret = snprintf(buf, sizeof(buf), "\033[%u;%uH", cury - rowoff + 1, renx - coloff + 1);
|
||||
bufAppend(buf, ret);
|
||||
|
||||
write(STDOUT_FILENO, scr_buf, scr_buf_size);
|
||||
bufFree();
|
||||
|
||||
keyboard();
|
||||
}
|
||||
}
|
@ -1,2 +1,6 @@
|
||||
#ifdef _BOX
|
||||
#define head_main tail_main
|
||||
#endif
|
||||
|
||||
#define _TAIL_C 1
|
||||
#include "head.c"
|
||||
|
@ -34,7 +34,7 @@ static int touch(const char *path, const time_t date) {
|
||||
if (!c_flag) {
|
||||
int fd = open(path, O_CREAT | O_RDONLY, 0666);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "touch: %s\n", strerror(errno));
|
||||
fprintf(stderr, "touch: %s: %s\n", path, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user