forked from bonsai/harakit
intcmp(1): new tool; npc(1): new tool; scrut(1): new tool; str(1): new tool; strcmp(1): new tool; tests: added POSIX compatibility test and C compiler compatibility test; Makefile: converted to GNUmakefile; README: added README; docs: added docs
This commit is contained in:
104
src/cat.c
104
src/cat.c
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This file is part of YAC coreutils.
|
||||
*
|
||||
* YAC coreutils is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* YAC coreutils is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "yac.h"
|
||||
|
||||
void cat(FILE *file, bool u) {
|
||||
int byte = 0; /* variable for storing bytes as they are read */
|
||||
int p = 0; /* index counter for bytes in buffered reading */
|
||||
char buf[4096]; /* buffer for buffered reading */
|
||||
|
||||
if (u) {
|
||||
while ((byte = fgetc(file)) != EOF) { putchar(byte); }
|
||||
} else {
|
||||
while ((byte = fgetc(file)) != EOF) {
|
||||
if (p > sizeof(buf) - 1) {
|
||||
fputs(buf, stdout);
|
||||
p = 0;
|
||||
} else {
|
||||
buf[p] = byte;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
fwrite(buf, 1, p, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool u = false;
|
||||
int opt;
|
||||
int i;
|
||||
|
||||
extern int optind;
|
||||
while ((opt = getopt(argc, argv, "u")) != -1) {
|
||||
switch (opt) {
|
||||
/*
|
||||
* From cat(1p):
|
||||
*
|
||||
* -u Write bytes from the input file to the standard output
|
||||
* without delay as each is read.
|
||||
*/
|
||||
case 'u':
|
||||
u = true;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: %s (-u) file...\n", argv[0]);
|
||||
return EX_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* From cat(1p):
|
||||
*
|
||||
* file A pathname of an input file. If no file operands are
|
||||
* specified, the standard input shall be used. If a file is
|
||||
* '-', the cat utility shall read from the standard input at
|
||||
* that point in the sequence. The cat utility shall not close
|
||||
* and reopen standard input when it is referenced in this way,
|
||||
* but shall accept multiple occurrences of '-' as a file
|
||||
* operand.
|
||||
*/
|
||||
|
||||
if (optind == argc) {
|
||||
cat(stdin, u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *file;
|
||||
|
||||
for (i = optind; i < argc; i++) {
|
||||
file = rpath(argv[0], argv[i]);
|
||||
if (file != NULL) {
|
||||
cat(file, u);
|
||||
if (file != stdin) { fclose(file); }
|
||||
} else { continue; }
|
||||
}
|
||||
|
||||
return EX_OK;
|
||||
}
|
||||
18
src/false.c
18
src/false.c
@@ -1,21 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* SPDX-License-Identifier: CC0
|
||||
*
|
||||
* This file is part of YAC coreutils.
|
||||
*
|
||||
* YAC coreutils is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* YAC coreutils is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
* This work is marked with CC0 1.0. To view a copy of this license, visit
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0>.
|
||||
*/
|
||||
|
||||
int main() { return 1; }
|
||||
|
||||
84
src/intcmp.c
Normal file
84
src/intcmp.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <errno.h> /* errno */
|
||||
#include <stdio.h> /* fprintf(3), stderr */
|
||||
#include <stdlib.h> /* strtol(3), size_t */
|
||||
#ifndef EX_USAGE
|
||||
# include <sysexits.h> /* EX_USAGE */
|
||||
#endif
|
||||
#include <unistd.h> /* getopt(3), optind */
|
||||
|
||||
/* 0b00? */ /* Equal | -e | 0b001 | 1 */
|
||||
#define EQUAL 0x01 /* Greater | -g | 0b010 | 2 */
|
||||
/* 0b0?0 */ /* Greater or Equal | -ge | 0b011 | 3 */
|
||||
#define GREATER 0x02 /* Less | -l | 0b100 | 4 */
|
||||
/* 0b?00 */ /* Less or Equal | -le | 0b101 | 5 */
|
||||
#define LESS 0x04 /* Inequal (Greater or Less) | -gl | 0b110 | 6 */
|
||||
|
||||
static char *program_name = "intcmp";
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
int c;
|
||||
size_t i;
|
||||
unsigned char mode;
|
||||
int r; /* reference integer */
|
||||
|
||||
mode = 0;
|
||||
|
||||
if(argc < 3)
|
||||
goto usage;
|
||||
|
||||
while((c = getopt(argc, argv, "egl")) != -1)
|
||||
switch(c){
|
||||
case 'e': mode |= EQUAL; break;
|
||||
case 'g': mode |= GREATER; break;
|
||||
case 'l': mode |= LESS; break;
|
||||
default: goto usage;
|
||||
}
|
||||
|
||||
if(optind + 2 /* ref cmp */ > argc){
|
||||
usage: fprintf(stderr,
|
||||
"Usage: %s (-eghl) [integer] [integer...]\n",
|
||||
argv[0] == NULL ? program_name : argv[0]);
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
i = optind;
|
||||
|
||||
do{ r = c;
|
||||
c = strtol(argv[i], &argv[i], 10);
|
||||
if(*argv[i] != '\0' || errno != 0){
|
||||
fprintf(stderr, "%s: argument #%d: Invalid integer\n",
|
||||
argv[0], (int)i);
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
if(i == optind)
|
||||
continue;
|
||||
|
||||
/* rule enforcement; if a mode isn't permitted and the numbers
|
||||
* correspond to it, return 1 */
|
||||
if( (!(mode & EQUAL) && r == c)
|
||||
|| (!(mode & GREATER) && r > c)
|
||||
|| (!(mode & LESS) && r < c))
|
||||
return 1;
|
||||
}while(++i < argc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
63
src/libfileis.c
Normal file
63
src/libfileis.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "libfileis.h"
|
||||
|
||||
#include <unistd.h> /* access(3), F_OK, R_OK, W_OK, X_OK */
|
||||
|
||||
int f_executable(char *path){ return access(path, X_OK) == 0; } /* test -x */
|
||||
int f_exists(char *path){ return access(path, F_OK) == 0; } /* test -e */
|
||||
int f_readable(char *path){ return access(path, R_OK) == 0; } /* test -r */
|
||||
int f_writeable(char *path){ return access(path, W_OK) == 0; } /* test -w */
|
||||
|
||||
#include <sys/stat.h> /* lstat(3), struct stat, S_ISBLK, S_ISCHR, S_ISDIR,
|
||||
* S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK,
|
||||
* S_ISUID, S_ISVTX */
|
||||
|
||||
static struct stat buf;
|
||||
|
||||
int f_blockspecial(char *path){ /* test -b */
|
||||
return lstat(path, &buf) != -1 && S_ISBLK(buf.st_mode);
|
||||
}
|
||||
int f_charspecial(char *path){ /* test -c */
|
||||
return lstat(path, &buf) != -1 && S_ISCHR(buf.st_mode);
|
||||
}
|
||||
int f_directory(char *path){ /* test -d */
|
||||
return lstat(path, &buf) != -1 && S_ISDIR(buf.st_mode);
|
||||
}
|
||||
int f_fifospecial(char *path){ /* test -p */
|
||||
return lstat(path, &buf) != -1 && S_ISFIFO(buf.st_mode);
|
||||
}
|
||||
int f_gid(char *path){ /* test -g */
|
||||
return lstat(path, &buf) != -1 && (buf.st_mode & S_ISGID);
|
||||
}
|
||||
int f_regular(char *path){ /* test -f */
|
||||
return lstat(path, &buf) != -1 && S_ISREG(buf.st_mode);
|
||||
}
|
||||
int f_socket(char *path){ /* test -S */
|
||||
return lstat(path, &buf) != -1 && S_ISSOCK(buf.st_mode);
|
||||
}
|
||||
int f_sticky(char *path){ /* test -k */
|
||||
return lstat(path, &buf) != -1 && (buf.st_mode & S_ISVTX);
|
||||
}
|
||||
int f_symlink(char *path){ /* test -h; test -L */
|
||||
return lstat(path, &buf) != -1 && S_ISLNK(buf.st_mode);
|
||||
}
|
||||
int f_uid(char *path){ /* test -u */
|
||||
return lstat(path, &buf) != -1 && (buf.st_mode & S_ISUID);
|
||||
}
|
||||
62
src/libfileis.h
Normal file
62
src/libfileis.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
/* libfileis functions return true if the condition is true and false if the
|
||||
* condition is false. Returned values are 0 or 1 only. */
|
||||
|
||||
/* True if file exists and is a block special file. */
|
||||
int f_blockspecial(char *path);
|
||||
|
||||
/* True if file exists and is a character special file. */
|
||||
int f_charspecial(char *path);
|
||||
|
||||
/* True if file exists and is a directory. */
|
||||
int f_directory(char *path);
|
||||
|
||||
/* True if file exists and is executable. */
|
||||
int f_executable(char *path);
|
||||
|
||||
/* True if file exists (regardless of type). */
|
||||
int f_exists(char *path);
|
||||
|
||||
/* True if file exists and is a named pipe (FIFO). */
|
||||
int f_fifospecial(char *path);
|
||||
|
||||
/* True if file exists and its set group ID flag is set. */
|
||||
int f_gid(char *path);
|
||||
|
||||
/* True if file exists and is readable. */
|
||||
int f_readable(char *path);
|
||||
|
||||
/* True if file exists and is a regular file. */
|
||||
int f_regular(char *path);
|
||||
|
||||
/* True if file exists and is a socket. */
|
||||
int f_socket(char *path);
|
||||
|
||||
/* True if file exists and its sticky bit is set. */
|
||||
int f_sticky(char *path);
|
||||
|
||||
/* True if file exists and is a symbolic link. */
|
||||
int f_symlink(char *path);
|
||||
|
||||
/* True if file exists and its set user ID flag is set. */
|
||||
int f_uid(char *path);
|
||||
|
||||
/* True if file exists and is writeable. */
|
||||
int f_writeable(char *path);
|
||||
64
src/npc.c
Normal file
64
src/npc.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* fprintf(3), fputs(3), getc(3), putc(3), stdin, stdout,
|
||||
* EOF */
|
||||
#include <unistd.h> /* getopt(3) */
|
||||
#if !defined EX_USAGE || !defined EX_OK
|
||||
# include <sysexits.h>
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
int c;
|
||||
char showend;
|
||||
char showtab;
|
||||
|
||||
showend = 0;
|
||||
showtab = 0;
|
||||
|
||||
if(argc > 0)
|
||||
while((c = getopt(argc, argv, "et")) != -1)
|
||||
switch(c){
|
||||
case 'e': showend = 1; break;
|
||||
case 't': showtab = 1; break;
|
||||
default: goto usage;
|
||||
}
|
||||
|
||||
if(argc > optind){
|
||||
usage: fprintf(stderr, "Usage: %s (-eht)\n", argv[0]);
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
while((c = getc(stdin)) != EOF){
|
||||
if((c & 0x80) != 0)
|
||||
fputs("M-", stdout);
|
||||
switch(c ^ 0x80 /* 0b 1000 0000 */){
|
||||
case 0x7f: fputs("^?", stdout);
|
||||
break;
|
||||
case '\n': if(showend)
|
||||
putc('$', stdout);
|
||||
default:
|
||||
if(c >= ' ' || c == '\n' || (!showtab && c == '\t'))
|
||||
putc(c, stdout);
|
||||
else
|
||||
fprintf(stdout, "^%c", c + '@');
|
||||
}
|
||||
}
|
||||
|
||||
return EX_OK;
|
||||
}
|
||||
98
src/scrut.c
Normal file
98
src/scrut.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* fprintf(3), stderr, NULL */
|
||||
#include <string.h> /* strchr(3) */
|
||||
#ifndef EX_USAGE
|
||||
# include <sysexits.h>
|
||||
#endif
|
||||
#include <unistd.h> /* access(3), getopt(3), F_OK, R_OK, W_OK, X_OK */
|
||||
#include <sys/stat.h> /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR,
|
||||
* S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK,
|
||||
* S_ISUID, S_ISVTX */
|
||||
|
||||
static char args[] = "bcdefghkprsuwxLS";
|
||||
static char ops[(sizeof args) / (sizeof *args)];
|
||||
static char *program_name = "scrut";
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
struct stat buf;
|
||||
int c;
|
||||
size_t i;
|
||||
|
||||
if(argc < 2)
|
||||
goto usage;
|
||||
|
||||
i = 0;
|
||||
while((c = getopt(argc, argv, args)) != -1)
|
||||
if(strchr(args, c) == NULL)
|
||||
goto usage;
|
||||
else
|
||||
ops[i++] = c;
|
||||
ops[i] = '\0';
|
||||
|
||||
if(optind == argc)
|
||||
goto usage;
|
||||
|
||||
argv += optind;
|
||||
do{ if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1)
|
||||
return 1; /* doesn't exist or isn't stattable */
|
||||
|
||||
for(i = 0; ops[i] != '\0'; ++i)
|
||||
if(ops[i] == 'e')
|
||||
continue;
|
||||
else if(ops[i] == 'h'){
|
||||
usage: fprintf(stderr, "Usage: %s (-%s) [file...]\n",
|
||||
argv[0] == NULL
|
||||
? program_name
|
||||
: argv[0],
|
||||
args);
|
||||
|
||||
return EX_USAGE;
|
||||
}else if(
|
||||
(ops[i] == 'b'
|
||||
&& !S_ISBLK(buf.st_mode))
|
||||
|| (ops[i] == 'c'
|
||||
&& !S_ISCHR(buf.st_mode))
|
||||
|| (ops[i] == 'd'
|
||||
&& !S_ISDIR(buf.st_mode))
|
||||
|| (ops[i] == 'f'
|
||||
&& !S_ISREG(buf.st_mode))
|
||||
|| (ops[i] == 'g'
|
||||
&& !(buf.st_mode & S_ISGID))
|
||||
|| (ops[i] == 'k'
|
||||
&& !(buf.st_mode & S_ISVTX))
|
||||
|| (ops[i] == 'p'
|
||||
&& !S_ISFIFO(buf.st_mode))
|
||||
|| (ops[i] == 'r'
|
||||
&& access(*argv, R_OK) != 0)
|
||||
|| (ops[i] == 'u'
|
||||
&& !(buf.st_mode & S_ISUID))
|
||||
|| (ops[i] == 'w'
|
||||
&& access(*argv, W_OK) != 0)
|
||||
|| (ops[i] == 'x'
|
||||
&& access(*argv, X_OK) != 0)
|
||||
|| (ops[i] == 'L'
|
||||
&& !S_ISLNK(buf.st_mode))
|
||||
|| (ops[i] == 'S'
|
||||
&& !S_ISSOCK(buf.st_mode)))
|
||||
return 1;
|
||||
}while(*++argv != NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
75
src/str.c
Normal file
75
src/str.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2023 DTB <trinity@trinity.moe>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdio.h> /* fprintf(3) */
|
||||
#include <string.h> /* strcmp(3) */
|
||||
#if !defined EX_USAGE
|
||||
# include <sysexits.h>
|
||||
#endif
|
||||
|
||||
static char *program_name = "str";
|
||||
|
||||
static struct {
|
||||
char *name;
|
||||
int (*f)(int);
|
||||
}ctypes[] = {
|
||||
{ "isalnum", isalnum },
|
||||
{ "isalpha", isalpha },
|
||||
{ "isblank", isblank },
|
||||
{ "iscntrl", iscntrl },
|
||||
{ "isdigit", isdigit },
|
||||
{ "isxdigit", isxdigit },
|
||||
{ "isgraph", isgraph },
|
||||
{ "islower", islower },
|
||||
{ "isprint", isprint },
|
||||
{ "ispunct", ispunct },
|
||||
{ "isspace", isspace },
|
||||
{ "isupper", isupper }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
int ctype;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
if(argc >= 3){
|
||||
for(ctype = 0; ctype < (sizeof ctypes) / (sizeof *ctypes);
|
||||
++ctype)
|
||||
if(strcmp(argv[1], ctypes[ctype].name) == 0)
|
||||
goto pass;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Usage: %s [type] [string...]\n",
|
||||
argv[0] == NULL ? program_name : argv[0]);
|
||||
|
||||
return EX_USAGE;
|
||||
|
||||
pass: for(argv += 2, r = 1; *argv != NULL; ++argv)
|
||||
for(i = 0; argv[0][i] != '\0'; ++i)
|
||||
/* First checks if argv[0][i] is valid ASCII; ctypes(3)
|
||||
* don't handle non-ASCII.
|
||||
* This is bad. */
|
||||
if(argv[0][i] < 0x80 && !ctypes[ctype].f(argv[0][i]))
|
||||
return 1;
|
||||
else
|
||||
r = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
25
src/strcmp.c
Normal file
25
src/strcmp.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <stdio.h> /* fprintf(3), stderr */
|
||||
#ifndef EX_USAGE
|
||||
# include <sysexits.h> /* EX_USAGE */
|
||||
#endif
|
||||
|
||||
static char *program_name = "strcmp";
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
int i;
|
||||
|
||||
if(argc < 3){
|
||||
fprintf(stderr, "Usage: %s [string] [string...]\n",
|
||||
argv[0] == NULL ? program_name : argv[0]);
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
for(; *argv[1] != '\0'; ++argv[1])
|
||||
for(i = 2; i < argc; ++i)
|
||||
if(*argv[i-1] > *argv[i])
|
||||
return 1;
|
||||
else if(*argv[i-1] < *argv[i]++)
|
||||
return -1; /* actually 255 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
209
src/tail.c
209
src/tail.c
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||
* Copyright (c) 2023 Marceline Cramer <mars@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This file is part of YAC coreutils.
|
||||
*
|
||||
* YAC coreutils is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* YAC coreutils is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sysexits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "yac.h"
|
||||
|
||||
typedef struct string_t {
|
||||
char *mem;
|
||||
int len;
|
||||
int capacity;
|
||||
} string_t;
|
||||
|
||||
string_t *string_new() {
|
||||
string_t *string = calloc(1, sizeof(string_t));
|
||||
string->capacity = 1024;
|
||||
string->len = 0;
|
||||
string->mem = calloc(string->capacity, sizeof(char));
|
||||
return string;
|
||||
}
|
||||
|
||||
void string_putc(string_t *string, char c) {
|
||||
string->mem[string->len] = c;
|
||||
string->len++;
|
||||
if (string->len >= string->capacity) {
|
||||
string->capacity *= 2;
|
||||
string->mem = realloc(string->mem, string->capacity * sizeof(char));
|
||||
}
|
||||
}
|
||||
|
||||
void tailc(FILE *f, long num) {}
|
||||
|
||||
void tailn(FILE *f, long num) {
|
||||
string_t *lines[num];
|
||||
int cursor = 0;
|
||||
int looped = 0;
|
||||
|
||||
lines[cursor] = string_new();
|
||||
|
||||
int c = fgetc(f);
|
||||
for (;;) {
|
||||
if (c == EOF) {
|
||||
string_putc(lines[cursor], '\0');
|
||||
break;
|
||||
}
|
||||
|
||||
string_putc(lines[cursor], c);
|
||||
|
||||
if (c == '\n') {
|
||||
string_putc(lines[cursor], '\0');
|
||||
|
||||
if ((c = fgetc(f)) == EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (++cursor >= num) {
|
||||
looped = 1;
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
lines[cursor] = string_new();
|
||||
} else {
|
||||
c = fgetc(f);
|
||||
}
|
||||
}
|
||||
|
||||
int read = looped ? cursor + 1 : 0;
|
||||
do {
|
||||
if (read >= num) {
|
||||
read = 0;
|
||||
}
|
||||
|
||||
fputs(lines[read]->mem, stdout);
|
||||
} while (read++ != cursor);
|
||||
}
|
||||
|
||||
void tailf(FILE *file) {
|
||||
int byte;
|
||||
|
||||
while(true) {
|
||||
if ((byte = fgetc(file)) != EOF) { putchar(byte); }
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool c = false;
|
||||
bool f = false;
|
||||
bool n = false;
|
||||
int i;
|
||||
int opt;
|
||||
long num;
|
||||
void (*fn)(FILE *, long) = tailn;
|
||||
|
||||
extern int optind;
|
||||
while ((opt = getopt(argc, argv, "c:fn:")) != -1) {
|
||||
switch (opt) {
|
||||
/*
|
||||
* From tail(1p):
|
||||
*
|
||||
* -c number The application shall ensure that the number option-argument
|
||||
* is a decimal integer, optionally including a sign. The sign
|
||||
* shall affect the location in the file, measured in bytes, to
|
||||
* begin the copying:
|
||||
*
|
||||
* ┌─────┬────────────────────────────────────────┐
|
||||
* │Sign │ Copying Starts │
|
||||
* ├─────┼────────────────────────────────────────┤
|
||||
* │ + │ Relative to the beginning of the file. │
|
||||
* │ - │ Relative to the end of the file. │
|
||||
* │none │ Relative to the end of the file. │
|
||||
* └─────┴────────────────────────────────────────┘
|
||||
* The application shall ensure that if the sign of the number
|
||||
* option-argument is '+', the number option-argument is a non-
|
||||
* zero decimal integer.
|
||||
*
|
||||
* The origin for counting shall be 1; that is, -c +1 represents
|
||||
* the first byte of the file, -c -1 the last.
|
||||
*
|
||||
* -f If the input file is a regular file or if the file operand
|
||||
* specifies a FIFO, do not terminate after the last line of the
|
||||
* input file has been copied, but read and copy further bytes
|
||||
* from the input file when they become available. If no file
|
||||
* operand is specified and standard input is a pipe or FIFO,
|
||||
* the -f option shall be ignored. If the input file is not a
|
||||
* FIFO, pipe, or regular file, it is unspecified whether or not
|
||||
* the -f option shall be ignored.
|
||||
*
|
||||
* -n number This option shall be equivalent to -c number, except the
|
||||
* starting location in the file shall be measured in lines
|
||||
* instead of bytes. The origin for counting shall be 1; that
|
||||
* is, -n +1 represents the first line of the file, -n -1 the
|
||||
* last.
|
||||
*
|
||||
* If neither -c nor -n is specified, -n 10 shall be assumed.
|
||||
*/
|
||||
case 'c':
|
||||
c = true;
|
||||
fn = tailc;
|
||||
num = strtol(optarg, NULL, 10);
|
||||
break;
|
||||
case 'f':
|
||||
f = true;
|
||||
case 'n':
|
||||
n = true;
|
||||
num = strtol(optarg, NULL, 10);
|
||||
break;
|
||||
default:
|
||||
fprintf(
|
||||
stderr,
|
||||
"Usage: %s (-f) [-c characters] [-n lines] file...\n",
|
||||
argv[0]
|
||||
);
|
||||
return EX_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!n && !c) {
|
||||
num = 10;
|
||||
} else if (n && c) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Usage: %s (-f) [-c characters] [-n lines] file...\n",
|
||||
argv[0]
|
||||
);
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
FILE *file;
|
||||
|
||||
if (optind == argc) {
|
||||
fn(stdin, num);
|
||||
|
||||
if (f) { tailf(stdin); }
|
||||
} else {
|
||||
for (i = optind; i < argc; i++) {
|
||||
if ((file = rpath(argv[0], argv[i])) != NULL) {
|
||||
fn(file, num);
|
||||
}
|
||||
|
||||
if (f) { tailf(file); }
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
return EX_OK;
|
||||
}
|
||||
18
src/true.c
18
src/true.c
@@ -1,21 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* SPDX-License-Identifier: CC0
|
||||
*
|
||||
* This file is part of YAC coreutils.
|
||||
*
|
||||
* YAC coreutils is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* YAC coreutils is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
* This work is marked with CC0 1.0. To view a copy of this license, visit
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0>.
|
||||
*/
|
||||
|
||||
int main() {}
|
||||
|
||||
77
src/yac.c
77
src/yac.c
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This file is part of YAC coreutils.
|
||||
*
|
||||
* YAC coreutils is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* YAC coreutils is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Resolve a file from a path */
|
||||
FILE *rpath(char *argv0, char *path) {
|
||||
struct stat stats;
|
||||
FILE *file;
|
||||
|
||||
if (path[0] == '-') {
|
||||
switch (path[1]) {
|
||||
case '\0':
|
||||
file = stdin;
|
||||
break;
|
||||
default:
|
||||
file = NULL;
|
||||
break;
|
||||
}
|
||||
} else if (stat(path, &stats) == 0 && S_ISDIR(stats.st_mode)) {
|
||||
fprintf(stderr, "%s: %s: Is a directory.\n", argv0, path);
|
||||
exit(EX_NOINPUT);
|
||||
} else if ((file = fopen(path, "r")) == NULL) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
fprintf(stderr, "%s: %s: Permission denied.\n", argv0, path);
|
||||
exit(EX_NOINPUT);
|
||||
case EISDIR:
|
||||
fprintf(stderr, "%s: %s: Is a directory.\n", argv0, path);
|
||||
exit(EX_NOINPUT);
|
||||
case ELOOP:
|
||||
fprintf(
|
||||
stderr,
|
||||
"%s: %s: Is a symbolic link loop.\n",
|
||||
argv0,
|
||||
path
|
||||
);
|
||||
exit(EX_UNAVAILABLE);
|
||||
case EMFILE:
|
||||
fprintf(stderr, "%s: Internal error.\n", argv0);
|
||||
exit(EX_SOFTWARE);
|
||||
case ENOENT: case ENOTDIR: case ENXIO:
|
||||
fprintf(
|
||||
stderr,
|
||||
"%s: %s: No such path or directory.\n",
|
||||
argv0,
|
||||
path
|
||||
);
|
||||
exit(EX_NOINPUT);
|
||||
default:
|
||||
fprintf(stderr, "%s: Unknown error.\n", argv0);
|
||||
exit(EX_UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
26
src/yac.h
26
src/yac.h
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* This file is part of YAC coreutils.
|
||||
*
|
||||
* YAC coreutils is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* YAC coreutils is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef YAC_H
|
||||
#define YAC_H
|
||||
|
||||
FILE *rpath(char *argv0, char *path);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user