Remove some dead code

This commit is contained in:
Justine Tunney 2023-07-03 02:47:05 -07:00
parent 168d1c157e
commit 73c0faa1b5
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
66 changed files with 324 additions and 7705 deletions

View file

@ -6,7 +6,6 @@ PKGS += TOOL_BUILD
TOOL_BUILD_FILES := $(wildcard tool/build/*)
TOOL_BUILD_SRCS = $(filter %.c,$(TOOL_BUILD_FILES))
TOOL_BUILD_HDRS = $(filter %.h,$(TOOL_BUILD_FILES))
TOOL_BUILD_CTESTS = $(filter %.ctest,$(TOOL_BUILD_FILES))
TOOL_BUILD_BINS = \
$(TOOL_BUILD_COMS) \
@ -21,8 +20,6 @@ TOOL_BUILD_BINS = \
o/$(MODE)/tool/build/printf \
o/$(MODE)/tool/build/dd
TOOL_BUILD_CALCULATOR = o/$(MODE)/tool/build/calculator.com
TOOL_BUILD_OBJS = \
$(TOOL_BUILD_SRCS:%.c=o/$(MODE)/%.o)
@ -31,8 +28,7 @@ TOOL_BUILD_COMS = \
TOOL_BUILD_CHECKS = \
$(TOOL_BUILD).pkg \
$(TOOL_BUILD_HDRS:%=o/$(MODE)/%.ok) \
$(TOOL_BUILD_CTESTS:%=o/$(MODE)/%.ok)
$(TOOL_BUILD_HDRS:%=o/$(MODE)/%.ok)
TOOL_BUILD_DIRECTDEPS = \
DSP_CORE \
@ -80,12 +76,6 @@ o/$(MODE)/tool/build/build.pkg: \
$(TOOL_BUILD_OBJS) \
$(foreach x,$(TOOL_BUILD_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/%.ctest.ok: \
%.ctest \
$(TOOL_BUILD_CALCULATOR) \
$(VM)
@$(COMPILE) -AMKWIDES -wtT$@ $(VM) $(TOOL_BUILD_CALCULATOR) $<
o/$(MODE)/tool/build/%.com.dbg: \
$(TOOL_BUILD_DEPS) \
o/$(MODE)/tool/build/build.pkg \

View file

@ -1,760 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "dsp/tty/tty.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/morton.h"
#include "libc/intrin/popcnt.h"
#include "libc/limits.h"
#include "libc/log/color.internal.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/mem/arraylist2.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/sig.h"
#include "libc/tinymath/emodl.h"
#include "libc/x/xsigaction.h"
#include "third_party/gdtoa/gdtoa.h"
#include "third_party/getopt/getopt.internal.h"
#define INT int128_t
#define FLOAT long double
#define EPSILON 1e-16l
#define BANNER \
"\
Reverse Polish Notation Calculator\n\
Copyright 2020 Justine Alexandra Roberts Tunney\n\
This is fast portable lightweight software. You have the freedom to build\n\
software just like it painlessly. See http://github.com/jart/cosmopolitan\n\
"
#define USAGE1 \
"SYNOPSIS\n\
\n\
Reverse Polish Notation Calculator\n\
\n\
USAGE\n\
\n"
#define USAGE2 \
" [FLAGS] [FILE...]\n\
\n\
FLAGS\n\
\n\
-h\n\
-? shows this information\n\
-i force interactive mode\n\
\n\
KEYBOARD SHORTCUTS\n\
\n\
CTRL-D Closes standard input\n\
CTRL-C Sends SIGINT to program\n\
CTRL-U Redraw line\n\
CTRL-L Redraw display\n\
\n\
FUNCTIONS\n\
\n"
#define USAGE3 \
"\n\
EXAMPLES\n\
\n\
calculator.com\n\
40 2 +\n\
42\n\
\n\
echo '2 2 + . cr' | calculator.com\n\
4\n\
\n\
calculator.com <<EOF\n\
true assert\n\
-1 ~ 0 = assert\n\
3 2 / 1.5 = assert\n\
81 3 // 27 = assert\n\
2 8 ** 256 = assert\n\
pi cos -1 = assert\n\
pi sqrt pi sqrt * pi - abs epsilon < assert\n\
nan isnormal ! assert\n\
0b1010101 0b0110101 ^ 0b1100000 = assert\n\
0b1010101 popcnt 4 = assert\n\
EOF\n\
\n\
CONTACT\n\
\n\
Justine Tunney <jtunney@gmail.com>\n\
https://github.com/jart/cosmooplitan\n\
\n\
"
#define CTRL(C) ((C) ^ 0100)
#define Fatal(...) Log(kFatal, __VA_ARGS__)
#define Warning(...) Log(kWarning, __VA_ARGS__)
enum Severity {
kFatal,
kWarning,
};
enum Exception {
kUnderflow = 1,
kDivideError,
};
struct Bytes {
size_t i, n;
char *p;
};
struct History {
size_t i, n;
struct Bytes *p;
};
struct Value {
enum Type {
kInt,
kFloat,
} t;
union {
INT i;
FLOAT f;
};
};
struct Function {
const char sym[16];
void (*fun)(void);
const char *doc;
};
jmp_buf thrower;
const char *file;
struct Bytes token;
struct History history;
struct Value stack[128];
int sp, comment, line, column, interactive;
uint32_t gray(uint32_t x) {
return x ^ (x >> 1);
}
uint32_t ungray(uint32_t x) {
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x ^= x >> 2;
x ^= x >> 1;
return x;
}
INT Popcnt(INT x) {
uint128_t word = x;
return popcnt(word >> 64) + popcnt(word);
}
char *Repr(struct Value x) {
static char buf[64];
if (x.t == kFloat) {
g_xfmt_p(buf, &x.f, 16, sizeof(buf), 0);
} else {
sprintf(buf, "%jjd", x.i);
}
return buf;
}
char *ReprStack(void) {
int i, j, l;
char *s, *p;
static char buf[80];
p = memset(buf, 0, sizeof(buf));
for (i = 0; i < sp; ++i) {
s = Repr(stack[i]);
l = strlen(s);
if (p + l + 2 > buf + sizeof(buf)) break;
p = mempcpy(p, s, l);
*p++ = ' ';
}
return buf;
}
void ShowStack(void) {
if (interactive) {
printf("\r\e[K");
fputs(ReprStack(), stdout);
}
}
void Cr(FILE *f) {
fputs(interactive || IsWindows() ? "\r\n" : "\n", f);
}
void Log(enum Severity l, const char *fmt, ...) {
va_list va;
const char *severity[] = {"FATAL", "WARNING"};
if (interactive) fflush(/* key triggering throw not echo'd yet */ stdout);
fprintf(stderr, "%s:%d:%d:%s: ", file, line + 1, column, severity[l & 1]);
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
Cr(stderr);
if (l == kFatal) exit(EXIT_FAILURE);
if (interactive) ShowStack();
}
void __on_arithmetic_overflow(void) {
Warning("arithmetic overflow");
}
void OnDivideError(void) {
longjmp(thrower, kDivideError);
}
struct Value Push(struct Value x) {
if (sp >= ARRAYLEN(stack)) Fatal("stack overflow");
return (stack[sp++] = x);
}
struct Value Pop(void) {
if (sp) {
return stack[--sp];
} else {
longjmp(thrower, kUnderflow);
}
}
INT Popi(void) {
struct Value x = Pop();
return x.t == kInt ? x.i : x.f;
}
void Pushi(INT i) {
struct Value x;
x.t = kInt;
x.i = i;
Push(x);
}
FLOAT Popf(void) {
struct Value x = Pop();
return x.t == kInt ? x.i : x.f;
}
void Pushf(FLOAT f) {
struct Value x;
x.t = kFloat;
x.f = f;
Push(x);
}
void OpDrop(void) {
Pop();
}
void OpDup(void) {
Push(Push(Pop()));
}
void OpExit(void) {
exit(Popi());
}
void OpSrand(void) {
srand(Popi());
}
void OpEmit(void) {
fputwc(Popi(), stdout);
}
void OpCr(void) {
Cr(stdout);
}
void OpPrint(void) {
printf("%s ", Repr(Pop()));
}
void OpComment(void) {
comment = true;
}
void Glue0f(FLOAT fn(void)) {
Pushf(fn());
}
void Glue0i(INT fn(void)) {
Pushi(fn());
}
void Glue1f(FLOAT fn(FLOAT)) {
Pushf(fn(Popf()));
}
void Glue1i(INT fn(INT)) {
Pushi(fn(Popi()));
}
void OpSwap(void) {
struct Value a, b;
b = Pop();
a = Pop();
Push(b);
Push(a);
}
void OpOver(void) {
struct Value a, b;
b = Pop();
a = Pop();
Push(a);
Push(b);
Push(a);
}
void OpKey(void) {
wint_t c;
ttyraw(kTtyCursor | kTtySigs | kTtyLfToCrLf);
c = fgetwc(stdin);
ttyraw(-1);
if (c != -1) Pushi(c);
}
void OpAssert(void) {
if (!Popi()) Fatal("assert failed");
}
void OpExpect(void) {
if (!Popi()) Warning("expect failed");
}
void OpMeminfo(void) {
OpCr();
OpCr();
fflush(stdout);
_meminfo(fileno(stdout));
}
void Glue2f(FLOAT fn(FLOAT, FLOAT)) {
FLOAT x, y;
y = Popf();
x = Popf();
Pushf(fn(x, y));
}
void Glue2i(INT fn(INT, INT)) {
INT x, y;
y = Popi();
x = Popi();
Pushi(fn(x, y));
}
void Glue1g(FLOAT fnf(FLOAT), INT fni(INT)) {
struct Value x;
x = Pop();
switch (x.t) {
case kInt:
Pushi(fni(x.i));
break;
case kFloat:
Pushf(fnf(x.f));
break;
default:
Warning("type mismatch");
}
}
void Glue2g(FLOAT fnf(FLOAT, FLOAT), INT fni(INT, INT)) {
struct Value x, y;
y = Pop();
x = Pop();
if (x.t == kInt && y.t == kInt) {
Pushi(fni(x.i, y.i));
} else if (x.t == kFloat && y.t == kFloat) {
Pushf(fnf(x.f, y.f));
} else if (x.t == kInt && y.t == kFloat) {
Pushf(fnf(x.i, y.f));
} else if (x.t == kFloat && y.t == kInt) {
Pushf(fnf(x.f, y.i));
} else {
Warning("type mismatch");
}
}
#define LB {
#define RB }
#define SEMI ;
#define FNTYPEi INT
#define FNTYPEf FLOAT
#define FORM(F) LB F SEMI RB
#define FNPL0(T) void
#define FNPL1(T) FNTYPE##T x
#define FNPL2(T) FNTYPE##T x, FNTYPE##T y
#define FNDEF(A, T, S, C) FNTYPE##T Fn##S##T(FNPL##A(T)) FORM(return C)
#define FNDEFf(A, S, C) FNDEF(A, f, S, C)
#define FNDEFi(A, S, C) FNDEF(A, i, S, C)
#define FNDEFg(A, S, C) FNDEF(A, f, S, C) FNDEF(A, i, S, C)
#define OPDEF(A, T, S, C) void Op##S(void) FORM(Glue##A##T(Fn##S##T))
#define OPDEFf(A, S, C) OPDEF(A, f, S, C)
#define OPDEFi(A, S, C) OPDEF(A, i, S, C)
#define OPDEFg(A, S, C) void Op##S(void) FORM(Glue##A##g(Fn##S##f, Fn##S##i))
#define M(A, T, N, S, C, D) FNDEF##T(A, S, C) OPDEF##T(A, S, C)
#include "tool/build/calculator.inc"
#undef M
const struct Function kFunctions[] = {
{".", OpPrint, "pops prints value repr"},
{"#", OpComment, "line comment"},
#define M(A, T, N, S, C, D) {N, Op##S, D},
#include "tool/build/calculator.inc"
#undef M
{"dup", OpDup, "pushes copy of last item on stack"},
{"drop", OpDrop, "pops and discards"},
{"swap", OpSwap, "swaps last two items on stack"},
{"over", OpOver, "pushes second item on stack"},
{"cr", OpCr, "prints newline"},
{"key", OpKey, "reads and pushes unicode character from keyboard"},
{"emit", OpEmit, "pops and writes unicode character to output"},
{"assert", OpAssert, "crashes if top of stack isn't nonzero"},
{"expect", OpExpect, "prints warning if top of stack isn't nonzero"},
{"meminfo", OpMeminfo, "prints memory mappings"},
{"exit", OpExit, "exits program with status"},
};
bool CallFunction(const char *sym) {
int i;
char s[16];
strncpy(s, sym, sizeof(s));
for (i = 0; i < ARRAYLEN(kFunctions); ++i) {
if (memcmp(kFunctions[i].sym, s, sizeof(s)) == 0) {
kFunctions[i].fun();
return true;
}
}
return false;
}
volatile const char *literal_;
bool ConsumeLiteral(const char *literal) {
bool r;
char *e;
struct Value x;
literal_ = literal;
errno = 0;
x.t = kInt;
x.i = strtoi128(literal, &e, 0);
if (*e) {
x.t = kFloat;
x.f = strtod(literal, &e);
r = !(!e || *e);
} else if (errno == ERANGE) {
r = false;
} else {
r = true;
}
Push(x);
return r;
}
void ConsumeToken(void) {
enum Exception ex;
if (!token.i) return;
token.p[token.i] = 0;
token.i = 0;
if (history.i) history.p[history.i - 1].i = 0;
if (comment) return;
if (_startswith(token.p, "#!")) return;
switch (setjmp(thrower)) {
default:
if (CallFunction(token.p)) return;
if (ConsumeLiteral(token.p)) return;
Warning("bad token: %`'s", token.p);
break;
case kUnderflow:
Warning("stack underflow");
break;
case kDivideError:
Warning("divide error");
break;
}
}
void CleanupRepl(void) {
if (sp && interactive) {
Cr(stdout);
}
}
void AppendByte(struct Bytes *a, char b) {
APPEND(&a->p, &a->i, &a->n, &b);
}
void AppendHistory(void) {
struct Bytes line;
if (interactive) {
bzero(&line, sizeof(line));
APPEND(&history.p, &history.i, &history.n, &line);
}
}
void AppendLine(char b) {
if (interactive) {
if (!history.i) AppendHistory();
AppendByte(&history.p[history.i - 1], b);
}
}
void Echo(int c) {
if (interactive) {
fputc(c, stdout);
}
}
void Backspace(int c) {
struct Bytes *line;
if (interactive) {
if (history.i) {
line = &history.p[history.i - 1];
if (line->i && token.i) {
do {
line->i--;
token.i--;
} while (line->i && token.i && (line->p[line->i] & 0x80));
fputs("\e[D \e[D", stdout);
}
}
}
}
void NewLine(void) {
line++;
column = 0;
comment = false;
if (interactive) {
Cr(stdout);
AppendHistory();
ShowStack();
}
}
void KillLine(void) {
if (interactive) {
if (history.i) {
history.p[history.i - 1].i--;
}
}
}
void ClearLine(void) {
if (interactive) {
if (token.i) sp = 0;
ShowStack();
}
}
void RedrawDisplay(void) {
int i;
struct Bytes *line;
if (interactive) {
printf("\e[H\e[2J%s", BANNER);
ShowStack();
if (history.i) {
line = &history.p[history.i - 1];
for (i = 0; i < line->i; ++i) {
fputc(line->p[i], stdout);
}
}
}
}
void GotoStartOfLine(void) {
if (interactive) {
printf("\r");
}
}
void GotoEndOfLine(void) {
}
void GotoPrevLine(void) {
}
void GotoNextLine(void) {
}
void GotoPrevChar(void) {
}
void GotoNextChar(void) {
}
void Calculator(FILE *f) {
int c;
while (!feof(f)) {
switch ((c = getc(f))) {
case -1:
case CTRL('D'):
goto Done;
case CTRL('@'):
break;
case ' ':
column++;
Echo(c);
AppendLine(c);
ConsumeToken();
break;
case '\t':
column = ROUNDUP(column, 8);
Echo(c);
AppendLine(c);
ConsumeToken();
break;
case '\r':
case '\n':
ConsumeToken();
NewLine();
break;
case CTRL('A'):
GotoStartOfLine();
break;
case CTRL('E'):
GotoEndOfLine();
break;
case CTRL('P'):
GotoPrevLine();
break;
case CTRL('N'):
GotoNextLine();
break;
case CTRL('B'):
GotoPrevChar();
break;
case CTRL('F'):
GotoNextChar();
break;
case CTRL('L'):
RedrawDisplay();
break;
case CTRL('U'):
ClearLine();
break;
case CTRL('K'):
KillLine();
break;
case CTRL('?'):
case CTRL('H'):
Backspace(c);
break;
default:
column++;
/* fallthrough */
case 0x80 ... 0xff:
Echo(c);
AppendLine(c);
AppendByte(&token, c);
break;
}
fflush(/* needed b/c this is event loop */ stdout);
}
Done:
CleanupRepl();
}
int Calculate(const char *path) {
FILE *f;
file = path;
line = column = 0;
if (!(f = fopen(file, "r"))) Fatal("file not found: %s", file);
Calculator(f);
return fclose(f);
}
void CleanupTerminal(void) {
ttyraw(-1);
}
void StartInteractive(void) {
if (!interactive && !__nocolor && isatty(fileno(stdin)) &&
isatty(fileno(stdout)) && !__nocolor) {
interactive = true;
}
errno = 0;
if (interactive) {
fputs(BANNER, stdout);
fflush(/* needed b/c entering tty mode */ stdout);
ttyraw(kTtyCursor | kTtySigs);
atexit(CleanupTerminal);
}
}
void PrintUsage(int rc, FILE *f) {
char c;
int i, j;
fprintf(f, "%s %s%s", USAGE1, program_invocation_name, USAGE2);
for (i = 0; i < ARRAYLEN(kFunctions); ++i) {
fputs(" ", f);
for (j = 0; j < ARRAYLEN(kFunctions[i].sym); ++j) {
c = kFunctions[i].sym[j];
fputc(c ? c : ' ', f);
}
fprintf(f, " %s\n", kFunctions[i].doc);
}
fputs(USAGE3, f);
exit(rc);
}
void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "?hi")) != -1) {
switch (opt) {
case 'i':
interactive = true;
break;
case 'h':
case '?':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
}
int main(int argc, char *argv[]) {
int i, rc;
ShowCrashReports();
GetOpts(argc, argv);
xsigaction(SIGFPE, OnDivideError, 0, 0, 0);
if (optind == argc) {
file = "/dev/stdin";
StartInteractive();
Calculator(stdin);
return fclose(stdin);
} else {
for (i = optind; i < argc; ++i) {
if (Calculate(argv[i]) == -1) {
return -1;
}
}
}
return 0;
}

View file

@ -1,91 +0,0 @@
# INTEGER
2 3 + 5 = assert
3 2 + 5 = assert
5 2 - 3 = assert
2 5 - -3 = assert
81 3 / 27 = assert
81 3 // 27 = assert
2 8 ** 256 = assert
17 10 % 7 = assert
17 10 fmod 7 = assert
# FLOATING POINT
.1 .2 + .3 - abs epsilon < assert
pi sqrt pi sqrt * pi - abs epsilon < assert
3 2 / 1.5 = assert
pi pi = assert
pi cos -1 = assert
pi 2 / sin 1 = assert
81 3 / 27 = assert
inf isinf assert
inf isnormal ! assert
nan isnormal ! assert
1 0 / isnormal ! assert
0 signbit ! assert
-.5 round -1 = assert
-.5 floor -1 = assert
-.5 rint dup 0 = assert signbit assert
-.5 nearbyint dup 0 = assert signbit assert
-.5 ceil dup 0 = assert signbit assert
-.5 trunc dup 0 = assert signbit assert
0 0 / dup isnan assert signbit assert # is this right?
1 0 / dup isinf assert signbit ! assert # is this right?
nan nan != assert # is this right?
# -nan -nan != assert # is this right?
inf inf = assert # is this right?
-inf -inf = assert # is this right?
# BIT ARITHMETIC
-1 ~ 0 = assert
0 0x7fffffffffffffffffffffffffffffff - -0x7fffffffffffffffffffffffffffffff = assert
0b1010101 popcnt 4 = assert
0b1010101 0b0110101 ^ 0b1100000 = assert
0b1010101 0b0110101 | 0b1110101 = assert
0b1010101 0b0110101 & 0b0010101 = assert
0b1010101 1 >> 0b000101010 = assert
0b1010101 2 >> 0b000010101 = assert
0b1010101 1 << 0b010101010 = assert
0b1010101 2 << 0b101010100 = assert
# BOOLEAN
true assert
false ! assert
true ! ! assert
true true && assert
true false && ! assert
false true && ! assert
true false && ! assert
false true && ! assert
true true || assert
false true || assert
true false || assert
false false || ! assert
4 5 < assert
5 4 < ! assert
-5 4 < assert
5 5 < ! assert
5 5 <= assert
5 4 > assert
4 5 > ! assert
4 -5 > assert
5 5 > ! assert
5 5 >= assert
# MISC
1 abs 1 = assert
-1 abs 1 = assert
-1 1 max 1 = assert
1 -1 max 1 = assert
1 2 max 2 = assert
-1 1 min -1 = assert
1 -1 min -1 = assert
1 2 min 1 = assert
rand64 rand64 rand64 rand64 != != && assert
# HEX SIGN
-0x80000000 -2147483648 = assert
0x80000000 2147483648 = assert
0x80000001 2147483649 = assert
0xffffffff 4294967295 = assert
0x100000000 4294967296 = assert
-0x100000000 -4294967296 = assert

View file

@ -1,100 +0,0 @@
M(2, g, "+", Add, x + y, "add")
M(2, g, "-", Sub, x - y, "sub")
M(2, g, "*", Mul, x *y, "multiply")
M(2, f, "/", Div, x / y, "division")
M(2, i, "%", Rem, x % y, "integer remainder")
M(2, i, "//", Idiv, x / y, "integer division")
M(2, g, "**", Expo, powl(x, y), "exponentiation")
M(1, i, "~", Not, ~x, "bitwise not")
M(2, i, "^", Xor, x ^ y, "bitwise xor")
M(2, i, "|", Or, x | y, "bitwise or")
M(2, i, "&", And, x &y, "bitwise and")
M(2, i, ">>", Shr, x >> y, "shift right")
M(2, i, "<<", Shl, x << y, "shift left")
M(1, i, "!", LogicalNot, !x, "logical not")
M(2, i, "||", LogicalOr, x || y, "logical or")
M(2, i, "&&", LogicalAnd, x &&y, "logical and")
M(2, g, "=", Equal1, x == y, "equal to")
M(2, g, "!=", Notequal, x != y, "not equal to")
M(2, g, "<", LessThan, x < y, "less than")
M(2, g, ">", GreaterThan, x > y, "greater than")
M(2, g, "<=", LessThanEqual, x <= y, "less than or equal to")
M(2, g, ">=", GreaterThanEqual, x >= y, "greater than or equal to")
M(1, i, "gray", Gray, gray(x), "gray coding")
M(1, i, "ungray", Ungray, ungray(x), "inverse gray coding")
M(1, i, "popcnt", Popcnt, Popcnt(x), "count bits")
M(1, g, "abs", Abs, fabsl(x), "absolute value")
M(2, g, "min", Min, fminl(x, y), "pops two values and pushes minimum")
M(2, g, "max", Max, fmaxl(x, y), "pops two values and pushes maximum")
M(2, g, "fmod", Fmod, fmodl(x, y), "trunc remainder")
M(2, g, "emod", Emod, emodl(x, y), "euclidean remainder")
M(2, g, "remainder", Remainder, remainderl(x, y), "rint remainder")
M(2, g, "hypot", Hypot, hypotl(x, y), "euclidean distance")
M(0, i, "false", False, 0, "0")
M(0, i, "true", True, 1, "1")
M(0, i, "intmin", IntMin, INT128_MIN, "native integer minimum")
M(0, i, "intmax", IntMax, INT128_MAX, "native integer maximum")
M(0, f, "e", Euler, M_E, "𝑒")
M(0, f, "pi", Fldpi, M_PI, "π")
M(0, f, "epsilon", Epsilon, EPSILON, "ɛ")
M(0, f, "inf", Inf, INFINITY, "")
M(0, f, "nan", Nan, NAN, "NAN")
M(0, f, "-0", Negzero, -0., "wut")
M(0, f, "l2t", Fldl2t, M_LOG2_10, "log₂10")
M(0, f, "lg2", Fldlg2, M_LOG10_2, "log₁₀2")
M(0, f, "ln2", Fldln2, M_LN2, "logₑ2")
M(0, f, "l2e", Fldl2e, M_LOG2E, "logₑ10")
M(2, f, "nextafter", Nextafter, nextafterl(x, y), "next ulp")
M(1, f, "significand", Significand, significandl(x), "mantissa")
M(1, f, "sqrt", Sqrt, sqrtl(x), "√𝑥")
M(1, f, "exp", Exp, expl(x), "𝑒ˣ")
M(1, g, "expm1", Expm1, expm1l(x), "𝑒ˣ-1")
M(1, g, "exp2", Exp2, exp2l(x), "")
M(1, g, "exp10", Exp10, exp10l(x), "10ˣ")
M(2, g, "ldexp", Ldexp, ldexpl(x, y), "𝑥×")
M(1, f, "log", Log, logl(x), "logₑ𝑥")
M(1, g, "log2", Log2, log2l(x), "log₂𝑥")
M(1, g, "log10", Log10, log10l(x), "log₁₀𝑥")
M(1, g, "ilogb", Ilogb, ilogbl(x), "exponent")
M(1, g, "sin", Sin, sinl(x), "sine")
M(1, g, "cos", Cos, cosl(x), "cosine")
M(1, g, "tan", Tan, tanl(x), "tangent")
M(1, g, "asin", Asin, asinl(x), "arcsine")
M(1, g, "acos", Acos, acosl(x), "arccosine")
M(1, g, "atan", Atan, atanl(x), "arctangent")
M(2, g, "atan2", Atan2, atan2l(x, y), "arctangent of 𝑥/𝑦")
M(1, g, "sinh", Sinh, sinhl(x), "hyperbolic sine")
M(1, g, "cosh", Cosh, coshl(x), "hyperbolic cosine")
M(1, g, "tanh", Tanh, tanhl(x), "hyperbolic tangent")
M(1, g, "asinh", Asinh, asinhl(x), "hyperbolic arcsine")
M(1, g, "acosh", Acosh, acoshl(x), "hyperbolic arccosine")
M(1, g, "atanh", Atanh, atanhl(x), "hyperbolic arctangent")
M(1, g, "round", Round, roundl(x), "round away from zero")
M(1, g, "trunc", Trunc, truncl(x), "round towards zero")
M(1, g, "rint", Rint, rintl(x), "round to even")
M(1, g, "nearbyint", Nearbyint, nearbyintl(x), "round to nearest integer")
M(1, g, "ceil", Ceil, ceill(x), "smallest integral not less than 𝑥")
M(1, g, "floor", Floor, floorl(x), "largest integral not greater than 𝑥")
M(1, f, "isnan", Isnan, isnan(x), "returns true if 𝑥=NAN")
M(1, f, "isinf", Isinf, isinf(x), "returns true if 𝑥=INFINITY")
M(1, f, "signbit", Signbit, signbit(x), "clears all bits but sign bit")
M(1, f, "isfinite", Isfinite, isfinite(x), "returns true if 𝑥≠INFINITY")
M(1, f, "isnormal", Isnormal, isnormal(x), "returns true if not denormal")
M(1, f, "fpclassify", Fpclassify, fpclassify(x),
"nan=0,inf=1,zero=2,subnorm=3,normal=4")
M(0, i, "rand", Rand, rand(), "deterministic random number")
M(0, i, "rand64", _Rand64, _rand64(), "64-bit random number")

View file

@ -21,6 +21,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "third_party/getopt/getopt.internal.h"
@ -33,42 +34,21 @@ SYNOPSIS\n\
\n\
FLAGS\n\
\n\
-?\n\
-h help\n\
\n"
const char *prog;
nullterminated() static void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
static wontreturn void SysExit(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static wontreturn void PrintUsage(int fd, int rc) {
Print(fd, "USAGE\n\n ", program_invocation_name, USAGE, NULL);
tinyprint(fd, "USAGE\n\n ", prog, USAGE, NULL);
exit(rc);
}
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "?h")) != -1) {
while ((opt = getopt(argc, argv, "h")) != -1) {
switch (opt) {
case 'h':
case '?':
PrintUsage(1, 0);
default:
PrintUsage(2, 1);
@ -79,18 +59,22 @@ static void GetOpts(int argc, char *argv[]) {
int main(int argc, char *argv[]) {
int i, mode;
char buf[PATH_MAX], *endptr;
prog = argv[0];
if (!prog) prog = "chmod";
GetOpts(argc, argv);
if (argc - optind < 2) {
PrintUsage(2, 1);
tinyprint(2, prog, ": missing operand\n", NULL);
exit(1);
}
mode = strtol(argv[optind], &endptr, 8) & 07777;
if (*endptr) {
Print(2, "chmod: invalid mode octal\n", NULL);
tinyprint(2, prog, ": invalid mode octal\n", NULL);
exit(1);
}
for (i = optind + 1; i < argc; ++i) {
if (chmod(argv[i], mode) == -1) {
SysExit(argv[i], "chmod");
perror(argv[i]);
exit(1);
}
}
return 0;

View file

@ -24,6 +24,7 @@
#include "libc/fmt/fmt.h"
#include "libc/fmt/libgen.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
@ -91,16 +92,14 @@ bool IsSymlink(const char *path) {
return res;
}
wontreturn void PrintUsage(int rc, FILE *f) {
fputs("usage: ", f);
fputs(prog, f);
fputs(USAGE, f);
wontreturn void PrintUsage(int rc, int fd) {
tinyprint(fd, "USAGE\n\n ", prog, USAGE, NULL);
exit(rc);
}
void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "?hfnaprR")) != -1) {
while ((opt = getopt(argc, argv, "hfnaprR")) != -1) {
switch (opt) {
case 'f':
force = true;
@ -118,10 +117,9 @@ void GetOpts(int argc, char *argv[]) {
flags |= COPYFILE_PRESERVE_TIMESTAMPS;
break;
case 'h':
case '?':
PrintUsage(EXIT_SUCCESS, stdout);
PrintUsage(0, 1);
default:
PrintUsage(EX_USAGE, stderr);
PrintUsage(1, 2);
}
}
}
@ -146,8 +144,7 @@ int Visit(const char *fpath, const struct stat *sb, int tflag,
Cp(srcfile, dstfile);
return 0;
default:
fputs(fpath, stderr);
fputs(": can't handle file type\n", stderr);
tinyprint(2, fpath, ": bad file type\n", NULL);
exit(1);
}
}
@ -157,7 +154,7 @@ char *Join(const char *a, const char *b) {
n = strlen(a);
m = strlen(b);
if (n + 1 + m + 1 > sizeof(dstfile)) {
fputs("error: cp: path too long\n", stderr);
tinyprint(2, prog, ": path too long\n", NULL);
exit(1);
}
stpcpy(stpcpy(stpcpy(dstfile, a), "/"), b);
@ -191,8 +188,7 @@ void Cp(char *src, char *dst) {
basename(dst);
if (IsDirectory(src)) {
if (!recursive) {
fputs(prog, stderr);
fputs(": won't copy directory without -r flag.\n", stderr);
tinyprint(2, prog, ": won't copy directory without -r flag\n", NULL);
exit(1);
}
strcpy(dstdir, dst);
@ -208,10 +204,7 @@ void Cp(char *src, char *dst) {
strcpy(srcdir, "");
}
if (nftw(src, Visit, 20, 0) == -1) {
fputs(prog, stderr);
fputs(": nftw failed: ", stderr);
fputs(_strerdoc(errno), stderr);
fputs("\n", stderr);
perror(src);
exit(1);
}
return;
@ -219,37 +212,49 @@ void Cp(char *src, char *dst) {
if (IsDirectory(dst)) {
dst = Join(dst, basename(src));
}
if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail;
strcpy(mkbuf, dst);
if (makedirs(dirname(mkbuf), 0755) == -1) goto OnFail;
if (IsSymlink(src)) {
if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) goto OnFail;
linkbuf[rc] = 0;
if (symlink(linkbuf, dst) == -1) goto OnFail;
} else {
if (!MovePreservingDestinationInode(src, dst)) goto OnFail;
if (!force && access(dst, W_OK) == -1 && errno != ENOENT) {
perror(dst);
exit(1);
}
strcpy(mkbuf, dst);
if (makedirs((s = dirname(mkbuf)), 0755) == -1) {
perror(s);
exit(1);
}
if (IsSymlink(src)) {
if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) {
perror(src);
exit(1);
}
linkbuf[rc] = 0;
if (symlink(linkbuf, dst) == -1) {
perror(dst);
exit(1);
}
} else {
if (!MovePreservingDestinationInode(src, dst)) {
perror(src);
exit(1);
}
}
return;
OnFail:
s = _strerdoc(errno);
fputs(prog, stderr);
fputs(": ", stderr);
fputs(src, stderr);
fputs(" ", stderr);
fputs(dst, stderr);
fputs(": ", stderr);
fputs(s, stderr);
fputs("\n", stderr);
exit(1);
}
int main(int argc, char *argv[]) {
int i;
prog = argc > 0 ? argv[0] : "cp.com";
prog = argv[0];
if (!prog) prog = "cp";
GetOpts(argc, argv);
if (argc - optind < 2) PrintUsage(EX_USAGE, stderr);
if (argc - optind < 2) {
tinyprint(2, prog, ": missing operand\n", NULL);
exit(1);
}
for (i = optind; i < argc - 1; ++i) {
Cp(argv[i], argv[argc - 1]);
}
return 0;
}

View file

@ -73,32 +73,20 @@ static const char *epath;
static Elf64_Xword symcount;
static const Elf64_Ehdr *elf;
nullterminated() static void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
static wontreturn void Die(const char *reason) {
Print(2, epath, ": ", reason, "\n", NULL);
tinyprint(2, epath, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void SysExit(const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, epath, ": ", func, " failed with ", errstr, "\n", NULL);
tinyprint(2, epath, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\n\
tinyprint(fd, "\n\
NAME\n\
\n\
Cosmopolitan Object Fixer\n\
@ -106,7 +94,7 @@ NAME\n\
SYNOPSIS\n\
\n\
",
program_invocation_name, " [FLAGS] OBJECT...\n\
program_invocation_name, " [FLAGS] OBJECT...\n\
\n\
DESCRIPTION\n\
\n\
@ -124,7 +112,7 @@ FLAGS\n\
-c checks only mode\n\
\n\
",
NULL);
NULL);
exit(exitcode);
}
@ -143,10 +131,10 @@ static void GetOpts(int argc, char *argv[]) {
}
}
if (optind == argc) {
Print(2,
"error: no elf object files specified\n"
"run ",
program_invocation_name, " -h for usage\n", NULL);
tinyprint(2,
"error: no elf object files specified\n"
"run ",
program_invocation_name, " -h for usage\n", NULL);
exit(1);
}
}
@ -184,11 +172,11 @@ static void CheckPrivilegedCrossReferences(void) {
if (~shdr->sh_flags & SHF_EXECINSTR) continue; // data reference
if ((secname = GetElfString(elf, esize, secstrs, shdr->sh_name)) &&
strcmp(".privileged", secname)) {
Print(2, epath,
": code in .privileged section "
"references symbol '",
GetElfString(elf, esize, symstrs, syms[x].st_name),
"' in unprivileged code section '", secname, "'\n", NULL);
tinyprint(2, epath,
": code in .privileged section "
"references symbol '",
GetElfString(elf, esize, symstrs, syms[x].st_name),
"' in unprivileged code section '", secname, "'\n", NULL);
exit(1);
}
}

View file

@ -289,7 +289,8 @@ void Decompress(const char *inpath) {
int main(int argc, char *argv[]) {
int i;
prog = argc > 0 ? argv[0] : "cp.com";
prog = argv[0];
if (!prog) prog = "gzip";
GetOpts(argc, argv);
if (opt_decompress) {
if (optind == argc) {

View file

@ -52,7 +52,7 @@ void PrintUsage(int rc, FILE *f) {
void GetOpts(int argc, char *argv[]) {
int opt;
bits_ = 64;
while ((opt = getopt(argc, argv, "?hbs")) != -1) {
while ((opt = getopt(argc, argv, "hbs")) != -1) {
switch (opt) {
case 's':
succinct_ = true;
@ -60,7 +60,6 @@ void GetOpts(int argc, char *argv[]) {
case 'b':
bits_ = atoi(optarg);
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:

View file

@ -8,14 +8,9 @@
*/
#endif
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/x/x.h"
#include "third_party/getopt/getopt.internal.h"
#define USAGE \
@ -30,19 +25,19 @@ FLAGS\n\
const char *prog;
wontreturn void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(prog, f);
fputs(USAGE, f);
wontreturn void PrintUsage(int rc, int fd) {
tinyprint(fd, "USAGE\n\n ", prog, USAGE, NULL);
exit(rc);
}
int main(int argc, char *argv[]) {
int i, mode = 0755;
int (*mkdirp)(const char *, unsigned) = mkdir;
prog = argc > 0 ? argv[0] : "mkdir.com";
while ((i = getopt(argc, argv, "?hpm:")) != -1) {
prog = argv[0];
if (!prog) prog = "mkdir";
while ((i = getopt(argc, argv, "hpm:")) != -1) {
switch (i) {
case 'p':
mkdirp = makedirs;
@ -50,31 +45,21 @@ int main(int argc, char *argv[]) {
case 'm':
mode = strtol(optarg, 0, 8);
break;
case '?':
case 'h':
PrintUsage(0, stdout);
PrintUsage(0, 1);
default:
PrintUsage(EX_USAGE, stderr);
PrintUsage(1, 2);
}
}
if (optind == argc) {
fputs(prog, stderr);
fputs(": missing argument\n", stderr);
fputs("Try '", stderr);
fputs(prog, stderr);
fputs(" -h' for more information.\n", stderr);
tinyprint(2, prog, ": missing operand\n", NULL);
exit(1);
}
for (i = optind; i < argc; ++i) {
if (mkdirp(argv[i], mode) == -1) {
fputs(prog, stderr);
fputs(": cannot create directory '", stderr);
fputs(argv[i], stderr);
fputs("' ", stderr);
fputs(_strerdoc(errno), stderr);
fputc('\n', stderr);
perror(argv[i]);
exit(1);
}
}

View file

@ -62,27 +62,15 @@ char linkbuf[PATH_MAX];
void Mv(char *, char *);
nullterminated() void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
wontreturn void Die(const char *path, const char *reason) {
Print(2, path, ": ", reason, "\n", NULL);
tinyprint(2, path, ": ", reason, "\n", NULL);
exit(1);
}
wontreturn void SysExit(const char *path, const char *func) {
wontreturn void SysDie(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, path, ": ", func, "() failed with ", errstr, "\n", NULL);
tinyprint(2, path, ": ", func, ": ", errstr, "\n", NULL);
exit(1);
}
@ -108,7 +96,7 @@ bool IsSymlink(const char *path) {
}
wontreturn void PrintUsage(int rc, int fd) {
Print(fd, "usage: ", prog, USAGE, NULL);
tinyprint(fd, "usage: ", prog, USAGE, NULL);
exit(rc);
}
@ -161,7 +149,7 @@ char *Join(const char *a, const char *b) {
n = strlen(a);
m = strlen(b);
if (n + 1 + m + 1 > sizeof(dstfile)) {
Print(2, "error: mv: path too long\n", NULL);
tinyprint(2, "error: mv: path too long\n", NULL);
exit(1);
}
stpcpy(stpcpy(stpcpy(dstfile, a), "/"), b);
@ -192,7 +180,7 @@ void Mv(char *src, char *dst) {
strcpy(srcdir, "");
}
if (nftw(src, Visit, 20, 0) == -1) {
SysExit(src, "nftw");
SysDie(src, "nftw");
}
return;
}
@ -200,30 +188,31 @@ void Mv(char *src, char *dst) {
dst = Join(dst, basename(src));
}
if (!force && access(dst, W_OK) == -1 && errno != ENOENT) {
SysExit(dst, "access");
SysDie(dst, "access");
}
strcpy(mkbuf, dst);
if (makedirs((d = dirname(mkbuf)), 0755) == -1) {
SysExit(d, "makedirs");
SysDie(d, "makedirs");
}
if (IsSymlink(src)) {
if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) {
SysExit(src, "readlink");
SysDie(src, "readlink");
}
linkbuf[rc] = 0;
if (symlink(linkbuf, dst)) {
SysExit(dst, "symlink");
SysDie(dst, "symlink");
}
} else {
if (rename(src, dst)) {
SysExit(src, "rename");
SysDie(src, "rename");
}
}
}
int main(int argc, char *argv[]) {
int i;
prog = argc > 0 ? argv[0] : "mv.com";
prog = argv[0];
if (!prog) prog = "mv";
GetOpts(argc, argv);
if (argc - optind < 2) PrintUsage(1, 2);
for (i = optind; i < argc - 1; ++i) {

View file

@ -1,79 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/o.h"
#include "third_party/getopt/getopt.internal.h"
char buf[512];
static void Write(const char *s, ...) {
va_list va;
va_start(va, s);
do {
write(2, s, strlen(s));
} while ((s = va_arg(va, const char *)));
va_end(va);
}
wontreturn void SysExit(int rc, const char *call, const char *thing) {
int err;
char ibuf[12];
const char *estr;
err = errno;
FormatInt32(ibuf, err);
estr = _strerdoc(err);
if (!estr) estr = "EUNKNOWN";
Write(thing, ": ", call, "() failed: ", estr, " (", ibuf, ")\n", 0);
exit(rc);
}
int main(int argc, char *argv[]) {
int i, opt;
const char *outpath = "/dev/stdout";
while ((opt = getopt(argc, argv, "o:")) != -1) {
switch (opt) {
case 'o':
outpath = optarg;
break;
default:
return 1;
}
}
int out = open(outpath, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (out == -1) SysExit(2, "open", outpath);
for (i = optind; i < argc; ++i) {
int in = open(argv[i], O_RDONLY);
if (in == -1) SysExit(3, "open", argv[i]);
for (;;) {
ssize_t rc = read(in, buf, 512);
if (rc == -1) SysExit(3, "read", argv[i]);
if (!rc) break;
ssize_t rc2 = write(out, buf, rc);
if (rc2 != rc) SysExit(4, "write", outpath);
}
if (close(in) == -1) SysExit(5, "close", argv[i]);
}
if (close(out) == -1) SysExit(6, "close", outpath);
}

View file

@ -153,27 +153,15 @@ struct Relas {
} * p;
} prtu;
nullterminated() static void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
static wontreturn void Die(const char *path, const char *reason) {
Print(2, path, ": ", reason, "\n", NULL);
tinyprint(2, path, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void SysExit(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerrno(errno))) errstr = "EUNKNOWN";
Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
tinyprint(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
@ -321,7 +309,7 @@ static void WritePackage(struct Package *pkg) {
}
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\n\
tinyprint(fd, "\n\
NAME\n\
\n\
Cosmopolitan Monorepo Packager\n\
@ -329,7 +317,7 @@ NAME\n\
SYNOPSIS\n\
\n\
",
program_invocation_name, " [FLAGS] OBJECT...\n\
program_invocation_name, " [FLAGS] OBJECT...\n\
\n\
DESCRIPTION\n\
\n\
@ -345,7 +333,7 @@ FLAGS\n\
-d PATH package dependency path [repeatable]\n\
\n\
",
NULL);
NULL);
exit(exitcode);
}
@ -370,14 +358,15 @@ static void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
}
}
if (pkg->path == -1) {
Print(2, "error: no packages passed to package.com\n", NULL);
tinyprint(2, "error: no packages passed to package.com\n", NULL);
exit(1);
}
if (optind == argc) {
Print(2,
"no objects passed to package.com; is your foo.mk $(FOO_OBJS) glob "
"broken?\n",
NULL);
tinyprint(
2,
"no objects passed to package.com; is your foo.mk $(FOO_OBJS) glob "
"broken?\n",
NULL);
exit(1);
}
getargs_init(&ga, argv + optind);
@ -495,7 +484,7 @@ static void LoadPriviligedRefsToUndefs(struct Package *pkg,
if (obj->syms[x].st_shndx) continue; // symbol is defined
if (ELF64_ST_BIND(obj->syms[x].st_info) != STB_WEAK &&
ELF64_ST_BIND(obj->syms[x].st_info) != STB_GLOBAL) {
Print(2, "warning: undefined symbol not global\n", NULL);
tinyprint(2, "warning: undefined symbol not global\n", NULL);
continue;
}
if (!(s = GetElfString(obj->elf, obj->size, obj->strs,
@ -602,13 +591,13 @@ static void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
undef = &pkg->undefs.p[i];
if (undef->bind_ == STB_WEAK) continue;
if (!FindSymbol(pkg->strings.p + undef->name, pkg, deps, NULL, NULL)) {
Print(2, pkg->strings.p + pkg->path, ": undefined symbol '",
pkg->strings.p + undef->name, "' (",
pkg->strings.p + pkg->objects.p[undef->object].path,
") not defined by direct dependencies:\n", NULL);
tinyprint(2, pkg->strings.p + pkg->path, ": undefined symbol '",
pkg->strings.p + undef->name, "' (",
pkg->strings.p + pkg->objects.p[undef->object].path,
") not defined by direct dependencies:\n", NULL);
for (j = 0; j < deps->i; ++j) {
dep = deps->p[j];
Print(2, "\t", dep->strings.p + dep->path, "\n", NULL);
tinyprint(2, "\t", dep->strings.p + dep->path, "\n", NULL);
}
exit(1);
}
@ -626,10 +615,11 @@ static void CheckYourPrivilege(struct Package *pkg, struct Packages *deps) {
name = prtu.p[i].symbol_name;
if (FindSymbol(name, pkg, deps, &dep, &sym) &&
dep->sections.p[sym->section].kind == kText) {
Print(2, prtu.p[i].object_path,
": privileged code referenced unprivileged symbol '", name,
"' in section '",
dep->strings.p + dep->sections.p[sym->section].name, "'\n", NULL);
tinyprint(2, prtu.p[i].object_path,
": privileged code referenced unprivileged symbol '", name,
"' in section '",
dep->strings.p + dep->sections.p[sym->section].name, "'\n",
NULL);
++f;
}
}

View file

@ -119,9 +119,7 @@ int main(int argc, char *argv[]) {
printf(U(argv[1]), argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
return 0;
default:
if (argc > 0) {
fprintf(stderr, "%s: %s format [arguments]\n", argv[0], argv[0]);
}
fprintf(stderr, "%s: %s format [arguments]\n", argv[0], argv[0]);
return 1;
}
}

View file

@ -1,990 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/bits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/x/xasprintf.h"
#include "libc/x/xgetline.h"
#include "third_party/dlmalloc/dlmalloc.h"
#include "third_party/getopt/getopt.internal.h"
/**
* @fileoverview Pythonic System Call Trace
*
* This program invokes `strace` as a subprocess and turns its output
* into Python data structures. It is useful because strace output is
* this weird plaintext format that's so famously difficult to parse.
*
* For example, you can run this command:
*
* pstrace -o trace.pylog echo hello world
*
* After which you may parse the output with Python:
*
* for line in open('trace.pylog'):
* pid,time,elap,kind,x = eval(line)
* if kind == 1:
* name,ret,args = x
* print "%s%r -> %d" % (name, args, ret)
*
* This program traces the subset of system calls governing processes
* and files. To do that we must track file descriptor lifetimes too.
* We also track system calls that are problematic for build configs,
* such as sockets, since compiling code shouldn't need the Internet.
*
* @note this tool is linux only
* @note freebsd: truss PROC ARGS
* @note appleos: sudo dtruss PROC ARGS
* @note openbsd: ktrace PROC ARGS && kdump -f ktrace.out
* @note windows: https://github.com/rogerorr/NtTrace
*/
#define DEBUG "%ld: %s", lineno, line
#define READ128BE(S) ((uint128_t)READ64BE(S) << 64 | READ64BE((S) + 8))
#define APPEND(L) \
do { \
if (++L.n > L.c) { \
L.c = MAX(11, L.c); \
L.c += L.c >> 1; \
L.p = realloc(L.p, L.c * sizeof(*L.p)); \
} \
bzero(L.p + L.n - 1, sizeof(*L.p)); \
} while (0)
struct Trace {
struct Slices {
long n, c;
struct Slice {
int n, c;
char *p;
} * p;
} slices;
struct HashTable {
long i, n;
struct HashEntry {
long h;
long i;
} * p;
} sliceindex;
struct Strlists {
long n, c;
struct Strlist {
long n, c;
long *p; // slices.p[p[i]]
} * p;
} strlists;
struct Events {
long n, c;
struct Event {
enum EventKind {
EK_NONE,
EK_CALL,
EK_EXIT, // ret is kernel code
EK_SIGNAL, // ret is signal code
EK_KILLED, // ret is signal code
} kind;
unsigned char arity;
unsigned char syscall_;
bool is_interrupted;
int us;
int elap;
int pid;
long sec;
long ret;
long lineno;
struct Arg {
enum ArgKind {
AK_LONG, // x
AK_STR, // slices.p[x]
AK_STRLIST, // strlists.p[x]
AK_INTPAIR, // (x&0xffffffff, x>>32)
} kind;
long name;
long x;
} arg[6];
} * p;
} events;
};
static const struct Syscall {
char name[16];
} kSyscalls[] = {
{"accept"}, //
{"accept4"}, //
{"access"}, //
{"bind"}, //
{"chdir"}, //
{"chmod"}, //
{"chown"}, //
{"chroot"}, //
{"clone"}, //
{"close"}, //
{"connect"}, //
{"creat"}, //
{"dup"}, //
{"dup2"}, //
{"dup3"}, //
{"epoll_create"}, //
{"epoll_create1"}, //
{"eventfd"}, //
{"eventfd2"}, //
{"execve"}, //
{"execveat"}, //
{"faccessat"}, //
{"fchmodat"}, //
{"fchownat"}, //
{"fdatasync"}, //
{"fcntl"}, //
{"flock"}, //
{"fork"}, //
{"fsync"}, //
{"lchown"}, //
{"link"}, //
{"linkat"}, //
{"listen"}, //
{"memfd_create"}, //
{"mkdir"}, //
{"mkdirat"}, //
{"mknod"}, //
{"mknodat"}, //
{"open"}, //
{"openat"}, //
{"pipe"}, //
{"pipe2"}, //
{"readlink"}, //
{"readlinkat"}, //
{"rename"}, //
{"renameat"}, //
{"renameat2"}, //
{"rmdir"}, //
{"signalfd"}, //
{"signalfd4"}, //
{"socket"}, //
{"socketpair"}, //
{"statfs"}, //
{"symlink"}, //
{"symlinkat"}, //
{"sync"}, //
{"syncfs"}, //
{"timerfd_create"}, //
{"truncate"}, //
{"unlink"}, //
{"unlinkat"}, //
{"utimensat"}, //
{"vfork"}, //
};
static const struct Signal {
char name[8];
unsigned char number;
} kSignals[] = {
{"SIGABRT", 6}, //
{"SIGALRM", 14}, //
{"SIGBUS", 7}, //
{"SIGCHLD", 17}, //
{"SIGCONT", 18}, //
{"SIGFPE", 8}, //
{"SIGHUP", 1}, //
{"SIGILL", 4}, //
{"SIGINT", 2}, //
{"SIGIO", 29}, //
{"SIGIOT", 6}, //
{"SIGKILL", 9}, //
{"SIGPIPE", 13}, //
{"SIGPOLL", 29}, //
{"SIGPROF", 27}, //
{"SIGPWR", 30}, //
{"SIGQUIT", 3}, //
{"SIGSEGV", 11}, //
{"SIGSTOP", 19}, //
{"SIGSYS", 31}, //
{"SIGTERM", 15}, //
{"SIGTRAP", 5}, //
{"SIGTSTP", 20}, //
{"SIGTTIN", 21}, //
{"SIGTTOU", 22}, //
{"SIGURG", 23}, //
{"SIGUSR1", 10}, //
{"SIGUSR2", 12}, //
{"SIGWINCH", 28}, //
{"SIGXCPU", 24}, //
{"SIGXFSZ", 25}, //
};
static const struct Errno {
char name[16];
unsigned char number;
} kErrnos[] = {
{"E2BIG", 7}, //
{"EACCES", 13}, //
{"EADDRINUSE", 98}, //
{"EADDRNOTAVAIL", 99}, //
{"EADV", 68}, //
{"EAFNOSUPPORT", 97}, //
{"EAGAIN", 11}, //
{"EALREADY", 114}, //
{"EBADE", 52}, //
{"EBADF", 9}, //
{"EBADFD", 77}, //
{"EBADMSG", 74}, //
{"EBADR", 53}, //
{"EBADRQC", 56}, //
{"EBADSLT", 57}, //
{"EBFONT", 59}, //
{"EBUSY", 16}, //
{"ECANCELED", 125}, //
{"ECHILD", 10}, //
{"ECHRNG", 44}, //
{"ECOMM", 70}, //
{"ECONNABORTED", 103}, //
{"ECONNREFUSED", 111}, //
{"ECONNRESET", 104}, //
{"EDEADLK", 35}, //
{"EDESTADDRREQ", 89}, //
{"EDOM", 33}, //
{"EDOTDOT", 73}, //
{"EDQUOT", 122}, //
{"EEXIST", 17}, //
{"EFAULT", 14}, //
{"EFBIG", 27}, //
{"EHOSTDOWN", 112}, //
{"EHOSTUNREACH", 113}, //
{"EHWPOISON", 133}, //
{"EIDRM", 43}, //
{"EILSEQ", 84}, //
{"EINPROGRESS", 115}, //
{"EINTR", 4}, //
{"EINVAL", 22}, //
{"EIO", 5}, //
{"EISCONN", 106}, //
{"EISDIR", 21}, //
{"EISNAM", 120}, //
{"EKEYEXPIRED", 127}, //
{"EKEYREJECTED", 129}, //
{"EKEYREVOKED", 128}, //
{"EL2HLT", 51}, //
{"EL2NSYNC", 45}, //
{"EL3HLT", 46}, //
{"EL3RST", 47}, //
{"ELIBACC", 79}, //
{"ELIBBAD", 80}, //
{"ELIBEXEC", 83}, //
{"ELIBMAX", 82}, //
{"ELIBSCN", 81}, //
{"ELNRNG", 48}, //
{"ELOOP", 40}, //
{"EMEDIUMTYPE", 124}, //
{"EMFILE", 24}, //
{"EMLINK", 31}, //
{"EMSGSIZE", 90}, //
{"EMULTIHOP", 72}, //
{"ENAMETOOLONG", 36}, //
{"ENAVAIL", 119}, //
{"ENETDOWN", 100}, //
{"ENETRESET", 102}, //
{"ENETUNREACH", 101}, //
{"ENFILE", 23}, //
{"ENOANO", 55}, //
{"ENOBUFS", 105}, //
{"ENOCSI", 50}, //
{"ENODATA", 61}, //
{"ENODEV", 19}, //
{"ENOENT", 2}, //
{"ENOEXEC", 8}, //
{"ENOKEY", 126}, //
{"ENOLCK", 37}, //
{"ENOLINK", 67}, //
{"ENOMEDIUM", 123}, //
{"ENOMEM", 12}, //
{"ENOMSG", 42}, //
{"ENONET", 64}, //
{"ENOPKG", 65}, //
{"ENOPROTOOPT", 92}, //
{"ENOSPC", 28}, //
{"ENOSR", 63}, //
{"ENOSTR", 60}, //
{"ENOSYS", 38}, //
{"ENOTBLK", 15}, //
{"ENOTCONN", 107}, //
{"ENOTDIR", 20}, //
{"ENOTEMPTY", 39}, //
{"ENOTNAM", 118}, //
{"ENOTRECOVERABLE", 131}, //
{"ENOTSOCK", 88}, //
{"ENOTSUP", 95}, //
{"ENOTTY", 25}, //
{"ENOTUNIQ", 76}, //
{"ENXIO", 6}, //
{"EOPNOTSUPP", 95}, //
{"EOVERFLOW", 75}, //
{"EOWNERDEAD", 130}, //
{"EPERM", 1}, //
{"EPFNOSUPPORT", 96}, //
{"EPIPE", 32}, //
{"EPROTO", 71}, //
{"EPROTONOSUPPORT", 93}, //
{"EPROTOTYPE", 91}, //
{"ERANGE", 34}, //
{"EREMCHG", 78}, //
{"EREMOTE", 66}, //
{"EREMOTEIO", 121}, //
{"ERESTART", 85}, //
{"ERFKILL", 132}, //
{"EROFS", 30}, //
{"ESHUTDOWN", 108}, //
{"ESOCKTNOSUPPORT", 94}, //
{"ESPIPE", 29}, //
{"ESRCH", 3}, //
{"ESRMNT", 69}, //
{"ESTALE", 116}, //
{"ESTRPIPE", 86}, //
{"ETIME", 62}, //
{"ETIMEDOUT", 110}, //
{"ETOOMANYREFS", 109}, //
{"ETXTBSY", 26}, //
{"EUCLEAN", 117}, //
{"EUNATCH", 49}, //
{"EUSERS", 87}, //
{"EWOULDBLOCK", 11}, //
{"EXDEV", 18}, //
{"EXFULL", 54}, //
};
static char **strace_args;
static size_t strace_args_len;
static volatile bool interrupted;
static long Hash(const void *p, size_t n) {
unsigned h, i;
for (h = i = 0; i < n; i++) {
h += ((unsigned char *)p)[i];
h *= 0x9e3779b1;
}
return MAX(1, h);
}
static uint64_t MakeKey64(const char *p, size_t n) {
char k[8] = {0};
memcpy(k, p, n);
return READ64BE(k);
}
static uint128_t MakeKey128(const char *p, size_t n) {
char k[16] = {0};
memcpy(k, p, n);
return READ128BE(k);
}
static int GetSyscall(const char *name, size_t namelen) {
int m, l, r;
uint128_t x, y;
char *endofname;
if (namelen && namelen <= 16) {
x = MakeKey128(name, namelen);
l = 0;
r = ARRAYLEN(kSyscalls) - 1;
while (l <= r) {
m = (l + r) >> 1;
y = READ128BE(kSyscalls[m].name);
if (x < y) {
r = m - 1;
} else if (x > y) {
l = m + 1;
} else {
return m;
}
}
}
return -1;
}
static int GetErrno(const char *name, size_t namelen) {
int m, l, r;
uint128_t x, y;
char *endofname;
if (namelen && namelen <= 16) {
x = MakeKey128(name, namelen);
l = 0;
r = ARRAYLEN(kErrnos) - 1;
while (l <= r) {
m = (l + r) >> 1;
y = READ128BE(kErrnos[m].name);
if (x < y) {
r = m - 1;
} else if (x > y) {
l = m + 1;
} else {
return kErrnos[m].number;
}
}
}
return -1;
}
static int GetSignal(const char *name, size_t namelen) {
int m, l, r;
uint64_t x, y;
char *endofname;
if (namelen && namelen <= 8) {
x = MakeKey64(name, namelen);
l = 0;
r = ARRAYLEN(kSignals) - 1;
while (l <= r) {
m = (l + r) >> 1;
y = READ64BE(kSignals[m].name);
if (x < y) {
r = m - 1;
} else if (x > y) {
l = m + 1;
} else {
return kSignals[m].number;
}
}
}
return -1;
}
static struct Trace *NewTrace(void) {
return calloc(1, sizeof(struct Trace));
}
static void FreeTrace(struct Trace *t) {
long i;
if (t) {
for (i = 0; i < t->slices.n; ++i) {
free(t->slices.p[i].p);
}
free(t->slices.p);
free(t->sliceindex.p);
for (i = 0; i < t->strlists.n; ++i) {
free(t->strlists.p[i].p);
}
free(t->strlists.p);
free(t->events.p);
free(t);
}
}
static void AppendStrlists(struct Trace *t) {
APPEND(t->strlists);
}
static void AppendStrlist(struct Strlist *l) {
APPEND((*l));
}
static void AppendEvent(struct Trace *t) {
APPEND(t->events);
}
static void AppendSlices(struct Trace *t) {
APPEND(t->slices);
}
static void AppendSlice(struct Slice *s, int c) {
APPEND((*s));
s->p[s->n - 1] = c;
}
static long Intern(struct Trace *t, char *data, long size) {
struct HashEntry *p;
long i, j, k, n, m, h, n2;
h = Hash(data, size);
n = t->sliceindex.n;
i = 0;
if (n) {
k = 0;
do {
i = (h + k + ((k + 1) >> 1)) & (n - 1);
if (t->sliceindex.p[i].h == h &&
t->slices.p[t->sliceindex.p[i].i].n == size &&
!memcmp(t->slices.p[t->sliceindex.p[i].i].p, data, size)) {
free(data);
return t->sliceindex.p[i].i;
}
++k;
} while (t->sliceindex.p[i].h);
}
if (++t->sliceindex.i >= (n >> 1)) {
m = n ? n << 1 : 16;
p = calloc(m, sizeof(struct HashEntry));
for (j = 0; j < n; ++j) {
if (t->sliceindex.p[j].h) {
k = 0;
do {
i = (t->sliceindex.p[j].h + k + ((k + 1) >> 1)) & (m - 1);
++k;
} while (p[i].h);
p[i].h = t->sliceindex.p[j].h;
p[i].i = t->sliceindex.p[j].i;
}
}
k = 0;
do {
i = (h + k + ((k + 1) >> 1)) & (m - 1);
++k;
} while (p[i].h);
free(t->sliceindex.p);
t->sliceindex.p = p;
t->sliceindex.n = m;
}
AppendSlices(t);
t->slices.p[t->slices.n - 1].p = data;
t->slices.p[t->slices.n - 1].n = size;
t->sliceindex.p[i].i = t->slices.n - 1;
t->sliceindex.p[i].h = h;
return t->slices.n - 1;
}
static long ReadCharLiteral(struct Slice *buf, long c, char *p, long *i) {
if (c != '\\') return c;
switch ((c = p[(*i)++])) {
case 'a':
return '\a';
case 'b':
return '\b';
case 't':
return '\t';
case 'n':
return '\n';
case 'v':
return '\v';
case 'f':
return '\f';
case 'r':
return '\r';
case 'e':
return 033;
case 'x':
if (isxdigit(p[*i])) {
c = hextoint(p[(*i)++]);
if (isxdigit(p[*i])) {
c = c * 16 + hextoint(p[(*i)++]);
}
}
return c;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c -= '0';
if ('0' <= p[*i] && p[*i] <= '7') {
c = c * 8 + (p[(*i)++] - '0');
if ('0' <= p[*i] && p[*i] <= '7') {
c = c * 8 + (p[(*i)++] - '0');
}
}
return c;
default:
return c;
}
}
static long GetDuration(long sec1, long us1, long sec2, long us2) {
long elap;
if ((elap = (sec2 - sec1) * 1000000)) {
return elap + 1000000 - us1 + us2;
} else {
return elap + us2 - us1;
}
}
static void Parse(struct Trace *t, const char *line, long lineno) {
char *p, *q;
struct Slice b;
long c, i, j, k, arg, pid, event, sec, us;
p = line;
pid = strtol(p, &p, 10);
while (*p == ' ') ++p;
sec = strtol(p, &p, 10);
CHECK_EQ('.', *p++, DEBUG);
us = strtol(p, &p, 10);
CHECK_EQ(' ', *p++, DEBUG);
if (_startswith(p, "<... ")) {
CHECK_NOTNULL((p = strchr(p, '>')));
++p;
for (event = t->events.n; event--;) {
if (t->events.p[event].pid == pid) {
CHECK(t->events.p[event].is_interrupted, DEBUG);
t->events.p[event].is_interrupted = false;
t->events.p[event].elap =
GetDuration(t->events.p[event].sec, t->events.p[event].us, sec, us);
break;
}
}
CHECK_GE(event, 0);
} else {
AppendEvent(t);
event = t->events.n - 1;
t->events.p[event].pid = pid;
t->events.p[event].sec = sec;
t->events.p[event].us = us;
t->events.p[event].lineno = lineno;
if (_startswith(p, "+++ exited with ")) {
p += strlen("+++ exited with ");
t->events.p[event].kind = EK_EXIT;
t->events.p[event].ret = atoi(p);
return;
} else if (_startswith(p, "+++ killed by ")) {
p += strlen("+++ killed by ");
CHECK((q = strchr(p, ' ')), DEBUG);
t->events.p[event].kind = EK_KILLED;
t->events.p[event].ret = GetSignal(p, q - p);
return;
} else if (_startswith(p, "--- ")) {
p += 4;
CHECK(isalpha(*p), DEBUG);
CHECK((q = strchr(p, ' ')), DEBUG);
t->events.p[event].kind = EK_SIGNAL;
t->events.p[event].ret = GetSignal(p, q - p);
return;
} else if (isalpha(*p) && (q = strchr(p, '('))) {
t->events.p[event].kind = EK_CALL;
CHECK_NE(-1, (t->events.p[event].syscall_ = GetSyscall(p, q - p)), DEBUG);
p = q + 1;
}
}
for (;;) {
if (*p == ',') ++p;
while (*p == ' ') ++p;
CHECK(*p, DEBUG);
if (_startswith(p, "<unfinished ...>")) {
t->events.p[event].is_interrupted = true;
break;
} else if (*p == ')') {
++p;
while (isspace(*p)) ++p;
CHECK_EQ('=', *p++, DEBUG);
while (isspace(*p)) ++p;
CHECK(isdigit(*p) || *p == '-', DEBUG);
t->events.p[event].ret = strtol(p, &p, 0);
if (t->events.p[event].ret == -1) {
while (isspace(*p)) ++p;
CHECK((q = strchr(p, ' ')), DEBUG);
if ((t->events.p[event].ret = GetErrno(p, q - p)) != -1) {
t->events.p[event].ret = -t->events.p[event].ret;
}
}
break;
}
CHECK_LT((arg = t->events.p[event].arity++), 6);
if (isalpha(*p) && !_startswith(p, "NULL")) {
bzero(&b, sizeof(b));
for (; isalpha(*p) || *p == '_'; ++p) {
AppendSlice(&b, *p);
}
t->events.p[event].arg[arg].name = Intern(t, b.p, b.n);
CHECK_EQ('=', *p++, DEBUG);
} else {
t->events.p[event].arg[arg].name = -1;
}
if (_startswith(p, "NULL")) {
p += 4;
t->events.p[event].arg[arg].kind = AK_LONG;
t->events.p[event].arg[arg].x = 0;
} else if (*p == '-' || isdigit(*p)) {
t->events.p[event].arg[arg].kind = AK_LONG;
for (;;) {
t->events.p[event].arg[arg].x |= strtol(p, &p, 0);
if (*p == '|') {
++p;
} else {
break;
}
}
} else if (*p == '{') {
CHECK_NOTNULL((p = strchr(p, '}')), DEBUG);
++p;
} else if (*p == '"') {
bzero(&b, sizeof(b));
for (j = 0; (c = p[++j]);) {
if (c == '"') {
p += j + 1;
break;
}
c = ReadCharLiteral(&b, c, p, &j);
AppendSlice(&b, c);
}
t->events.p[event].arg[arg].kind = AK_STR;
t->events.p[event].arg[arg].x = Intern(t, b.p, b.n);
} else if (*p == '[') {
++p;
if (isdigit(*p)) {
t->events.p[event].arg[arg].kind = AK_INTPAIR;
t->events.p[event].arg[arg].x = strtol(p, &p, 0) & 0xffffffff;
CHECK_EQ(',', *p++, DEBUG);
CHECK_EQ(' ', *p++, DEBUG);
t->events.p[event].arg[arg].x |= strtol(p, &p, 0) << 32;
CHECK_EQ(']', *p++, DEBUG);
} else {
AppendStrlists(t);
for (j = 0;; ++j) {
if (*p == ']') {
++p;
break;
}
if (*p == ',') ++p;
if (*p == ' ') ++p;
CHECK_EQ('"', *p, DEBUG);
bzero(&b, sizeof(b));
for (k = 0; (c = p[++k]);) {
if (c == '"') {
p += k + 1;
break;
}
c = ReadCharLiteral(&b, c, p, &k);
AppendSlice(&b, c);
}
AppendStrlist(&t->strlists.p[t->strlists.n - 1]);
t->strlists.p[t->strlists.n - 1]
.p[t->strlists.p[t->strlists.n - 1].n - 1] = Intern(t, b.p, b.n);
}
t->events.p[event].arg[arg].kind = AK_STRLIST;
t->events.p[event].arg[arg].x = t->strlists.n - 1;
}
} else {
CHECK(false, DEBUG);
}
}
}
static void PrintArg(FILE *f, struct Trace *t, long ev, long arg) {
long i, x;
x = t->events.p[ev].arg[arg].name;
if (x != -1) {
fprintf(f, "b%`'.*s:", t->slices.p[x].n, t->slices.p[x].p);
}
x = t->events.p[ev].arg[arg].x;
switch (t->events.p[ev].arg[arg].kind) {
case AK_LONG:
fprintf(f, "%ld", x);
break;
case AK_STR:
fprintf(f, "b%`'.*s", t->slices.p[x].n, t->slices.p[x].p);
break;
case AK_INTPAIR:
fprintf(f, "(%d,%d)", x >> 32, x);
break;
case AK_STRLIST:
fprintf(f, "(");
for (i = 0; i < t->strlists.p[x].n; ++i) {
fprintf(f, "b%`'.*s,", t->slices.p[t->strlists.p[x].p[i]].n,
t->slices.p[t->strlists.p[x].p[i]].p);
}
fprintf(f, ")");
break;
default:
abort();
}
}
static void PrintEvent(FILE *f, struct Trace *t, long ev) {
long arg;
fprintf(f, "(%d,%ld,%d,%d,", t->events.p[ev].pid,
t->events.p[ev].sec * 1000000 + t->events.p[ev].us,
t->events.p[ev].elap, t->events.p[ev].kind);
switch (t->events.p[ev].kind) {
case EK_EXIT:
case EK_SIGNAL:
case EK_KILLED:
fprintf(f, "%d", t->events.p[ev].ret);
break;
case EK_CALL:
CHECK_LT(t->events.p[ev].syscall_, ARRAYLEN(kSyscalls));
fprintf(f, "(b%`'s,%ld,", kSyscalls[t->events.p[ev].syscall_].name,
t->events.p[ev].ret);
fprintf(f, "%c",
t->events.p[ev].arity && t->events.p[ev].arg[0].name != -1 ? '{'
: '(');
for (arg = 0; arg < t->events.p[ev].arity; ++arg) {
PrintArg(f, t, ev, arg);
fprintf(f, ",");
}
fprintf(f, "%c)",
t->events.p[ev].arity && t->events.p[ev].arg[0].name != -1 ? '}'
: ')');
break;
default:
break;
}
fprintf(f, ")");
}
static void AppendArg(char *arg) {
strace_args = realloc(strace_args, ++strace_args_len * sizeof(*strace_args));
strace_args[strace_args_len - 1] = arg;
}
static wontreturn void PrintUsage(FILE *f, int rc) {
fprintf(f, "Usage: %s [-o OUT] PROG [ARGS...]\n", program_invocation_name);
exit(rc);
}
int main(int argc, char *argv[]) {
int i;
int ws;
int opt;
int pid;
long ev;
FILE *fin;
FILE *fout;
char *line;
long lineno;
char *strace;
int pipefds[2];
struct Trace *t;
sigset_t block, mask;
struct sigaction ignore, saveint, savequit;
/*
* parse prefix arguments
*/
fout = stderr;
while ((opt = getopt(argc, argv, "?ho:")) != -1) {
switch (opt) {
case 'o':
fout = fopen(optarg, "w");
break;
case 'h':
case '?':
PrintUsage(stdout, EXIT_SUCCESS);
default:
PrintUsage(stderr, EX_USAGE);
}
}
if (optind == argc) {
PrintUsage(stderr, EX_USAGE);
}
/*
* resolve full paths of dependencies
*/
if ((strace = commandvenv("STRACE", "strace"))) {
strace = strdup(strace);
} else {
fprintf(stderr, "error: please install strace\n");
exit(1);
}
/*
* create strace argument list
*/
AppendArg("strace");
AppendArg("-q"); // don't log attach/detach noise
AppendArg("-v"); // don't abbreviate arrays
AppendArg("-f"); // follow subprocesses
AppendArg("-ttt"); // print unixseconds.micros
AppendArg("-X"); // print numbers instead of symbols
AppendArg("raw"); // e.g. 2 vs. O_RDWR
AppendArg("-s"); // don't abbreviate data
AppendArg("805306368"); // strace won't let us go higher
AppendArg("-e"); // system calls that matter
AppendArg(
"open,close,access,pipe,dup,dup2,socket,connect,accept,bind,listen,"
"socketpair,fork,vfork,execve,clone,flock,fsync,fdatasync,truncate,chdir,"
"rename,mkdir,rmdir,creat,link,unlink,symlink,readlink,chmod,chown,fcntl,"
"lchown,mknod,mknodat,statfs,chroot,sync,epoll_create,openat,mkdirat,"
"fchownat,unlinkat,renameat,linkat,symlinkat,readlinkat,fchmodat,fchdir,"
"faccessat,utimensat,accept4,dup3,pipe2,epoll_create1,signalfd,signalfd4,"
"eventfd,eventfd2,timerfd_create,syncfs,renameat2,memfd_create,execveat");
CHECK_NE(-1, pipe(pipefds));
AppendArg("-o");
AppendArg(xasprintf("/dev/fd/%d", pipefds[1]));
for (i = optind; i < argc; ++i) {
AppendArg(argv[i]);
}
AppendArg(NULL);
/*
* spawn strace
*/
ignore.sa_flags = 0;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
sigaction(SIGINT, &ignore, &saveint);
sigaction(SIGQUIT, &ignore, &savequit);
sigfillset(&block);
sigprocmask(SIG_BLOCK, &block, &mask);
CHECK_NE(-1, (pid = vfork()));
if (!pid) {
close(pipefds[0]);
sigaction(SIGINT, &saveint, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &mask, NULL);
execv(strace, strace_args);
_exit(127);
}
close(pipefds[1]);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_SETMASK, &mask, NULL);
/*
* read output of strace until eof
*/
fin = fdopen(pipefds[0], "r");
t = NewTrace();
for (ev = 0, lineno = 1; !interrupted && (line = xgetline(fin)); ++lineno) {
_chomp(line);
Parse(t, line, lineno);
free(line);
for (; ev < t->events.n && !t->events.p[ev].is_interrupted; ++ev) {
PrintEvent(fout, t, ev);
fprintf(fout, "\n");
}
}
FreeTrace(t);
CHECK_NE(-1, fclose(fout));
/*
* wait for strace to exit
*/
while (waitpid(pid, &ws, 0) == -1) {
CHECK_EQ(EINTR, errno);
}
CHECK_NE(-1, fclose(fin));
/*
* propagate exit
*/
if (WIFEXITED(ws)) {
return WEXITSTATUS(ws);
} else {
return 128 + WTERMSIG(ws);
}
}

View file

@ -17,21 +17,27 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* @fileoverview Tool for printing current directory.
*/
char path[PATH_MAX];
int main(int argc, char *argv[]) {
char *p;
if ((p = getcwd(path, sizeof(path)))) {
fputs(p, stdout);
fputc('\n', stdout);
return 0;
} else {
return 1;
char path[PATH_MAX + 2];
if (!getcwd(path, PATH_MAX)) {
perror(argv[0]);
exit(1);
}
strcat(path, "\n");
if (write(1, path, strlen(path)) == -1) {
perror("write");
exit(1);
}
return 0;
}

View file

@ -1,134 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/check.h"
#include "libc/mem/alg.h"
#include "libc/mem/gc.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/x/x.h"
/**
* @fileoverview Pretty fast substring refactor tool.
*/
static const char kBefore[] = "\
Copyright 2020 Justine Alexandra Roberts Tunney \n\
\n\
This program is free software; you can redistribute it and/or modify \n\
it under the terms of the GNU General Public License as published by \n\
the Free Software Foundation; version 2 of the License. \n\
\n\
This program is distributed in the hope that it will be useful, but \n\
WITHOUT ANY WARRANTY; without even the implied warranty of \n\
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU \n\
General Public License for more details. \n\
\n\
You should have received a copy of the GNU General Public License \n\
along with this program; if not, write to the Free Software \n\
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA \n\
02110-1301 USA \n\
";
const char kAfter[] = "\
Copyright 2020 Justine Alexandra Roberts Tunney \n\
\n\
Permission to use, copy, modify, and/or distribute this software for \n\
any purpose with or without fee is hereby granted, provided that the \n\
above copyright notice and this permission notice appear in all copies. \n\
\n\
THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL │\n\
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED \n\
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE \n\
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL \n\
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR \n\
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER \n\
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR \n\
PERFORMANCE OF THIS SOFTWARE. \n\
";
#if 0
static const char kBefore[] = "\
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│";
const char kAfter[] = "\
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│";
#endif
void RefactorFile(const char *path) {
int fd;
struct stat st;
size_t len, partlen, len1, len2;
char *mem, *spot = NULL, *part1, *part2;
CHECK_NE(-1, (fd = open(path, O_RDONLY)));
CHECK_NE(-1, fstat(fd, &st));
len2 = 0;
if ((len = st.st_size)) {
CHECK_NE(MAP_FAILED,
(mem = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)));
partlen = sizeof(kBefore) - 1;
if ((spot = memmem(mem, len, kBefore, partlen))) {
part1 = gc(xmalloc((len1 = spot - mem)));
part2 = gc(xmalloc((len2 = len - partlen - (spot - mem))));
memcpy(part1, mem, len1);
memcpy(part2, spot + partlen, len2);
}
CHECK_NE(-1, munmap(mem, len));
}
CHECK_NE(-1, close(fd));
if (spot) {
fprintf(stderr, "found! %s\n", path);
CHECK_NE(-1, (fd = open(path, O_RDWR | O_TRUNC)));
CHECK_EQ(len1, write(fd, part1, len1));
CHECK_EQ(sizeof(kAfter) - 1, write(fd, kAfter, sizeof(kAfter) - 1));
CHECK_EQ(len2, write(fd, part2, len2));
CHECK_NE(-1, close(fd));
}
}
void RefactorDir(const char *dpath) {
DIR *dir;
struct dirent *ent;
char *path = gc(xmalloc(4096));
CHECK_NOTNULL(dir = opendir(firstnonnull(dpath, ".")));
while ((ent = readdir(dir))) {
if (_startswith(ent->d_name, ".")) continue;
if (strcmp(ent->d_name, "o") == 0) continue;
snprintf(path, 4096, "%s%s%s", dpath ? dpath : "", dpath ? "/" : "",
ent->d_name);
if (isdirectory(path)) {
RefactorDir(path);
} else if (isregularfile(path)) {
RefactorFile(path);
}
}
CHECK_NE(-1, closedir(dir));
}
int main(int argc, char *argv[]) {
RefactorDir(NULL);
return 0;
}

View file

@ -1,251 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/errfuns.h"
#include "third_party/getopt/getopt.internal.h"
#define USAGE1 \
"NAME\n\
\n\
rle - Run Length Encoder\n\
\n\
SYNOPSIS\n\
\n\
"
#define USAGE2 \
" [FLAGS] [FILE...]\n\
\n\
DESCRIPTION\n\
\n\
This is a primitive compression algorithm. Its advantage is that\n\
the concomitant rldecode() library is seventeen bytes, and works\n\
on IA-16, IA-32, and NexGen32e without needing to be recompiled.\n\
\n\
This CLI is consistent with gzip, bzip2, lzma, etc.\n\
\n\
FLAGS\n\
\n\
-1 .. -9 ignored\n\
-a ignored\n\
-c send to stdout\n\
-d decompress\n\
-f ignored\n\
-t test integrity\n\
-S SUFFIX overrides .rle extension\n\
-h shows this information\n"
FILE *fin_, *fout_;
bool decompress_, test_;
const char *suffix_, *hint_;
void StartErrorMessage(void) {
fputs("error: ", stderr);
fputs(hint_, stderr);
fputs(": ", stderr);
}
void PrintIoErrorMessage(void) {
int err;
err = errno;
StartErrorMessage();
fputs(strerror(err), stderr);
fputc('\n', stderr);
}
void PrintUsage(int rc, FILE *f) {
fputs(USAGE1, f);
fputs(program_invocation_name, f);
fputs(USAGE2, f);
exit(rc);
}
void GetOpts(int argc, char *argv[]) {
int opt;
fin_ = stdin;
suffix_ = ".rle";
while ((opt = getopt(argc, argv, "123456789S:acdfho:t")) != -1) {
switch (opt) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'f':
break;
case 'c':
fout_ = stdout;
break;
case 'd':
decompress_ = true;
break;
case 't':
test_ = true;
break;
case 'o':
fclose(fout_);
if (!(fout_ = fopen((hint_ = optarg), "w"))) {
PrintIoErrorMessage();
exit(1);
}
break;
case 'S':
suffix_ = optarg;
break;
case 'h':
case '?':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
}
int RunLengthEncode1(void) {
int byte1, byte2, runlength;
byte2 = -1;
runlength = 0;
if ((byte1 = fgetc(fin_)) == -1) return -1;
do {
while (++runlength < 255) {
if ((byte2 = fgetc(fin_)) != byte1) break;
}
if (fputc(runlength, fout_) == -1 || fputc(byte1, fout_) == -1) {
return -1;
}
runlength = 0;
} while ((byte1 = byte2) != -1);
return feof(fin_) ? 0 : -1;
}
int RunLengthEncode2(void) {
return fputc(0, fout_) | fputc(0, fout_);
}
int EmitRun(unsigned char count, unsigned char byte) {
do {
if (fputc(byte, fout_) == -1) return -1;
} while (--count);
return 0;
}
int RunLengthDecode(void) {
int byte1, byte2;
if ((byte1 = fgetc(fin_)) == -1) return einval();
if ((byte2 = fgetc(fin_)) == -1) return einval();
while (byte1) {
if (!test_ && EmitRun(byte1, byte2) == -1) return -1;
if ((byte1 = fgetc(fin_)) == -1) break;
if ((byte2 = fgetc(fin_)) == -1) return einval();
}
if (byte1 != 0 || byte2 != 0) return einval();
fgetc(fin_);
return feof(fin_) ? 0 : -1;
}
int RunLengthCode(void) {
if (test_ || decompress_) {
return RunLengthDecode();
} else {
return RunLengthEncode1();
}
}
int Run(char **paths, size_t count) {
int rc;
char *p;
size_t i, suffixlen;
const char pathbuf[PATH_MAX];
if (!count) {
hint_ = "/dev/stdin";
if (!fout_) fout_ = stdout;
rc = RunLengthCode();
rc |= fclose(fin_);
fin_ = 0;
} else {
rc = fclose(fin_);
fin_ = 0;
for (i = 0; i < count && rc != -1; ++i) {
rc = -1;
if ((fin_ = fopen((hint_ = paths[i]), "r"))) {
if (test_ || fout_) {
rc = RunLengthCode();
} else {
suffixlen = strlen(suffix_);
if (!IsTrustworthy() &&
strlen(paths[i]) + suffixlen >= ARRAYLEN(pathbuf)) {
return eoverflow();
}
p = stpcpy(pathbuf, paths[i]);
if (!decompress_) {
strcpy(p, suffix_);
} else if (p - pathbuf > suffixlen &&
memcmp(p - suffixlen, suffix_, suffixlen) == 0) {
p[-suffixlen] = '\0';
} else {
return enotsup();
}
if ((fout_ = fopen((hint_ = pathbuf), "w"))) {
rc = RunLengthCode();
if (rc != -1 && !decompress_) {
rc = RunLengthEncode2();
}
if ((rc |= fclose(fout_)) != -1) {
unlink(paths[i]);
}
fout_ = 0;
}
}
rc |= fclose(fin_);
fin_ = 0;
}
}
}
if (rc != -1 && fout_) {
rc = RunLengthEncode2();
rc |= fclose(fout_);
fout_ = 0;
}
return rc;
}
int main(int argc, char *argv[]) {
GetOpts(argc, argv);
if (Run(argv + optind, argc - optind) != -1) {
return EXIT_SUCCESS;
} else {
PrintIoErrorMessage();
return EXIT_FAILURE;
}
}

View file

@ -22,8 +22,6 @@
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/ok.h"
#include "third_party/getopt/getopt.internal.h"
@ -36,63 +34,53 @@ SYNOPSIS\n\
\n\
FLAGS\n\
\n\
-?\n\
-h help\n\
-f force\n\
\n"
bool force;
const char *prog;
static bool force;
static const char *prog;
wontreturn void PrintUsage(int rc, FILE *f) {
fputs("usage: ", f);
fputs(prog, f);
fputs(USAGE, f);
static wontreturn void PrintUsage(int rc, int fd) {
tinyprint(fd, "USAGE\n\n ", prog, USAGE, NULL);
exit(rc);
}
void GetOpts(int argc, char *argv[]) {
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "?hf")) != -1) {
while ((opt = getopt(argc, argv, "hf")) != -1) {
switch (opt) {
case 'f':
force = true;
break;
case 'h':
case '?':
PrintUsage(EXIT_SUCCESS, stdout);
PrintUsage(0, 1);
default:
PrintUsage(EX_USAGE, stderr);
PrintUsage(1, 2);
}
}
}
void Remove(const char *path) {
const char *s;
if (!force && access(path, W_OK) == -1) goto OnFail;
if (unlink(path) == -1) goto OnFail;
return;
OnFail:
if (force && errno == ENOENT) return;
s = _strerdoc(errno);
fputs(prog, stderr);
fputs(": cannot remove '", stderr);
fputs(path, stderr);
fputs("': ", stderr);
fputs(s, stderr);
fputs("\n", stderr);
exit(1);
static void Remove(const char *path) {
if (!force && access(path, W_OK) == -1) {
perror(path);
exit(1);
}
if (unlink(path) == -1) {
if (force && errno == ENOENT) return;
perror(path);
exit(1);
}
}
int main(int argc, char *argv[]) {
int i;
prog = argc > 0 ? argv[0] : "rm.com";
prog = argv[0];
if (!prog) prog = "rm";
if (argc < 2) {
fputs(prog, stderr);
fputs(": missing operand\n"
"Try 'rm -h' for more information.\n",
stderr);
tinyprint(2, prog, ": missing operand\n", NULL);
exit(1);
}

View file

@ -28,17 +28,15 @@
#include "third_party/getopt/getopt.internal.h"
#include "third_party/mbedtls/sha256.h"
#define PROG "sha256sum"
#define USAGE \
"\
Usage: " PROG " [-?hbctw] [PATH...]\n\
"[-?hbctw] [PATH...]\n\
-h help\n\
-c check mode\n\
-b binary mode\n\
-t textual mode\n\
-w warning mode\n\
\n\
cosmopolitan " PROG " v1.0\n\
cosmopolitan sha256sum v1.1\n\
copyright 2022 justine alexandra roberts tunney\n\
notice licenses are embedded in the binary\n\
https://twitter.com/justinetunney\n\
@ -56,11 +54,17 @@ static bool g_warn;
static char g_mode;
static bool g_check;
static int g_mismatches;
static const char *prog;
static wontreturn void PrintUsage(int rc, int fd) {
tinyprint(fd, "Usage: ", prog, USAGE, NULL);
exit(rc);
}
static void GetOpts(int argc, char *argv[]) {
int opt;
g_mode = ' ';
while ((opt = getopt(argc, argv, "?hbctw")) != -1) {
while ((opt = getopt(argc, argv, "hbctw")) != -1) {
switch (opt) {
case 'w':
g_warn = true;
@ -75,28 +79,13 @@ static void GetOpts(int argc, char *argv[]) {
g_mode = '*';
break;
case 'h':
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
exit(0);
PrintUsage(0, 1);
default:
write(2, USAGE, sizeof(USAGE) - 1);
exit(64);
PrintUsage(1, 2);
}
}
}
static ssize_t Write(int fd, const char *s, ...) {
va_list va;
char buf[512];
buf[0] = 0;
va_start(va, s);
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
va_end(va);
return write(fd, buf, strlen(buf));
}
static bool IsModeCharacter(char c) {
switch (c) {
case ' ':
@ -117,7 +106,7 @@ static bool IsSupportedPath(const char *path) {
case '\r':
case '\n':
case '\\':
Write(2, PROG, ": ", path, ": unsupported path\n", NULL);
tinyprint(2, prog, ": ", path, ": unsupported path\n", NULL);
return false;
default:
break;
@ -135,7 +124,7 @@ static bool GetDigest(const char *path, FILE *f, unsigned char digest[32]) {
_unassert(!mbedtls_sha256_update_ret(&ctx, buf, got));
}
if (ferror(f)) {
Write(2, PROG, ": ", path, ": ", _strerdoc(errno), "\n", NULL);
tinyprint(2, prog, ": ", path, ": ", strerror(errno), "\n", NULL);
return false;
}
_unassert(!mbedtls_sha256_finish_ret(&ctx, digest));
@ -150,7 +139,7 @@ static bool ProduceDigest(const char *path, FILE *f) {
if (!IsSupportedPath(path)) return false;
if (!GetDigest(path, f, digest)) return false;
hexpcpy(hexdigest, digest, 32);
Write(1, hexdigest, " ", mode, path, "\n", NULL);
tinyprint(1, hexdigest, " ", mode, path, "\n", NULL);
return true;
}
@ -182,13 +171,13 @@ static bool CheckDigests(const char *path, FILE *f) {
++g_mismatches;
k = false;
}
Write(1, path2, ": ", status, "\n", NULL);
tinyprint(1, path2, ": ", status, "\n", NULL);
} else {
k = false;
}
fclose(f2);
} else {
Write(2, PROG, ": ", path2, ": ", _strerdoc(errno), "\n", NULL);
tinyprint(2, prog, ": ", path2, ": ", strerror(errno), "\n", NULL);
k = false;
}
continue;
@ -196,12 +185,12 @@ static bool CheckDigests(const char *path, FILE *f) {
if (g_warn) {
char linestr[12];
FormatInt32(linestr, line + 1);
Write(2, PROG, ": ", path, ":", linestr, ": ",
"improperly formatted checksum line", "\n", NULL);
tinyprint(2, prog, ": ", path, ":", linestr, ": ",
"improperly formatted checksum line", "\n", NULL);
}
}
if (ferror(f)) {
Write(2, PROG, ": ", path, ": ", _strerdoc(errno), "\n", NULL);
tinyprint(2, prog, ": ", path, ": ", strerror(errno), "\n", NULL);
k = false;
}
return k;
@ -219,6 +208,8 @@ int main(int argc, char *argv[]) {
int i;
FILE *f;
bool k = true;
prog = argv[0];
if (!prog) prog = "sha256sum";
GetOpts(argc, argv);
if (optind == argc) {
f = stdin;
@ -229,7 +220,7 @@ int main(int argc, char *argv[]) {
k &= Process(argv[i], f);
fclose(f);
} else {
Write(2, PROG, ": ", argv[i], ": ", _strerdoc(errno), "\n", NULL);
tinyprint(2, prog, ": ", argv[i], ": ", strerror(errno), "\n", NULL);
k = false;
}
}
@ -237,8 +228,8 @@ int main(int argc, char *argv[]) {
if (g_mismatches) {
char ibuf[12];
FormatInt32(ibuf, g_mismatches);
Write(2, PROG, ": WARNING: ", ibuf, " computed checksum did NOT match\n",
NULL);
tinyprint(2, prog, ": WARNING: ", ibuf,
" computed checksum did NOT match\n", NULL);
}
return !k;
}

View file

@ -17,31 +17,31 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* @fileoverview Command for updating timestamps on files.
* @fileoverview file timestamp update command
*/
int main(int argc, char *argv[]) {
int i;
const char *s, *prog;
prog = argc > 0 ? argv[0] : "touch.com";
const char *prog;
prog = argv[0];
if (!prog) prog = "touch";
if (argc < 2) {
tinyprint(2, prog, ": missing operand\n", NULL);
exit(1);
}
for (i = 1; i < argc; ++i) {
if (touch(argv[i], 0666) == -1) {
s = _strerdoc(errno);
fputs(prog, stderr);
fputs(": cannot touch '", stderr);
fputs(argv[i], stderr);
fputs("': ", stderr);
fputs(s, stderr);
fputs("\n", stderr);
perror(argv[i]);
exit(1);
}
}
return 0;
}

View file

@ -74,7 +74,8 @@ int Visit(const char *fpath, const struct stat *sb, int tflag,
int main(int argc, char *argv[]) {
if (!IsLinux()) return 0;
prog = argc > 0 ? argv[0] : "unbundle.com";
prog = argv[0];
if (!prog) prog = "unbundle";
if (IsDirectory("o/third_party/gcc")) return 0;
makedirs("o/third_party", 0755);
FormatInt32(stpcpy(tmpdir, "o/third_party/gcc."), getpid());

View file

@ -1,330 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/fmt/conv.h"
#include "libc/log/check.h"
#include "libc/math.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/x/xasprintf.h"
/**
* @fileoverview Tool for generating rldecode'd character sets, e.g.
*
* # generate http token table
* o//tool/build/xlat.com -TiC ' ()<>@,;:\"/[]?={}' -i
*/
int dig;
int xlat[256];
bool identity;
const char *symbol;
static int Bing(int c) {
if (!c) return L'';
if (c == ' ') return L'';
if (c == '$') return L'§';
if (c == '\\') return L'';
return kCp437[c & 255];
}
static void Fill(int f(int)) {
int i;
for (i = 0; i < 256; ++i) {
if (f(i)) {
xlat[i] = identity ? i : 1;
}
}
}
static void Invert(void) {
int i;
for (i = 0; i < 256; ++i) {
xlat[i] = !xlat[i];
}
}
static void Negate(void) {
int i;
for (i = 0; i < 256; ++i) {
xlat[i] = ~xlat[i] & 255;
}
}
static void Negative(void) {
int i;
for (i = 0; i < 256; ++i) {
xlat[i] = -xlat[i] & 255;
}
}
static bool ArgNeedsShellQuotes(const char *s) {
if (*s) {
for (;;) {
switch (*s++ & 255) {
case 0:
return false;
case '-':
case '.':
case '/':
case '_':
case '=':
case ':':
case '0' ... '9':
case 'A' ... 'Z':
case 'a' ... 'z':
break;
default:
return true;
}
}
} else {
return true;
}
}
static char *AddShellQuotes(const char *s) {
char *p, *q;
size_t i, j, n;
n = strlen(s);
p = malloc(1 + n * 5 + 1 + 1);
j = 0;
p[j++] = '\'';
for (i = 0; i < n; ++i) {
if (s[i] != '\'') {
p[j++] = s[i];
} else {
p[j + 0] = '\'';
p[j + 1] = '"';
p[j + 2] = '\'';
p[j + 3] = '"';
p[j + 4] = '\'';
j += 5;
}
}
p[j++] = '\'';
p[j] = 0;
if ((q = realloc(p, j + 1))) p = q;
return p;
}
static const char *GetArg(char *argv[], int i, int *k) {
if (argv[*k][i + 1]) {
return argv[*k] + i + 1;
} else {
return argv[++*k];
}
}
int main(int argc, char *argv[]) {
const char *arg;
int i, j, k, opt;
dig = 1;
symbol = "kXlatTab";
for (k = 1; k < argc; ++k) {
if (argv[k][0] != '-') {
for (i = 0; argv[k][i]; ++i) {
/* xlat[argv[k][i] & 255] = identity ? i : dig; */
xlat[argv[k][i] & 255] = identity ? (argv[k][i] & 255) : dig;
}
} else {
i = 0;
moar:
++i;
if ((opt = argv[k][i])) {
switch (opt) {
case 's':
symbol = GetArg(argv, i, &k);
break;
case 'x':
dig = atoi(GetArg(argv, i, &k)) & 255;
break;
case 'i':
Invert();
goto moar;
case 'I':
identity = !identity;
goto moar;
case 'n':
Negative();
goto moar;
case 'N':
Negate();
goto moar;
case 'T':
Fill(isascii);
goto moar;
case 'C':
Fill(iscntrl);
goto moar;
case 'A':
Fill(isalpha);
goto moar;
case 'B':
Fill(isblank);
goto moar;
case 'G':
Fill(isgraph);
goto moar;
case 'P':
Fill(ispunct);
goto moar;
case 'D':
Fill(isdigit);
goto moar;
case 'U':
Fill(isupper);
goto moar;
case 'L':
Fill(islower);
goto moar;
default:
fprintf(stderr, "error: unrecognized option: %c\n", opt);
return 1;
}
}
}
}
////////////////////////////////////////////////////////////
printf("#include \"libc/macros.internal.h\"\n");
printf("\n");
printf("//\tgenerated by:\n");
printf("//\t");
for (i = 0; i < argc; ++i) {
if (i) printf(" ");
printf("%s", !ArgNeedsShellQuotes(argv[i]) ? argv[i]
: _gc(AddShellQuotes(argv[i])));
}
printf("\n");
////////////////////////////////////////////////////////////
printf("//\n");
printf("//\t present absent\n");
printf("//\t ──────────────── ────────────────\n");
for (i = 0; i < 16; ++i) {
char16_t absent[16];
char16_t present[16];
for (j = 0; j < 16; ++j) {
if (xlat[i * 16 + j]) {
absent[j] = L' ';
present[j] = Bing(i * 16 + j);
} else {
absent[j] = Bing(i * 16 + j);
present[j] = L' ';
}
}
printf("//\t %.16hs %.16hs 0x%02x\n", present, absent, i * 16);
}
////////////////////////////////////////////////////////////
printf("//\n");
printf("//\tconst char %s[256] = {\n//\t", symbol);
for (i = 0; i < 16; ++i) {
printf(" ");
for (j = 0; j < 16; ++j) {
printf("%2d,", (char)xlat[i * 16 + j]);
}
printf(" // 0x%02x\n//\t", i * 16);
}
printf("};\n");
printf("\n");
////////////////////////////////////////////////////////////
printf("\t.initbss 300,_init_%s\n", symbol);
printf("%s:\n", symbol);
printf("\t.zero\t256\n");
printf("\t.endobj\t%s,globl\n", symbol);
printf("\t.previous\n");
printf("\n");
////////////////////////////////////////////////////////////
printf("\t.initro 300,_init_%s\n", symbol);
printf("%s.rom:\n", symbol);
int thebloat = 0;
int thetally = 0;
int thecount = 0;
int runstart = 0;
int runchar = -1;
int runcount = 0;
for (i = 0;; ++i) {
if (i < 256 && xlat[i] == runchar) {
++runcount;
} else {
if (runcount) {
printf("\t.byte\t%-24s# %02x-%02x %hc-%hc\n",
_gc(xasprintf("%3d,%d", runcount, runchar)), runstart,
runstart + runcount - 1, Bing(runstart),
Bing(runstart + runcount - 1));
thetally += 2;
thecount += runcount;
}
if (i < 256) {
runcount = 1;
runchar = xlat[i];
runstart = i;
}
}
if (i == 256) {
break;
}
}
CHECK_EQ(256, thecount);
printf("\t.byte\t%-24s# terminator\n", "0,0");
thetally += 2;
thebloat = thetally;
for (i = 0; (thetally + i) % 8; i += 2) {
printf("\t.byte\t%-24s# padding\n", "0,0");
thebloat += 2;
}
printf("\t.endobj\t%s.rom,globl\n", symbol);
printf("\n");
////////////////////////////////////////////////////////////
printf("\t.init.start 300,_init_%s\n", symbol);
printf("\tcall\trldecode\n");
thebloat += 5;
int padding = 8 - thetally % 8;
if (padding < 8) {
if (padding >= 4) {
thebloat += 1;
printf("\tlodsl\n");
padding -= 4;
}
if (padding >= 2) {
thebloat += 2;
printf("\tlodsw\n");
}
}
printf("\t.init.end 300,_init_%s\n", symbol);
////////////////////////////////////////////////////////////
printf("\n");
printf("//\t%d bytes total (%d%% original size)\n", thebloat,
(int)round((double)thebloat / 256 * 100));
}

View file

@ -38,32 +38,20 @@ static const char *inpath;
static const char *outpath;
static unsigned char *inmap;
nullterminated() static void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
static wontreturn void Die(const char *path, const char *reason) {
Print(2, path, ": ", reason, "\n", NULL);
tinyprint(2, path, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void SysExit(const char *path, const char *func) {
static wontreturn void SysDie(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
tinyprint(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\
tinyprint(fd, "\
NAME\n\
\n\
Cosmopolitan Zip Copier\n\
@ -71,7 +59,7 @@ NAME\n\
SYNOPSIS\n\
\n\
",
program_invocation_name, " [FLAGS] SRC DST\n\
program_invocation_name, " [FLAGS] SRC DST\n\
\n\
DESCRIPTION\n\
\n\
@ -96,7 +84,7 @@ EXAMPLE\n\
\n\
\n\
",
NULL);
NULL);
exit(exitcode);
}
@ -173,10 +161,10 @@ static void CopyZip(void) {
// write output
if ((outfd = open(outpath, O_WRONLY | O_CREAT, 0644)) == -1) {
SysExit(outpath, "open");
SysDie(outpath, "open");
}
if ((outsize = lseek(outfd, 0, SEEK_END)) == -1) {
SysExit(outpath, "lseek");
SysDie(outpath, "lseek");
}
ldest = outsize;
cdest = outsize + ltotal;
@ -186,23 +174,23 @@ static void CopyZip(void) {
// write local file
length = ZIP_LFILE_SIZE(lfile);
if (pwrite(outfd, lfile, length, ldest) != length) {
SysExit(outpath, "lfile pwrite");
SysDie(outpath, "lfile pwrite");
}
ldest += length;
// write directory entry
length = ZIP_CFILE_HDRSIZE(cfile);
if (pwrite(outfd, cfile, length, cdest) != length) {
SysExit(outpath, "lfile pwrite");
SysDie(outpath, "lfile pwrite");
}
cdest += length;
}
WRITE32LE(eocd + kZipCdirOffsetOffset, outsize + ltotal);
length = ZIP_CDIR_HDRSIZE(eocd);
if (pwrite(outfd, eocd, length, cdest) != length) {
SysExit(outpath, "eocd pwrite");
SysDie(outpath, "eocd pwrite");
}
if (close(outfd)) {
SysExit(outpath, "close");
SysDie(outpath, "close");
}
}
@ -213,23 +201,23 @@ int main(int argc, char *argv[]) {
}
GetOpts(argc, argv);
if ((infd = open(inpath, O_RDONLY)) == -1) {
SysExit(inpath, "open");
SysDie(inpath, "open");
}
if ((insize = lseek(infd, 0, SEEK_END)) == -1) {
SysExit(inpath, "lseek");
SysDie(inpath, "lseek");
}
if (!insize) {
Die(inpath, "file is empty");
}
if ((inmap = mmap(0, insize, PROT_READ | PROT_WRITE, MAP_PRIVATE, infd, 0)) ==
MAP_FAILED) {
SysExit(inpath, "mmap");
SysDie(inpath, "mmap");
}
CopyZip();
if (munmap(inmap, insize)) {
SysExit(inpath, "munmap");
SysDie(inpath, "munmap");
}
if (close(infd)) {
SysExit(inpath, "close");
SysDie(inpath, "close");
}
}

View file

@ -21,7 +21,6 @@
#include "libc/elf/def.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/libgen.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
@ -52,15 +51,16 @@ int strip_components_;
const char *path_prefix_;
struct timespec timestamp;
wontreturn void PrintUsage(int rc) {
kprintf("\n\
wontreturn void PrintUsage(int fd, int rc) {
tinyprint(fd, "\n\
NAME\n\
\n\
Cosmpolitan Zip File Compiler\n\
\n\
SYNOPSIS\n\
\n\
%s [FLAGS] FILE...\n\
",
program_invocation_name, " [FLAGS] FILE...\n\
\n\
DESCRIPTION\n\
\n\
@ -80,7 +80,7 @@ FLAGS\n\
-y SYMBOL generate yoink for symbol (default __zip_eocd)\n\
\n\
",
program_invocation_name);
NULL);
exit(rc);
}
@ -117,17 +117,18 @@ void GetOpts(int *argc, char ***argv) {
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS);
PrintUsage(1, EXIT_SUCCESS);
default:
PrintUsage(EX_USAGE);
PrintUsage(2, EX_USAGE);
}
}
*argc -= optind;
*argv += optind;
if (!outpath_) {
kprintf("error: no output path specified\n"
"run %s -h for usage\n",
program_invocation_name);
tinyprint(2,
"error: no output path specified\n"
"run ",
program_invocation_name, " -h for usage\n", NULL);
exit(1);
}
}