mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Make more fixes and improvements
This commit is contained in:
parent
01b25e267b
commit
1599b818d9
24 changed files with 858 additions and 538 deletions
2
Makefile
2
Makefile
|
@ -281,7 +281,7 @@ COSMOPOLITAN_OBJECTS = \
|
||||||
LIBC_RAND \
|
LIBC_RAND \
|
||||||
LIBC_SYSV_CALLS \
|
LIBC_SYSV_CALLS \
|
||||||
LIBC_NT_PSAPI \
|
LIBC_NT_PSAPI \
|
||||||
LIBC_NT_POWERPROF \
|
LIBC_NT_POWRPROF \
|
||||||
LIBC_NT_PDH \
|
LIBC_NT_PDH \
|
||||||
LIBC_NT_SHELL32 \
|
LIBC_NT_SHELL32 \
|
||||||
LIBC_NT_GDI32 \
|
LIBC_NT_GDI32 \
|
||||||
|
|
|
@ -46,7 +46,7 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
||||||
LIBC_NT_NTDLL \
|
LIBC_NT_NTDLL \
|
||||||
LIBC_NT_PDH \
|
LIBC_NT_PDH \
|
||||||
LIBC_NT_PSAPI \
|
LIBC_NT_PSAPI \
|
||||||
LIBC_NT_POWERPROF \
|
LIBC_NT_POWRPROF \
|
||||||
LIBC_NT_WS2_32 \
|
LIBC_NT_WS2_32 \
|
||||||
LIBC_STR \
|
LIBC_STR \
|
||||||
LIBC_STUBS \
|
LIBC_STUBS \
|
||||||
|
|
397
libc/fmt/fmt.c
397
libc/fmt/fmt.c
|
@ -21,7 +21,7 @@
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmt.internal.h"
|
||||||
#include "libc/fmt/internal.h"
|
#include "libc/fmt/internal.h"
|
||||||
#include "libc/fmt/itoa.h"
|
#include "libc/fmt/itoa.h"
|
||||||
#include "libc/intrin/nomultics.internal.h"
|
#include "libc/intrin/nomultics.internal.h"
|
||||||
|
@ -33,25 +33,6 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "third_party/gdtoa/gdtoa.h"
|
#include "third_party/gdtoa/gdtoa.h"
|
||||||
|
|
||||||
#define PUT(C) \
|
|
||||||
do { \
|
|
||||||
char Buf[1] = {C}; \
|
|
||||||
if (out(Buf, arg, 1) == -1) { \
|
|
||||||
return -1; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
|
||||||
|
|
||||||
static void __fmt_free_dtoa(char **mem) {
|
|
||||||
if (*mem) {
|
|
||||||
if (weaken(freedtoa)) {
|
|
||||||
weaken(freedtoa)(*mem);
|
|
||||||
}
|
|
||||||
*mem = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __fmt_atoi(const char **str) {
|
static int __fmt_atoi(const char **str) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
|
for (i = 0; '0' <= **str && **str <= '9'; ++*str) {
|
||||||
|
@ -129,11 +110,6 @@ static int __fmt_atoi(const char **str) {
|
||||||
* @vforksafe if floating point isn't used
|
* @vforksafe if floating point isn't used
|
||||||
*/
|
*/
|
||||||
hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
union {
|
|
||||||
double d;
|
|
||||||
uint32_t u[2];
|
|
||||||
uint64_t q;
|
|
||||||
} pun;
|
|
||||||
long ld;
|
long ld;
|
||||||
void *p;
|
void *p;
|
||||||
unsigned u;
|
unsigned u;
|
||||||
|
@ -145,13 +121,12 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
const char *alphabet;
|
const char *alphabet;
|
||||||
int (*out)(const char *, void *, size_t);
|
int (*out)(const char *, void *, size_t);
|
||||||
unsigned char signbit, log2base;
|
unsigned char signbit, log2base;
|
||||||
int c, d, k, w, n, i1, ui, bw, bex;
|
char *s, *q, qchar;
|
||||||
char *s, *q, *se, *mem, qchar, special[8];
|
int d, w, n;
|
||||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
int sign, prec, flags, width, lasterr;
|
||||||
|
|
||||||
lasterr = errno;
|
lasterr = errno;
|
||||||
out = fn ? fn : (void *)missingno;
|
out = fn ? fn : (void *)missingno;
|
||||||
mem = 0;
|
|
||||||
|
|
||||||
while (*format) {
|
while (*format) {
|
||||||
if (*format != '%') {
|
if (*format != '%') {
|
||||||
|
@ -361,7 +336,6 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
prec = 1;
|
prec = 1;
|
||||||
flags |= FLAGS_PRECISION;
|
flags |= FLAGS_PRECISION;
|
||||||
|
@ -369,12 +343,10 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
p = charbuf;
|
p = charbuf;
|
||||||
charbuf[0] = va_arg(va, int);
|
charbuf[0] = va_arg(va, int);
|
||||||
goto FormatString;
|
goto FormatString;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
p = weaken(strerror) ? weaken(strerror)(lasterr) : "?";
|
p = weaken(strerror) ? weaken(strerror)(lasterr) : "?";
|
||||||
signbit = 0;
|
signbit = 0;
|
||||||
goto FormatString;
|
goto FormatString;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
// undocumented %r specifier
|
// undocumented %r specifier
|
||||||
// used for good carriage return
|
// used for good carriage return
|
||||||
|
@ -385,11 +357,9 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
p = "\r\e[K";
|
p = "\r\e[K";
|
||||||
goto FormatString;
|
goto FormatString;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'q':
|
case 'q':
|
||||||
flags |= FLAGS_QUOTE;
|
flags |= FLAGS_QUOTE;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
p = va_arg(va, void *);
|
p = va_arg(va, void *);
|
||||||
FormatString:
|
FormatString:
|
||||||
|
@ -397,369 +367,40 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
// nonstandard %n specifier
|
// nonstandard %n specifier
|
||||||
// used to print newlines that work in raw terminal modes
|
// used to print newlines that work in raw terminal modes
|
||||||
if (__nomultics) PUT('\r');
|
if (__nomultics) __FMT_PUT('\r');
|
||||||
PUT('\n');
|
__FMT_PUT('\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
case 'f':
|
case 'f':
|
||||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
case 'G':
|
||||||
if (longdouble) {
|
case 'g':
|
||||||
pun.d = va_arg(va, long double);
|
case 'e':
|
||||||
} else {
|
case 'E':
|
||||||
pun.d = va_arg(va, double);
|
case 'a':
|
||||||
}
|
case 'A':
|
||||||
FormatDtoa:
|
|
||||||
if (!weaken(__fmt_dtoa)) {
|
if (!weaken(__fmt_dtoa)) {
|
||||||
p = "?";
|
p = "?";
|
||||||
goto FormatThatThing;
|
prec = 0;
|
||||||
}
|
|
||||||
assert(!mem);
|
|
||||||
s = mem = weaken(__fmt_dtoa)(pun.d, 3, prec, &decpt, &sgn, &se);
|
|
||||||
if (decpt == 9999) {
|
|
||||||
Format9999:
|
|
||||||
bzero(special, sizeof(special));
|
|
||||||
p = q = special;
|
|
||||||
if (sgn) {
|
|
||||||
*q++ = '-';
|
|
||||||
} else if (flags & FLAGS_PLUS) {
|
|
||||||
*q++ = '+';
|
|
||||||
} else if (flags & FLAGS_SPACE) {
|
|
||||||
*q++ = ' ';
|
|
||||||
}
|
|
||||||
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
|
|
||||||
FormatThatThing:
|
|
||||||
__fmt_free_dtoa(&mem);
|
|
||||||
mem = 0;
|
|
||||||
prec = alt = 0;
|
|
||||||
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
||||||
goto FormatString;
|
goto FormatString;
|
||||||
}
|
}
|
||||||
FormatReal:
|
if (weaken(__fmt_dtoa)(out, arg, d, flags, prec, sign, width,
|
||||||
if (sgn) sign = '-';
|
longdouble, qchar, signbit, alphabet,
|
||||||
if (prec > 0) width -= prec;
|
va) == -1) {
|
||||||
if (width > 0) {
|
return -1;
|
||||||
if (sign) --width;
|
|
||||||
if (decpt <= 0) {
|
|
||||||
--width;
|
|
||||||
if (prec > 0) --width;
|
|
||||||
} else {
|
|
||||||
if (s == se) decpt = 1;
|
|
||||||
width -= decpt;
|
|
||||||
if (prec > 0 || alt) --width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
|
||||||
if (flags & FLAGS_ZEROPAD) {
|
|
||||||
if (sign) PUT(sign);
|
|
||||||
sign = 0;
|
|
||||||
do PUT('0');
|
|
||||||
while (--width > 0);
|
|
||||||
} else {
|
|
||||||
do PUT(' ');
|
|
||||||
while (--width > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sign) PUT(sign);
|
|
||||||
if (decpt <= 0) {
|
|
||||||
PUT('0');
|
|
||||||
if (prec > 0 || alt) PUT('.');
|
|
||||||
while (decpt < 0) {
|
|
||||||
PUT('0');
|
|
||||||
prec--;
|
|
||||||
decpt++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
if ((c = *s)) {
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
c = '0';
|
|
||||||
}
|
|
||||||
PUT(c);
|
|
||||||
} while (--decpt > 0);
|
|
||||||
if (prec > 0 || alt) PUT('.');
|
|
||||||
}
|
|
||||||
while (--prec >= 0) {
|
|
||||||
if ((c = *s)) {
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
c = '0';
|
|
||||||
}
|
|
||||||
PUT(c);
|
|
||||||
}
|
|
||||||
while (--width >= 0) {
|
|
||||||
PUT(' ');
|
|
||||||
}
|
|
||||||
__fmt_free_dtoa(&mem);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'G':
|
|
||||||
case 'g':
|
|
||||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
|
||||||
if (longdouble) {
|
|
||||||
pun.d = va_arg(va, long double);
|
|
||||||
} else {
|
|
||||||
pun.d = va_arg(va, double);
|
|
||||||
}
|
|
||||||
if (prec < 0) prec = 0;
|
|
||||||
if (!weaken(__fmt_dtoa)) {
|
|
||||||
p = "?";
|
|
||||||
goto FormatThatThing;
|
|
||||||
}
|
|
||||||
assert(!mem);
|
|
||||||
s = mem =
|
|
||||||
weaken(__fmt_dtoa)(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
|
|
||||||
if (decpt == 9999) goto Format9999;
|
|
||||||
c = se - s;
|
|
||||||
prec1 = prec;
|
|
||||||
if (!prec) {
|
|
||||||
prec = c;
|
|
||||||
prec1 = c + (s[1] || alt ? 5 : 4);
|
|
||||||
}
|
|
||||||
if (decpt > -4 && decpt <= prec1) {
|
|
||||||
if (alt) {
|
|
||||||
prec -= decpt;
|
|
||||||
} else {
|
|
||||||
prec = c - decpt;
|
|
||||||
}
|
|
||||||
if (prec < 0) prec = 0;
|
|
||||||
goto FormatReal;
|
|
||||||
}
|
|
||||||
d -= 2;
|
|
||||||
if (!alt && prec > c) prec = c;
|
|
||||||
--prec;
|
|
||||||
goto FormatExpo;
|
|
||||||
|
|
||||||
case 'e':
|
|
||||||
case 'E':
|
|
||||||
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
|
||||||
if (longdouble) {
|
|
||||||
pun.d = va_arg(va, long double);
|
|
||||||
} else {
|
|
||||||
pun.d = va_arg(va, double);
|
|
||||||
}
|
|
||||||
if (prec < 0) prec = 0;
|
|
||||||
if (!weaken(__fmt_dtoa)) {
|
|
||||||
p = "?";
|
|
||||||
goto FormatThatThing;
|
|
||||||
}
|
|
||||||
assert(!mem);
|
|
||||||
s = mem = weaken(__fmt_dtoa)(pun.d, 2, prec + 1, &decpt, &sgn, &se);
|
|
||||||
if (decpt == 9999) goto Format9999;
|
|
||||||
FormatExpo:
|
|
||||||
if (sgn) sign = '-';
|
|
||||||
if ((width -= prec + 5) > 0) {
|
|
||||||
if (sign) --width;
|
|
||||||
if (prec || alt) --width;
|
|
||||||
}
|
|
||||||
if ((c = --decpt) < 0) c = -c;
|
|
||||||
while (c >= 100) {
|
|
||||||
--width;
|
|
||||||
c /= 10;
|
|
||||||
}
|
|
||||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
|
||||||
if (flags & FLAGS_ZEROPAD) {
|
|
||||||
if (sign) PUT(sign);
|
|
||||||
sign = 0;
|
|
||||||
do PUT('0');
|
|
||||||
while (--width > 0);
|
|
||||||
} else {
|
|
||||||
do PUT(' ');
|
|
||||||
while (--width > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sign) PUT(sign);
|
|
||||||
PUT(*s++);
|
|
||||||
if (prec || alt) PUT('.');
|
|
||||||
while (--prec >= 0) {
|
|
||||||
if ((c = *s)) {
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
c = '0';
|
|
||||||
}
|
|
||||||
PUT(c);
|
|
||||||
}
|
|
||||||
__fmt_free_dtoa(&mem);
|
|
||||||
PUT(d);
|
|
||||||
if (decpt < 0) {
|
|
||||||
PUT('-');
|
|
||||||
decpt = -decpt;
|
|
||||||
} else {
|
|
||||||
PUT('+');
|
|
||||||
}
|
|
||||||
for (c = 2, k = 10; 10 * k <= decpt; c++) k *= 10;
|
|
||||||
for (;;) {
|
|
||||||
i1 = decpt / k;
|
|
||||||
PUT(i1 + '0');
|
|
||||||
if (--c <= 0) break;
|
|
||||||
decpt -= i1 * k;
|
|
||||||
decpt *= 10;
|
|
||||||
}
|
|
||||||
while (--width >= 0) {
|
|
||||||
PUT(' ');
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
alphabet = "0123456789abcdefpx";
|
|
||||||
goto FormatBinary;
|
|
||||||
case 'A':
|
|
||||||
alphabet = "0123456789ABCDEFPX";
|
|
||||||
FormatBinary:
|
|
||||||
if (longdouble) {
|
|
||||||
pun.d = va_arg(va, long double);
|
|
||||||
} else {
|
|
||||||
pun.d = va_arg(va, double);
|
|
||||||
}
|
|
||||||
if ((pun.u[1] & 0x7ff00000) == 0x7ff00000) {
|
|
||||||
goto FormatDtoa;
|
|
||||||
}
|
|
||||||
if (pun.u[1] & 0x80000000) {
|
|
||||||
sign = '-';
|
|
||||||
pun.u[1] &= 0x7fffffff;
|
|
||||||
}
|
|
||||||
if (pun.d) {
|
|
||||||
c = '1';
|
|
||||||
bex = (pun.u[1] >> 20) - 1023;
|
|
||||||
pun.u[1] &= 0xfffff;
|
|
||||||
if (bex == -1023) {
|
|
||||||
++bex;
|
|
||||||
if (pun.u[1]) {
|
|
||||||
do {
|
|
||||||
--bex;
|
|
||||||
pun.u[1] <<= 1;
|
|
||||||
if (pun.u[0] & 0x80000000) pun.u[1] |= 1;
|
|
||||||
pun.u[0] <<= 1;
|
|
||||||
} while (pun.u[1] < 0x100000);
|
|
||||||
} else {
|
|
||||||
while (!(pun.u[0] & 0x80000000)) {
|
|
||||||
--bex;
|
|
||||||
pun.u[0] <<= 1;
|
|
||||||
}
|
|
||||||
bex -= 21;
|
|
||||||
pun.u[1] = pun.u[0] >> 11;
|
|
||||||
pun.u[0] <<= 21;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c = '0';
|
|
||||||
bex = 0;
|
|
||||||
}
|
|
||||||
if (flags & FLAGS_PRECISION) {
|
|
||||||
if (prec > 13) prec = 13;
|
|
||||||
if (pun.d && prec < 13) {
|
|
||||||
pun.u[1] |= 0x100000;
|
|
||||||
if (prec < 5) {
|
|
||||||
ui = 1u << ((5 - prec) * 4 - 1);
|
|
||||||
if (pun.u[1] & ui) {
|
|
||||||
if (pun.u[1] & ((ui - 1) | (ui << 1)) || pun.u[0]) {
|
|
||||||
pun.u[1] += ui;
|
|
||||||
BexCheck:
|
|
||||||
if (pun.u[1] & 0x200000) {
|
|
||||||
++bex;
|
|
||||||
pun.u[1] >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (prec == 5) {
|
|
||||||
if (pun.u[0] & 0x80000000) {
|
|
||||||
BumpIt:
|
|
||||||
++pun.u[1];
|
|
||||||
goto BexCheck;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i1 = (13 - prec) * 4;
|
|
||||||
ui = 1u << (i1 - 1);
|
|
||||||
if (pun.u[0] & ui && pun.u[0] & ((ui - 1) | (ui << 1))) {
|
|
||||||
pun.u[0] += ui;
|
|
||||||
if (!(pun.u[0] >> i1)) goto BumpIt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((ui = pun.u[0])) {
|
|
||||||
ui = __builtin_ctz(ui);
|
|
||||||
prec = 6 + ((32 - ROUNDDOWN(ui, 4)) >> 2) - 1;
|
|
||||||
} else if ((ui = pun.u[1] & 0xfffff)) {
|
|
||||||
ui = __builtin_ctz(ui);
|
|
||||||
prec = (20 - ROUNDDOWN(ui, 4)) >> 2;
|
|
||||||
} else {
|
|
||||||
prec = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bw = 1;
|
|
||||||
if (bex) {
|
|
||||||
if ((i1 = bex) < 0) i1 = -i1;
|
|
||||||
while (i1 >= 10) {
|
|
||||||
++bw;
|
|
||||||
i1 /= 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pun.u[1] & 0x80000000) {
|
|
||||||
pun.u[1] &= 0x7fffffff;
|
|
||||||
if (pun.d || sign) sign = '-';
|
|
||||||
}
|
|
||||||
if ((width -= bw + 5) > 0) {
|
|
||||||
if (sign) --width;
|
|
||||||
if (prec || alt) --width;
|
|
||||||
}
|
|
||||||
if (pun.q && prec > 0) {
|
|
||||||
width -= ROUNDUP(bsrl(pun.q) + 1, 4) >> 2;
|
|
||||||
}
|
|
||||||
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
|
||||||
if (flags & FLAGS_ZEROPAD) {
|
|
||||||
if (sign) {
|
|
||||||
PUT(sign);
|
|
||||||
sign = 0;
|
|
||||||
}
|
|
||||||
do PUT('0');
|
|
||||||
while (--width > 0);
|
|
||||||
} else {
|
|
||||||
do PUT(' ');
|
|
||||||
while (--width > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sign) PUT(sign);
|
|
||||||
PUT('0');
|
|
||||||
PUT(alphabet[17]);
|
|
||||||
PUT(c);
|
|
||||||
if (prec > 0 || alt) PUT('.');
|
|
||||||
while (prec-- > 0) {
|
|
||||||
PUT(alphabet[(pun.q >> 48) & 0xf]);
|
|
||||||
pun.q <<= 4;
|
|
||||||
}
|
|
||||||
PUT(alphabet[16]);
|
|
||||||
if (bex < 0) {
|
|
||||||
PUT('-');
|
|
||||||
bex = -bex;
|
|
||||||
} else {
|
|
||||||
PUT('+');
|
|
||||||
}
|
|
||||||
for (c = 1; 10 * c <= bex;) c *= 10;
|
|
||||||
for (;;) {
|
|
||||||
i1 = bex / c;
|
|
||||||
PUT('0' + i1);
|
|
||||||
if (!--bw) break;
|
|
||||||
bex -= i1 * c;
|
|
||||||
bex *= 10;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '%':
|
case '%':
|
||||||
PUT('%');
|
__FMT_PUT('%');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PUT(format[-1]);
|
__FMT_PUT(format[-1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!mem);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_FMT_FMTS_H_
|
#ifndef COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_LIBC_FMT_FMTS_H_
|
#define COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_
|
||||||
|
|
||||||
#define PRINTF_NTOA_BUFFER_SIZE 144
|
#define PRINTF_NTOA_BUFFER_SIZE 144
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
COSMOPOLITAN_C_START_
|
COSMOPOLITAN_C_START_
|
||||||
|
|
||||||
|
#define __FMT_PUT(C) \
|
||||||
|
do { \
|
||||||
|
char Buf[1] = {C}; \
|
||||||
|
if (out(Buf, arg, 1) == -1) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||||
unsigned long) hidden;
|
unsigned long) hidden;
|
||||||
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||||
|
@ -14,8 +22,9 @@ int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||||
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
||||||
unsigned char, unsigned long, unsigned long, unsigned long,
|
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||||
unsigned char, const char *) hidden;
|
unsigned char, const char *) hidden;
|
||||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
int __fmt_dtoa(int (*)(const char *, void *, size_t), void *, int, int, int,
|
||||||
|
int, int, bool, char, unsigned char, const char *, va_list);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
#endif /* COSMOPOLITAN_LIBC_FMT_FMTS_H_ */
|
#endif /* COSMOPOLITAN_LIBC_FMT_FMT_INTERNAL_H_ */
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/fmt/conv.h"
|
#include "libc/fmt/conv.h"
|
||||||
#include "libc/fmt/divmod10.internal.h"
|
#include "libc/fmt/divmod10.internal.h"
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmt.internal.h"
|
||||||
#include "libc/fmt/internal.h"
|
#include "libc/fmt/internal.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmt.internal.h"
|
||||||
|
|
||||||
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||||
unsigned long n) {
|
unsigned long n) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
#ifndef COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||||
#define COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
#define COSMOPOLITAN_LIBC_FMT_PFLINK_H_
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/fmt/fmts.h"
|
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -23,7 +22,6 @@
|
||||||
({ \
|
({ \
|
||||||
if (___PFLINK(FMT, strpbrk, "faAeg")) STATIC_YOINK("__fmt_dtoa"); \
|
if (___PFLINK(FMT, strpbrk, "faAeg")) STATIC_YOINK("__fmt_dtoa"); \
|
||||||
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
if (___PFLINK(FMT, strpbrk, "cmrqs")) { \
|
||||||
if (___PFLINK(FMT, strchr, '#')) STATIC_YOINK("kCp437"); \
|
|
||||||
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
if (___PFLINK(FMT, strstr, "%m")) STATIC_YOINK("strerror"); \
|
||||||
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
if (!IsTiny() && (___PFLINK(FMT, strstr, "%*") || \
|
||||||
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
___PFLINK(FMT, strpbrk, "0123456789"))) { \
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/bits/bits.h"
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/safemacros.internal.h"
|
#include "libc/bits/safemacros.internal.h"
|
||||||
#include "libc/bits/weaken.h"
|
#include "libc/bits/weaken.h"
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/fmt/fmt.internal.h"
|
||||||
#include "libc/fmt/internal.h"
|
#include "libc/fmt/internal.h"
|
||||||
#include "libc/nexgen32e/bsr.h"
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
@ -46,7 +46,7 @@ static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
||||||
|
|
||||||
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||||
char buf[8];
|
char buf[8];
|
||||||
w = tpenc((*weaken(kCp437))[w & 0xFF]);
|
w = tpenc(kCp437[w & 0xFF]);
|
||||||
WRITE64LE(buf, w);
|
WRITE64LE(buf, w);
|
||||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.include "o/libc/nt/codegen.inc"
|
.include "o/libc/nt/codegen.inc"
|
||||||
.imp PowerProf,__imp_SetSuspendState,SetSuspendState,0
|
.imp PowrProf,__imp_SetSuspendState,SetSuspendState,0
|
||||||
|
|
||||||
.text.windows
|
.text.windows
|
||||||
SetSuspendState:
|
SetSuspendState:
|
|
@ -4052,10 +4052,10 @@ imp 'SetTcpEntry' SetTcpEntry iphlpapi 0
|
||||||
imp 'UnenableRouter' UnenableRouter iphlpapi 0
|
imp 'UnenableRouter' UnenableRouter iphlpapi 0
|
||||||
imp 'UnregisterInterfaceTimestampConfigChange' UnregisterInterfaceTimestampConfigChange iphlpapi 0
|
imp 'UnregisterInterfaceTimestampConfigChange' UnregisterInterfaceTimestampConfigChange iphlpapi 0
|
||||||
|
|
||||||
# POWERPROF.DLL
|
# POWRPROF.DLL
|
||||||
#
|
#
|
||||||
# Name Actual DLL Hint Arity
|
# Name Actual DLL Hint Arity
|
||||||
imp 'SetSuspendState' SetSuspendState PowerProf 0 3
|
imp 'SetSuspendState' SetSuspendState PowrProf 0 3
|
||||||
|
|
||||||
# PDH.DLL
|
# PDH.DLL
|
||||||
#
|
#
|
||||||
|
|
|
@ -311,22 +311,22 @@ $(LIBC_NT_IPHLPAPI_A).pkg: \
|
||||||
|
|
||||||
#───────────────────────────────────────────────────────────────────────────────
|
#───────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
LIBC_NT_ARTIFACTS += LIBC_NT_POWERPROF_A
|
LIBC_NT_ARTIFACTS += LIBC_NT_POWRPROF_A
|
||||||
LIBC_NT_POWERPROF = $(LIBC_NT_POWERPROF_A_DEPS) $(LIBC_NT_POWERPROF_A)
|
LIBC_NT_POWRPROF = $(LIBC_NT_POWRPROF_A_DEPS) $(LIBC_NT_POWRPROF_A)
|
||||||
LIBC_NT_POWERPROF_A = o/$(MODE)/libc/nt/powerprof.a
|
LIBC_NT_POWRPROF_A = o/$(MODE)/libc/nt/powrprof.a
|
||||||
LIBC_NT_POWERPROF_A_SRCS := $(wildcard libc/nt/PowerProf/*.s)
|
LIBC_NT_POWRPROF_A_SRCS := $(wildcard libc/nt/PowrProf/*.s)
|
||||||
LIBC_NT_POWERPROF_A_OBJS = $(LIBC_NT_POWERPROF_A_SRCS:%.s=o/$(MODE)/%.o)
|
LIBC_NT_POWRPROF_A_OBJS = $(LIBC_NT_POWRPROF_A_SRCS:%.s=o/$(MODE)/%.o)
|
||||||
LIBC_NT_POWERPROF_A_CHECKS = $(LIBC_NT_POWERPROF_A).pkg
|
LIBC_NT_POWRPROF_A_CHECKS = $(LIBC_NT_POWRPROF_A).pkg
|
||||||
LIBC_NT_POWERPROF_A_DIRECTDEPS = LIBC_NT_KERNEL32
|
LIBC_NT_POWRPROF_A_DIRECTDEPS = LIBC_NT_KERNEL32
|
||||||
LIBC_NT_POWERPROF_A_DEPS := \
|
LIBC_NT_POWRPROF_A_DEPS := \
|
||||||
$(call uniq,$(foreach x,$(LIBC_NT_POWERPROF_A_DIRECTDEPS),$($(x))))
|
$(call uniq,$(foreach x,$(LIBC_NT_POWRPROF_A_DIRECTDEPS),$($(x))))
|
||||||
$(LIBC_NT_POWERPROF_A): \
|
$(LIBC_NT_POWRPROF_A): \
|
||||||
libc/nt/PowerProf/ \
|
libc/nt/PowrProf/ \
|
||||||
$(LIBC_NT_POWERPROF_A).pkg \
|
$(LIBC_NT_POWRPROF_A).pkg \
|
||||||
$(LIBC_NT_POWERPROF_A_OBJS)
|
$(LIBC_NT_POWRPROF_A_OBJS)
|
||||||
$(LIBC_NT_POWERPROF_A).pkg: \
|
$(LIBC_NT_POWRPROF_A).pkg: \
|
||||||
$(LIBC_NT_POWERPROF_A_OBJS) \
|
$(LIBC_NT_POWRPROF_A_OBJS) \
|
||||||
$(foreach x,$(LIBC_NT_POWERPROF_A_DIRECTDEPS),$($(x)_A).pkg)
|
$(foreach x,$(LIBC_NT_POWRPROF_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||||
|
|
||||||
#───────────────────────────────────────────────────────────────────────────────
|
#───────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
/*-*- 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│
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||||
│ │
|
│ │
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
│ any purpose with or without fee is hereby granted, provided that the │
|
||||||
|
@ -16,10 +16,379 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/fmt/fmts.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/fmt/fmt.h"
|
||||||
|
#include "libc/fmt/fmt.internal.h"
|
||||||
|
#include "libc/fmt/internal.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/nexgen32e/bsr.h"
|
||||||
#include "third_party/gdtoa/gdtoa.h"
|
#include "third_party/gdtoa/gdtoa.h"
|
||||||
|
|
||||||
char *__fmt_dtoa(double d0, int mode, int ndigits, int *decpt, int *sign,
|
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||||
char **rve) {
|
|
||||||
return dtoa(d0, mode, ndigits, decpt, sign, rve);
|
static void __fmt_free_dtoa(char **mem) {
|
||||||
|
if (*mem) {
|
||||||
|
freedtoa(*mem);
|
||||||
|
*mem = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
|
||||||
|
int flags, int prec, int sign, int width, bool longdouble,
|
||||||
|
char qchar, unsigned char signbit, const char *alphabet,
|
||||||
|
va_list va) {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint32_t u[2];
|
||||||
|
uint64_t q;
|
||||||
|
} pun;
|
||||||
|
int c, k, i1, ui, bw, bex, sgn, prec1, decpt;
|
||||||
|
char *s, *p, *q, *se, *mem, special[8];
|
||||||
|
mem = 0;
|
||||||
|
switch (d) {
|
||||||
|
case 'F':
|
||||||
|
case 'f':
|
||||||
|
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||||
|
if (longdouble) {
|
||||||
|
pun.d = va_arg(va, long double);
|
||||||
|
} else {
|
||||||
|
pun.d = va_arg(va, double);
|
||||||
|
}
|
||||||
|
FormatDtoa:
|
||||||
|
assert(!mem);
|
||||||
|
s = mem = dtoa(pun.d, 3, prec, &decpt, &sgn, &se);
|
||||||
|
if (decpt == 9999) {
|
||||||
|
Format9999:
|
||||||
|
bzero(special, sizeof(special));
|
||||||
|
p = q = special;
|
||||||
|
if (sgn) {
|
||||||
|
*q++ = '-';
|
||||||
|
} else if (flags & FLAGS_PLUS) {
|
||||||
|
*q++ = '+';
|
||||||
|
} else if (flags & FLAGS_SPACE) {
|
||||||
|
*q++ = ' ';
|
||||||
|
}
|
||||||
|
memcpy(q, kSpecialFloats[*s == 'N'][d >= 'a'], 4);
|
||||||
|
FormatThatThing:
|
||||||
|
__fmt_free_dtoa(&mem);
|
||||||
|
mem = 0;
|
||||||
|
prec = 0;
|
||||||
|
flags &= ~(FLAGS_PRECISION | FLAGS_PLUS | FLAGS_SPACE);
|
||||||
|
goto FormatString;
|
||||||
|
}
|
||||||
|
FormatReal:
|
||||||
|
if (sgn) sign = '-';
|
||||||
|
if (prec > 0) width -= prec;
|
||||||
|
if (width > 0) {
|
||||||
|
if (sign) --width;
|
||||||
|
if (decpt <= 0) {
|
||||||
|
--width;
|
||||||
|
if (prec > 0) --width;
|
||||||
|
} else {
|
||||||
|
if (s == se) decpt = 1;
|
||||||
|
width -= decpt;
|
||||||
|
if (prec > 0) --width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||||
|
if (flags & FLAGS_ZEROPAD) {
|
||||||
|
if (sign) __FMT_PUT(sign);
|
||||||
|
sign = 0;
|
||||||
|
do
|
||||||
|
__FMT_PUT('0');
|
||||||
|
while (--width > 0);
|
||||||
|
} else {
|
||||||
|
do
|
||||||
|
__FMT_PUT(' ');
|
||||||
|
while (--width > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sign) __FMT_PUT(sign);
|
||||||
|
if (decpt <= 0) {
|
||||||
|
__FMT_PUT('0');
|
||||||
|
if (prec > 0) __FMT_PUT('.');
|
||||||
|
while (decpt < 0) {
|
||||||
|
__FMT_PUT('0');
|
||||||
|
prec--;
|
||||||
|
decpt++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
if ((c = *s)) {
|
||||||
|
s++;
|
||||||
|
} else {
|
||||||
|
c = '0';
|
||||||
|
}
|
||||||
|
__FMT_PUT(c);
|
||||||
|
} while (--decpt > 0);
|
||||||
|
if (prec > 0) __FMT_PUT('.');
|
||||||
|
}
|
||||||
|
while (--prec >= 0) {
|
||||||
|
if ((c = *s)) {
|
||||||
|
s++;
|
||||||
|
} else {
|
||||||
|
c = '0';
|
||||||
|
}
|
||||||
|
__FMT_PUT(c);
|
||||||
|
}
|
||||||
|
while (--width >= 0) {
|
||||||
|
__FMT_PUT(' ');
|
||||||
|
}
|
||||||
|
__fmt_free_dtoa(&mem);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'G':
|
||||||
|
case 'g':
|
||||||
|
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||||
|
if (longdouble) {
|
||||||
|
pun.d = va_arg(va, long double);
|
||||||
|
} else {
|
||||||
|
pun.d = va_arg(va, double);
|
||||||
|
}
|
||||||
|
if (prec < 0) prec = 0;
|
||||||
|
assert(!mem);
|
||||||
|
s = mem = dtoa(pun.d, prec ? 2 : 0, prec, &decpt, &sgn, &se);
|
||||||
|
if (decpt == 9999) goto Format9999;
|
||||||
|
c = se - s;
|
||||||
|
prec1 = prec;
|
||||||
|
if (!prec) {
|
||||||
|
prec = c;
|
||||||
|
prec1 = c + (s[1] ? 5 : 4);
|
||||||
|
}
|
||||||
|
if (decpt > -4 && decpt <= prec1) {
|
||||||
|
prec = c - decpt;
|
||||||
|
if (prec < 0) prec = 0;
|
||||||
|
goto FormatReal;
|
||||||
|
}
|
||||||
|
d -= 2;
|
||||||
|
if (prec > c) prec = c;
|
||||||
|
--prec;
|
||||||
|
goto FormatExpo;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
if (!(flags & FLAGS_PRECISION)) prec = 6;
|
||||||
|
if (longdouble) {
|
||||||
|
pun.d = va_arg(va, long double);
|
||||||
|
} else {
|
||||||
|
pun.d = va_arg(va, double);
|
||||||
|
}
|
||||||
|
if (prec < 0) prec = 0;
|
||||||
|
if (!dtoa) {
|
||||||
|
p = "?";
|
||||||
|
goto FormatThatThing;
|
||||||
|
}
|
||||||
|
assert(!mem);
|
||||||
|
s = mem = dtoa(pun.d, 2, prec + 1, &decpt, &sgn, &se);
|
||||||
|
if (decpt == 9999) goto Format9999;
|
||||||
|
FormatExpo:
|
||||||
|
if (sgn) sign = '-';
|
||||||
|
if ((width -= prec + 5) > 0) {
|
||||||
|
if (sign) --width;
|
||||||
|
if (prec) --width;
|
||||||
|
}
|
||||||
|
if ((c = --decpt) < 0) c = -c;
|
||||||
|
while (c >= 100) {
|
||||||
|
--width;
|
||||||
|
c /= 10;
|
||||||
|
}
|
||||||
|
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||||
|
if (flags & FLAGS_ZEROPAD) {
|
||||||
|
if (sign) __FMT_PUT(sign);
|
||||||
|
sign = 0;
|
||||||
|
do
|
||||||
|
__FMT_PUT('0');
|
||||||
|
while (--width > 0);
|
||||||
|
} else {
|
||||||
|
do
|
||||||
|
__FMT_PUT(' ');
|
||||||
|
while (--width > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sign) __FMT_PUT(sign);
|
||||||
|
__FMT_PUT(*s++);
|
||||||
|
if (prec) __FMT_PUT('.');
|
||||||
|
while (--prec >= 0) {
|
||||||
|
if ((c = *s)) {
|
||||||
|
s++;
|
||||||
|
} else {
|
||||||
|
c = '0';
|
||||||
|
}
|
||||||
|
__FMT_PUT(c);
|
||||||
|
}
|
||||||
|
__fmt_free_dtoa(&mem);
|
||||||
|
__FMT_PUT(d);
|
||||||
|
if (decpt < 0) {
|
||||||
|
__FMT_PUT('-');
|
||||||
|
decpt = -decpt;
|
||||||
|
} else {
|
||||||
|
__FMT_PUT('+');
|
||||||
|
}
|
||||||
|
for (c = 2, k = 10; 10 * k <= decpt; c++) k *= 10;
|
||||||
|
for (;;) {
|
||||||
|
i1 = decpt / k;
|
||||||
|
__FMT_PUT(i1 + '0');
|
||||||
|
if (--c <= 0) break;
|
||||||
|
decpt -= i1 * k;
|
||||||
|
decpt *= 10;
|
||||||
|
}
|
||||||
|
while (--width >= 0) {
|
||||||
|
__FMT_PUT(' ');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
alphabet = "0123456789abcdefpx";
|
||||||
|
goto FormatBinary;
|
||||||
|
case 'A':
|
||||||
|
alphabet = "0123456789ABCDEFPX";
|
||||||
|
FormatBinary:
|
||||||
|
if (longdouble) {
|
||||||
|
pun.d = va_arg(va, long double);
|
||||||
|
} else {
|
||||||
|
pun.d = va_arg(va, double);
|
||||||
|
}
|
||||||
|
if ((pun.u[1] & 0x7ff00000) == 0x7ff00000) {
|
||||||
|
goto FormatDtoa;
|
||||||
|
}
|
||||||
|
if (pun.u[1] & 0x80000000) {
|
||||||
|
sign = '-';
|
||||||
|
pun.u[1] &= 0x7fffffff;
|
||||||
|
}
|
||||||
|
if (pun.d) {
|
||||||
|
c = '1';
|
||||||
|
bex = (pun.u[1] >> 20) - 1023;
|
||||||
|
pun.u[1] &= 0xfffff;
|
||||||
|
if (bex == -1023) {
|
||||||
|
++bex;
|
||||||
|
if (pun.u[1]) {
|
||||||
|
do {
|
||||||
|
--bex;
|
||||||
|
pun.u[1] <<= 1;
|
||||||
|
if (pun.u[0] & 0x80000000) pun.u[1] |= 1;
|
||||||
|
pun.u[0] <<= 1;
|
||||||
|
} while (pun.u[1] < 0x100000);
|
||||||
|
} else {
|
||||||
|
while (!(pun.u[0] & 0x80000000)) {
|
||||||
|
--bex;
|
||||||
|
pun.u[0] <<= 1;
|
||||||
|
}
|
||||||
|
bex -= 21;
|
||||||
|
pun.u[1] = pun.u[0] >> 11;
|
||||||
|
pun.u[0] <<= 21;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c = '0';
|
||||||
|
bex = 0;
|
||||||
|
}
|
||||||
|
if (flags & FLAGS_PRECISION) {
|
||||||
|
if (prec > 13) prec = 13;
|
||||||
|
if (pun.d && prec < 13) {
|
||||||
|
pun.u[1] |= 0x100000;
|
||||||
|
if (prec < 5) {
|
||||||
|
ui = 1u << ((5 - prec) * 4 - 1);
|
||||||
|
if (pun.u[1] & ui) {
|
||||||
|
if (pun.u[1] & ((ui - 1) | (ui << 1)) || pun.u[0]) {
|
||||||
|
pun.u[1] += ui;
|
||||||
|
BexCheck:
|
||||||
|
if (pun.u[1] & 0x200000) {
|
||||||
|
++bex;
|
||||||
|
pun.u[1] >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (prec == 5) {
|
||||||
|
if (pun.u[0] & 0x80000000) {
|
||||||
|
BumpIt:
|
||||||
|
++pun.u[1];
|
||||||
|
goto BexCheck;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i1 = (13 - prec) * 4;
|
||||||
|
ui = 1u << (i1 - 1);
|
||||||
|
if (pun.u[0] & ui && pun.u[0] & ((ui - 1) | (ui << 1))) {
|
||||||
|
pun.u[0] += ui;
|
||||||
|
if (!(pun.u[0] >> i1)) goto BumpIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((ui = pun.u[0])) {
|
||||||
|
ui = __builtin_ctz(ui);
|
||||||
|
prec = 6 + ((32 - ROUNDDOWN(ui, 4)) >> 2) - 1;
|
||||||
|
} else if ((ui = pun.u[1] & 0xfffff)) {
|
||||||
|
ui = __builtin_ctz(ui);
|
||||||
|
prec = (20 - ROUNDDOWN(ui, 4)) >> 2;
|
||||||
|
} else {
|
||||||
|
prec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bw = 1;
|
||||||
|
if (bex) {
|
||||||
|
if ((i1 = bex) < 0) i1 = -i1;
|
||||||
|
while (i1 >= 10) {
|
||||||
|
++bw;
|
||||||
|
i1 /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pun.u[1] & 0x80000000) {
|
||||||
|
pun.u[1] &= 0x7fffffff;
|
||||||
|
if (pun.d || sign) sign = '-';
|
||||||
|
}
|
||||||
|
if ((width -= bw + 5) > 0) {
|
||||||
|
if (sign) --width;
|
||||||
|
if (prec) --width;
|
||||||
|
}
|
||||||
|
if (pun.q && prec > 0) {
|
||||||
|
width -= ROUNDUP(bsrl(pun.q) + 1, 4) >> 2;
|
||||||
|
}
|
||||||
|
if (width > 0 && !(flags & FLAGS_LEFT)) {
|
||||||
|
if (flags & FLAGS_ZEROPAD) {
|
||||||
|
if (sign) {
|
||||||
|
__FMT_PUT(sign);
|
||||||
|
sign = 0;
|
||||||
|
}
|
||||||
|
do
|
||||||
|
__FMT_PUT('0');
|
||||||
|
while (--width > 0);
|
||||||
|
} else {
|
||||||
|
do
|
||||||
|
__FMT_PUT(' ');
|
||||||
|
while (--width > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sign) __FMT_PUT(sign);
|
||||||
|
__FMT_PUT('0');
|
||||||
|
__FMT_PUT(alphabet[17]);
|
||||||
|
__FMT_PUT(c);
|
||||||
|
if (prec > 0) __FMT_PUT('.');
|
||||||
|
while (prec-- > 0) {
|
||||||
|
__FMT_PUT(alphabet[(pun.q >> 48) & 0xf]);
|
||||||
|
pun.q <<= 4;
|
||||||
|
}
|
||||||
|
__FMT_PUT(alphabet[16]);
|
||||||
|
if (bex < 0) {
|
||||||
|
__FMT_PUT('-');
|
||||||
|
bex = -bex;
|
||||||
|
} else {
|
||||||
|
__FMT_PUT('+');
|
||||||
|
}
|
||||||
|
for (c = 1; 10 * c <= bex;) c *= 10;
|
||||||
|
for (;;) {
|
||||||
|
i1 = bex / c;
|
||||||
|
__FMT_PUT('0' + i1);
|
||||||
|
if (!--bw) break;
|
||||||
|
bex -= i1 * c;
|
||||||
|
bex *= 10;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
FormatString:
|
||||||
|
if (__fmt_stoa(out, arg, p, flags, prec, width, signbit, qchar) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
34
third_party/lua/lapi.c
vendored
34
third_party/lua/lapi.c
vendored
|
@ -1001,6 +1001,15 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lua_seti [-1, +0, e]
|
||||||
|
*
|
||||||
|
* Does the equivalent to t[n] = v, where t is the value at the given index
|
||||||
|
* and v is the value on the top of the stack.
|
||||||
|
*
|
||||||
|
* This function pops the value from the stack. As in Lua, this function may
|
||||||
|
* trigger a metamethod for the "newindex" event (see §2.4).
|
||||||
|
*/
|
||||||
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
||||||
TValue *t;
|
TValue *t;
|
||||||
const TValue *slot;
|
const TValue *slot;
|
||||||
|
@ -1033,11 +1042,27 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lua_rawset [-2, +0, m]
|
||||||
|
*
|
||||||
|
* Similar to lua_settable, but does a raw assignment (i.e., without
|
||||||
|
* metamethods).
|
||||||
|
*/
|
||||||
LUA_API void lua_rawset (lua_State *L, int idx) {
|
LUA_API void lua_rawset (lua_State *L, int idx) {
|
||||||
aux_rawset(L, idx, s2v(L->top - 2), 2);
|
aux_rawset(L, idx, s2v(L->top - 2), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lua_rawsetp [-1, +0, m]
|
||||||
|
*
|
||||||
|
* Does the equivalent of t[p] = v, where t is the table at the given index,
|
||||||
|
* p is encoded as a light userdata, and v is the value on the top of the
|
||||||
|
* stack.
|
||||||
|
*
|
||||||
|
* This function pops the value from the stack. The assignment is raw, that
|
||||||
|
* is, it does not use the __newindex metavalue.
|
||||||
|
*/
|
||||||
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
|
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
|
||||||
TValue k;
|
TValue k;
|
||||||
setpvalue(&k, cast_voidp(p));
|
setpvalue(&k, cast_voidp(p));
|
||||||
|
@ -1045,6 +1070,15 @@ LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lua_rawseti [-1, +0, m]
|
||||||
|
*
|
||||||
|
* Does the equivalent of t[i] = v, where t is the table at the given index
|
||||||
|
* and v is the value on the top of the stack.
|
||||||
|
*
|
||||||
|
* This function pops the value from the stack. The assignment is raw, that
|
||||||
|
* is, it does not use the __newindex metavalue.
|
||||||
|
*/
|
||||||
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
|
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
|
||||||
Table *t;
|
Table *t;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
|
1
third_party/lua/llimits.h
vendored
1
third_party/lua/llimits.h
vendored
|
@ -86,7 +86,6 @@ typedef LUAI_UACINT l_uacInt;
|
||||||
*/
|
*/
|
||||||
#if defined LUAI_ASSERT
|
#if defined LUAI_ASSERT
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <assert.h>
|
|
||||||
#define lua_assert(c) assert(c)
|
#define lua_assert(c) assert(c)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ static const struct sock_filter kSandboxFilter[] = {
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x04f), // getcwd
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x010), // ioctl todo
|
_SECCOMP_ALLOW_SYSCALL(0x010), // ioctl todo
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x016), // pipe
|
_SECCOMP_ALLOW_SYSCALL(0x016), // pipe
|
||||||
|
@ -60,6 +61,15 @@ static const struct sock_filter kSandboxFilter[] = {
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x127), // preadv
|
_SECCOMP_ALLOW_SYSCALL(0x127), // preadv
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x128), // pwritev
|
_SECCOMP_ALLOW_SYSCALL(0x128), // pwritev
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0d9), // getdents
|
_SECCOMP_ALLOW_SYSCALL(0x0d9), // getdents
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x066), // getuid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x068), // getgid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x06e), // getppid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x06f), // getpgrp
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x07c), // getsid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x06b), // geteuid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x06c), // getegid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x061), // getrlimit
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x028), // sendfile
|
_SECCOMP_ALLOW_SYSCALL(0x028), // sendfile
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x02d), // recvfrom
|
_SECCOMP_ALLOW_SYSCALL(0x02d), // recvfrom
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x033), // getsockname
|
_SECCOMP_ALLOW_SYSCALL(0x033), // getsockname
|
||||||
|
@ -67,7 +77,6 @@ static const struct sock_filter kSandboxFilter[] = {
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x060), // gettimeofday
|
_SECCOMP_ALLOW_SYSCALL(0x060), // gettimeofday
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x03c), // exit
|
_SECCOMP_ALLOW_SYSCALL(0x03c), // exit
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
||||||
|
|
80
tool/net/demo/unix-info.lua
Normal file
80
tool/net/demo/unix-info.lua
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
local unix = require 'unix'
|
||||||
|
|
||||||
|
Write('<!doctype html>\r\n')
|
||||||
|
Write('<title>redbean</title>\r\n')
|
||||||
|
Write('<h3>UNIX Information Demo</h3>\r\n')
|
||||||
|
|
||||||
|
Write('<dl>\r\n')
|
||||||
|
Write('<dt>getuid()\r\n')
|
||||||
|
Write(string.format('<dd>%d\r\n', unix.getuid()))
|
||||||
|
Write('<dt>getgid()\r\n')
|
||||||
|
Write(string.format('<dd>%d\r\n', unix.getgid()))
|
||||||
|
Write('<dt>getpid()\r\n')
|
||||||
|
Write(string.format('<dd>%d\r\n', unix.getpid()))
|
||||||
|
Write('<dt>getppid()\r\n')
|
||||||
|
Write(string.format('<dd>%d\r\n', unix.getppid()))
|
||||||
|
Write('<dt>getpgrp()\r\n')
|
||||||
|
Write(string.format('<dd>%d\r\n', unix.getpgrp()))
|
||||||
|
|
||||||
|
Write('<dt>getsid(0)\r\n')
|
||||||
|
sid, errno = unix.getsid(0)
|
||||||
|
if sid then
|
||||||
|
Write(string.format('<dd>%d\r\n', sid))
|
||||||
|
else
|
||||||
|
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.strerrno(errno))))
|
||||||
|
end
|
||||||
|
|
||||||
|
Write('<dt>gethostname()\r\n')
|
||||||
|
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.gethostname())))
|
||||||
|
Write('<dt>getcwd()\r\n')
|
||||||
|
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.getcwd())))
|
||||||
|
|
||||||
|
function PrintResourceLimit(name, id)
|
||||||
|
soft, hard, errno = unix.getrlimit(id)
|
||||||
|
Write(string.format('<dt>getrlimit(%s)\r\n', name))
|
||||||
|
if soft then
|
||||||
|
Write('<dd>')
|
||||||
|
Write('soft ')
|
||||||
|
if soft == -1 then
|
||||||
|
Write('∞')
|
||||||
|
else
|
||||||
|
Write(string.format('%d', soft))
|
||||||
|
end
|
||||||
|
Write('<br>\r\n')
|
||||||
|
Write('hard ')
|
||||||
|
if hard == -1 then
|
||||||
|
Write('∞')
|
||||||
|
else
|
||||||
|
Write(string.format('%d', hard))
|
||||||
|
end
|
||||||
|
Write('\r\n')
|
||||||
|
else
|
||||||
|
Write(string.format('<dd>%s\r\n', EscapeHtml(unix.strerrno(errno))))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
PrintResourceLimit('RLIMIT_AS', unix.RLIMIT_AS)
|
||||||
|
PrintResourceLimit('RLIMIT_RSS', unix.RLIMIT_RSS)
|
||||||
|
PrintResourceLimit('RLIMIT_CPU', unix.RLIMIT_CPU)
|
||||||
|
PrintResourceLimit('RLIMIT_FSIZE', unix.RLIMIT_FSIZE)
|
||||||
|
PrintResourceLimit('RLIMIT_NPROC', unix.RLIMIT_NPROC)
|
||||||
|
PrintResourceLimit('RLIMIT_NOFILE', unix.RLIMIT_NOFILE)
|
||||||
|
|
||||||
|
Write('<dt>siocgifconf()\r\n')
|
||||||
|
Write('<dd>\r\n')
|
||||||
|
ifs, errno = unix.siocgifconf()
|
||||||
|
if ifs then
|
||||||
|
for i = 1,#ifs do
|
||||||
|
if ifs[i].netmask ~= 0 then
|
||||||
|
cidr = 32 - Bsf(ifs[i].netmask)
|
||||||
|
else
|
||||||
|
cidr = 0
|
||||||
|
end
|
||||||
|
Write(string.format('%s %s/%d<br>\r\n',
|
||||||
|
EscapeHtml(ifs[i].name),
|
||||||
|
FormatIp(ifs[i].ip),
|
||||||
|
cidr))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Write(string.format('%s\r\n', EscapeHtml(unix.strerrno(errno))))
|
||||||
|
end
|
||||||
|
Write('</dl>\r\n')
|
44
tool/net/demo/unix-subprocess.lua
Normal file
44
tool/net/demo/unix-subprocess.lua
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
-- example of how to run the ls command
|
||||||
|
-- and pipe its output to the http user
|
||||||
|
local unix = require "unix"
|
||||||
|
function main()
|
||||||
|
syscall = 'commandv'
|
||||||
|
ls, errno = unix.commandv("ls")
|
||||||
|
if ls then
|
||||||
|
syscall = 'pipe'
|
||||||
|
reader, writer, errno = unix.pipe()
|
||||||
|
if reader then
|
||||||
|
syscall = 'fork'
|
||||||
|
child, errno = unix.fork()
|
||||||
|
if child then
|
||||||
|
if child == 0 then
|
||||||
|
unix.close(1)
|
||||||
|
unix.dup(writer)
|
||||||
|
unix.close(writer)
|
||||||
|
unix.close(reader)
|
||||||
|
unix.execve(ls, {ls, "-Shal"})
|
||||||
|
unix.exit(127)
|
||||||
|
else
|
||||||
|
unix.close(writer)
|
||||||
|
SetStatus(200)
|
||||||
|
SetHeader('Content-Type', 'text/plain')
|
||||||
|
while true do
|
||||||
|
data = unix.read(reader)
|
||||||
|
if data ~= "" then
|
||||||
|
Write(data)
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
unix.close(reader)
|
||||||
|
unix.wait(-1)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
SetStatus(200)
|
||||||
|
SetHeader('Content-Type', 'text/plain')
|
||||||
|
Write(string.format('error %s calling %s()', unix.strerrno(errno), syscall))
|
||||||
|
end
|
||||||
|
main()
|
|
@ -1,26 +0,0 @@
|
||||||
-- example of how to run the ls command
|
|
||||||
-- and pipe its output to the http user
|
|
||||||
local unix = require "unix"
|
|
||||||
ls = unix.commandv("ls")
|
|
||||||
reader, writer = unix.pipe()
|
|
||||||
if unix.fork() == 0 then
|
|
||||||
unix.close(1)
|
|
||||||
unix.dup(writer)
|
|
||||||
unix.close(writer)
|
|
||||||
unix.close(reader)
|
|
||||||
unix.execve(ls, {ls, "-Shal"})
|
|
||||||
unix.exit(127)
|
|
||||||
else
|
|
||||||
unix.close(writer)
|
|
||||||
SetHeader('Content-Type', 'text/plain')
|
|
||||||
while true do
|
|
||||||
data = unix.read(reader)
|
|
||||||
if data ~= "" then
|
|
||||||
Write(data)
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
unix.close(reader)
|
|
||||||
unix.wait(-1)
|
|
||||||
end
|
|
|
@ -47,15 +47,16 @@ void PrintUsage(char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void UdpServer(void) {
|
void UdpServer(void) {
|
||||||
|
int ip;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
struct sockaddr_in addr2;
|
struct sockaddr_in addr2;
|
||||||
uint32_t addrsize2 = sizeof(struct sockaddr_in);
|
uint32_t addrsize2 = sizeof(struct sockaddr_in);
|
||||||
CHECK_NE(-1, (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)));
|
CHECK_NE(-1, (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)));
|
||||||
CHECK_NE(-1, bind(sock, &addr, addrsize));
|
CHECK_NE(-1, bind(sock, &addr, addrsize));
|
||||||
CHECK_NE(-1, getsockname(sock, &addr2, &addrsize2));
|
CHECK_NE(-1, getsockname(sock, &addr2, &addrsize2));
|
||||||
kprintf("udp server %hhu.%hhu.%hhu.%hhu %hu%n", addr2.sin_addr.s_addr >> 24,
|
ip = ntohl(addr2.sin_addr.s_addr);
|
||||||
addr2.sin_addr.s_addr >> 16, addr2.sin_addr.s_addr >> 8,
|
kprintf("udp server %hhu.%hhu.%hhu.%hhu %hu%n", ip >> 24, ip >> 16, ip >> 8,
|
||||||
addr2.sin_addr.s_addr, addr2.sin_port);
|
ip, ntohs(addr2.sin_port));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CHECK_NE(-1,
|
CHECK_NE(-1,
|
||||||
(rc = recvfrom(sock, buf, sizeof(buf), 0, &addr2, &addrsize2)));
|
(rc = recvfrom(sock, buf, sizeof(buf), 0, &addr2, &addrsize2)));
|
||||||
|
@ -73,23 +74,23 @@ void UdpClient(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TcpServer(void) {
|
void TcpServer(void) {
|
||||||
int client;
|
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
int ip, client;
|
||||||
struct sockaddr_in addr2;
|
struct sockaddr_in addr2;
|
||||||
uint32_t addrsize2 = sizeof(struct sockaddr_in);
|
uint32_t addrsize2 = sizeof(struct sockaddr_in);
|
||||||
CHECK_NE(-1, (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)));
|
CHECK_NE(-1, (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)));
|
||||||
CHECK_NE(-1, bind(sock, &addr, addrsize));
|
CHECK_NE(-1, bind(sock, &addr, addrsize));
|
||||||
CHECK_NE(-1, listen(sock, 10));
|
CHECK_NE(-1, listen(sock, 10));
|
||||||
CHECK_NE(-1, getsockname(sock, &addr2, &addrsize2));
|
CHECK_NE(-1, getsockname(sock, &addr2, &addrsize2));
|
||||||
kprintf("tcp server %hhu.%hhu.%hhu.%hhu %hu%n", addr2.sin_addr.s_addr >> 24,
|
ip = ntohl(addr2.sin_addr.s_addr);
|
||||||
addr2.sin_addr.s_addr >> 16, addr2.sin_addr.s_addr >> 8,
|
kprintf("tcp server %hhu.%hhu.%hhu.%hhu %hu%n", ip >> 24, ip >> 16, ip >> 8,
|
||||||
addr2.sin_addr.s_addr, addr2.sin_port);
|
ip, ntohs(addr2.sin_port));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
addrsize2 = sizeof(struct sockaddr_in);
|
addrsize2 = sizeof(struct sockaddr_in);
|
||||||
CHECK_NE(-1, (client = accept(sock, &addr2, &addrsize2)));
|
CHECK_NE(-1, (client = accept(sock, &addr2, &addrsize2)));
|
||||||
kprintf("got client %hhu.%hhu.%hhu.%hhu %hu%n", addr2.sin_addr.s_addr >> 24,
|
ip = ntohl(addr2.sin_addr.s_addr);
|
||||||
addr2.sin_addr.s_addr >> 16, addr2.sin_addr.s_addr >> 8,
|
kprintf("got client %hhu.%hhu.%hhu.%hhu %hu%n", ip >> 24, ip >> 16, ip >> 8,
|
||||||
addr2.sin_addr.s_addr, addr2.sin_port);
|
ip, ntohs(addr2.sin_port));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
CHECK_NE(-1, (rc = read(client, buf, sizeof(buf))));
|
CHECK_NE(-1, (rc = read(client, buf, sizeof(buf))));
|
||||||
if (!rc) break;
|
if (!rc) break;
|
||||||
|
|
|
@ -1440,7 +1440,7 @@ UNIX MODULE
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
unix.close(reader)
|
unix.close(reader)
|
||||||
unix.wait(-1)
|
unix.wait()
|
||||||
end
|
end
|
||||||
|
|
||||||
unix.wait([pid:int, options:int])
|
unix.wait([pid:int, options:int])
|
||||||
|
@ -1705,6 +1705,28 @@ UNIX MODULE
|
||||||
Further note that calling `unix.bind(sock)` is equivalent to not
|
Further note that calling `unix.bind(sock)` is equivalent to not
|
||||||
calling bind() at all, since the above behavior is the default.
|
calling bind() at all, since the above behavior is the default.
|
||||||
|
|
||||||
|
unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}[, errno:int]
|
||||||
|
|
||||||
|
Returns list of network adapter addresses.
|
||||||
|
|
||||||
|
unix.poll({fd:int=events:int, ...}[, timeoutms:int])
|
||||||
|
→ {fd:int=revents:int, ...}[, errno:int]
|
||||||
|
|
||||||
|
Checks for events on a set of file descriptors.
|
||||||
|
|
||||||
|
The table of file descriptors to poll uses sparse integer keys. Any
|
||||||
|
pairs with non-integer keys will be ignored. Pairs with negative
|
||||||
|
keys are ignored by poll(). The returned table will be a subset of
|
||||||
|
the supplied file descriptors.
|
||||||
|
|
||||||
|
`timeoutms` is the number of seconds to block. If this is set to -1
|
||||||
|
then that means block as long as it takes until there's an event or
|
||||||
|
an interrupt. If the timeout expires, an empty table is returned.
|
||||||
|
|
||||||
|
unix.gethostname() → host:str[, errno:int]
|
||||||
|
|
||||||
|
Returns hostname of system.
|
||||||
|
|
||||||
unix.listen(fd:int[, backlog]) → rc:int[, errno:int]
|
unix.listen(fd:int[, backlog]) → rc:int[, errno:int]
|
||||||
|
|
||||||
Begins listening for incoming connections on a socket.
|
Begins listening for incoming connections on a socket.
|
||||||
|
@ -1802,20 +1824,6 @@ UNIX MODULE
|
||||||
unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND)
|
unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND)
|
||||||
unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0)
|
unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0)
|
||||||
|
|
||||||
unix.reboot(how:int) → str
|
|
||||||
|
|
||||||
Changes power status of system.
|
|
||||||
|
|
||||||
`how` may be `RB_AUTOBOOT` to reboot, `RB_POWER_OFF` to power
|
|
||||||
down, `RB_HALT_SYSTEM` to literally just stop the processor, or
|
|
||||||
`RB_SW_SUSPEND` to put the machine into a suspend state. These
|
|
||||||
magnums will be set to -1 if the method isn't supported on the
|
|
||||||
host platform.
|
|
||||||
|
|
||||||
By default, an implicit sync() is performed. That's to help
|
|
||||||
prevent you from losing data. If you don't want to shutdown
|
|
||||||
gracefully, then you can bitwise or `RB_NOSYNC` into `how`.
|
|
||||||
|
|
||||||
unix.strerrno(errno:int) → str
|
unix.strerrno(errno:int) → str
|
||||||
|
|
||||||
Turns `errno` code into its symbolic name, e.g. `"EINTR"`.
|
Turns `errno` code into its symbolic name, e.g. `"EINTR"`.
|
||||||
|
@ -1829,6 +1837,41 @@ UNIX MODULE
|
||||||
Turns platform-specific `sig` code into its name, e.g.
|
Turns platform-specific `sig` code into its name, e.g.
|
||||||
`strsignal(9)` always returns `"SIGKILL"`.
|
`strsignal(9)` always returns `"SIGKILL"`.
|
||||||
|
|
||||||
|
unix.setrlimit(resource:int, soft:int[, hard:int]) → rc:int[, errno:int]
|
||||||
|
|
||||||
|
Changes resource limit.
|
||||||
|
|
||||||
|
`resource` may be one of:
|
||||||
|
|
||||||
|
- `RLIMIT_AS` limits the size of the virtual address space. This
|
||||||
|
will work on all platforms. It's emulated on XNU and Windows which
|
||||||
|
means it won't propagate across execve() currently.
|
||||||
|
|
||||||
|
- `RLIMIT_CPU` causes `SIGXCPU` to be sent to the process when the
|
||||||
|
soft limit on CPU time is exceeded, and the process is destroyed
|
||||||
|
when the hard limit is exceeded. It works everywhere but Windows
|
||||||
|
where it should be possible to poll getrusage() with setitimer()
|
||||||
|
|
||||||
|
- `RLIMIT_FSIZE` causes `SIGXFSZ` to sent to the process when the
|
||||||
|
soft limit on file size is exceeded and the process is destroyed
|
||||||
|
when the hard limit is exceeded. It works everywhere but Windows
|
||||||
|
|
||||||
|
- `RLIMIT_NPROC` limits the number of simultaneous processes and it
|
||||||
|
should work on all platforms except Windows. Please be advised it
|
||||||
|
limits the process, with respect to the activities of the user id
|
||||||
|
as a whole.
|
||||||
|
|
||||||
|
- `RLIMIT_NOFILE` limits the number of open file descriptors and it
|
||||||
|
should work on all platforms except Windows (TODO)
|
||||||
|
|
||||||
|
If a limit isn't supported by the host platform, it'll be set to
|
||||||
|
127. On most platforms these limits are enforced by the kernel and
|
||||||
|
as such are inherited by subprocesses.
|
||||||
|
|
||||||
|
unix.getrlimit(resource:int) → soft:int, hard:int[, errno:int]
|
||||||
|
|
||||||
|
Returns information about resource limit.
|
||||||
|
|
||||||
unix.stat(x) → UnixStat*, errno:int
|
unix.stat(x) → UnixStat*, errno:int
|
||||||
|
|
||||||
Gets information about file or directory. `x` may be a file or
|
Gets information about file or directory. `x` may be a file or
|
||||||
|
|
166
tool/net/lunix.c
166
tool/net/lunix.c
|
@ -18,6 +18,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/ioctl.h"
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/dirent.h"
|
#include "libc/calls/struct/dirent.h"
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
#include "libc/calls/struct/stat.h"
|
#include "libc/calls/struct/stat.h"
|
||||||
#include "libc/calls/struct/timespec.h"
|
#include "libc/calls/struct/timespec.h"
|
||||||
#include "libc/calls/ucontext.h"
|
#include "libc/calls/ucontext.h"
|
||||||
|
#include "libc/dns/dns.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/fmt/fmt.h"
|
#include "libc/fmt/fmt.h"
|
||||||
#include "libc/fmt/kerrornames.internal.h"
|
#include "libc/fmt/kerrornames.internal.h"
|
||||||
|
@ -52,13 +54,15 @@
|
||||||
#include "libc/sysv/consts/nr.h"
|
#include "libc/sysv/consts/nr.h"
|
||||||
#include "libc/sysv/consts/o.h"
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/ok.h"
|
#include "libc/sysv/consts/ok.h"
|
||||||
#include "libc/sysv/consts/reboot.h"
|
#include "libc/sysv/consts/rlim.h"
|
||||||
#include "libc/sysv/consts/rlimit.h"
|
#include "libc/sysv/consts/rlimit.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/shut.h"
|
#include "libc/sysv/consts/shut.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
|
#include "libc/sysv/consts/sio.h"
|
||||||
#include "libc/sysv/consts/sock.h"
|
#include "libc/sysv/consts/sock.h"
|
||||||
#include "libc/sysv/consts/w.h"
|
#include "libc/sysv/consts/w.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
#include "libc/time/time.h"
|
#include "libc/time/time.h"
|
||||||
#include "libc/x/x.h"
|
#include "libc/x/x.h"
|
||||||
#include "third_party/lua/lauxlib.h"
|
#include "third_party/lua/lauxlib.h"
|
||||||
|
@ -104,14 +108,6 @@ static dontinline int ReturnTimespec(lua_State *L, struct timespec *ts) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ReturnRc(lua_State *L, int64_t rc, int olderr) {
|
|
||||||
lua_pushinteger(L, rc);
|
|
||||||
if (rc != -1) return 1;
|
|
||||||
lua_pushinteger(L, errno);
|
|
||||||
errno = olderr;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ReturnErrno(lua_State *L, int nils, int olderr) {
|
static int ReturnErrno(lua_State *L, int nils, int olderr) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < nils; ++i) {
|
for (i = 0; i < nils; ++i) {
|
||||||
|
@ -122,6 +118,15 @@ static int ReturnErrno(lua_State *L, int nils, int olderr) {
|
||||||
return nils + 1;
|
return nils + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ReturnRc(lua_State *L, int64_t rc, int olderr) {
|
||||||
|
if (rc != -1) {
|
||||||
|
lua_pushinteger(L, rc);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char **ConvertLuaArrayToStringList(lua_State *L, int i) {
|
static char **ConvertLuaArrayToStringList(lua_State *L, int i) {
|
||||||
int j, n;
|
int j, n;
|
||||||
char **p;
|
char **p;
|
||||||
|
@ -146,7 +151,7 @@ static char **ConvertLuaTableToEnvList(lua_State *L, int i) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
for (n = 0; lua_next(L, i);) {
|
for (n = 0; lua_next(L, i);) {
|
||||||
if (lua_type(L, -2) == LUA_TSTRING) {
|
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||||
p = xrealloc(p, (++n + 1) * sizeof(char *));
|
p = xrealloc(p, (++n + 1) * sizeof(*p));
|
||||||
p[n - 1] = xasprintf("%s=%s", lua_tostring(L, -2), lua_tostring(L, -1));
|
p[n - 1] = xasprintf("%s=%s", lua_tostring(L, -2), lua_tostring(L, -1));
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
@ -322,12 +327,16 @@ static int LuaUnixChmod(lua_State *L) {
|
||||||
|
|
||||||
// unix.getcwd(path:str, mode:int) → rc:int[, errno:int]
|
// unix.getcwd(path:str, mode:int) → rc:int[, errno:int]
|
||||||
static int LuaUnixGetcwd(lua_State *L) {
|
static int LuaUnixGetcwd(lua_State *L) {
|
||||||
|
int olderr;
|
||||||
char *path;
|
char *path;
|
||||||
path = getcwd(0, 0);
|
olderr = errno;
|
||||||
assert(path);
|
if ((path = getcwd(0, 0))) {
|
||||||
lua_pushstring(L, path);
|
lua_pushstring(L, path);
|
||||||
free(path);
|
free(path);
|
||||||
return 1;
|
return 1;
|
||||||
|
} else {
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.fork() → childpid|0:int[, errno:int]
|
// unix.fork() → childpid|0:int[, errno:int]
|
||||||
|
@ -374,9 +383,7 @@ static int LuaUnixExecve(lua_State *L) {
|
||||||
execve(prog, argv, envp);
|
execve(prog, argv, envp);
|
||||||
FreeStringList(freeme1);
|
FreeStringList(freeme1);
|
||||||
FreeStringList(freeme2);
|
FreeStringList(freeme2);
|
||||||
lua_pushinteger(L, errno);
|
return ReturnErrno(L, 1, olderr);
|
||||||
errno = olderr;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.commandv(prog:str) → path:str[, errno:int]
|
// unix.commandv(prog:str) → path:str[, errno:int]
|
||||||
|
@ -450,8 +457,8 @@ static int LuaUnixGetrlimit(lua_State *L) {
|
||||||
olderr = errno;
|
olderr = errno;
|
||||||
resource = luaL_checkinteger(L, 1);
|
resource = luaL_checkinteger(L, 1);
|
||||||
if (!getrlimit(resource, &rlim)) {
|
if (!getrlimit(resource, &rlim)) {
|
||||||
lua_pushinteger(L, rlim.rlim_cur);
|
lua_pushinteger(L, rlim.rlim_cur < RLIM_INFINITY ? rlim.rlim_cur : -1);
|
||||||
lua_pushinteger(L, rlim.rlim_max);
|
lua_pushinteger(L, rlim.rlim_max < RLIM_INFINITY ? rlim.rlim_max : -1);
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
return ReturnErrno(L, 2, olderr);
|
return ReturnErrno(L, 2, olderr);
|
||||||
|
@ -931,7 +938,7 @@ static int LuaUnixGetsockname(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.getpeername(fd) → ip, port, errno
|
// unix.getpeername(fd:int) → ip:uint32, port:uint16[, errno:int]
|
||||||
static int LuaUnixGetpeername(lua_State *L) {
|
static int LuaUnixGetpeername(lua_State *L) {
|
||||||
int fd, olderr;
|
int fd, olderr;
|
||||||
uint32_t addrsize;
|
uint32_t addrsize;
|
||||||
|
@ -948,7 +955,72 @@ static int LuaUnixGetpeername(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.accept(serverfd:int) → clientfd:int, ip:uint32, port:uint16, errno
|
// unix.siocgifconf() → {{name:str,ip:uint32,netmask:uint32}, ...}[, errno:int]
|
||||||
|
static int LuaUnixSiocgifconf(lua_State *L) {
|
||||||
|
size_t n;
|
||||||
|
char *data;
|
||||||
|
int i, fd, olderr;
|
||||||
|
struct ifreq *ifr;
|
||||||
|
struct ifconf conf;
|
||||||
|
olderr = errno;
|
||||||
|
if (!(data = malloc((n = 4096)))) {
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
|
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
|
||||||
|
free(data);
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
|
conf.ifc_buf = data;
|
||||||
|
conf.ifc_len = n;
|
||||||
|
if (ioctl(fd, SIOCGIFCONF, &conf) == -1) {
|
||||||
|
close(fd);
|
||||||
|
free(data);
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
|
lua_newtable(L);
|
||||||
|
i = 0;
|
||||||
|
for (ifr = (struct ifreq *)data; (char *)ifr < data + conf.ifc_len; ++ifr) {
|
||||||
|
if (ifr->ifr_addr.sa_family != AF_INET) continue;
|
||||||
|
lua_createtable(L, 0, 3);
|
||||||
|
lua_pushstring(L, "name");
|
||||||
|
lua_pushstring(L, ifr->ifr_name);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
lua_pushstring(L, "ip");
|
||||||
|
lua_pushinteger(
|
||||||
|
L, ntohl(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr));
|
||||||
|
lua_settable(L, -3);
|
||||||
|
if (ioctl(fd, SIOCGIFNETMASK, ifr) != -1) {
|
||||||
|
lua_pushstring(L, "netmask");
|
||||||
|
lua_pushinteger(
|
||||||
|
L, ntohl(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr));
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
lua_rawseti(L, -2, ++i);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
free(data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unix.gethostname() → host:str[, errno:int]
|
||||||
|
static int LuaUnixGethostname(lua_State *L) {
|
||||||
|
int rc, olderr;
|
||||||
|
char buf[DNS_NAME_MAX + 1];
|
||||||
|
olderr = errno;
|
||||||
|
if ((rc = gethostname(buf, sizeof(buf))) != -1) {
|
||||||
|
if (strnlen(buf, sizeof(buf)) < sizeof(buf)) {
|
||||||
|
lua_pushstring(L, buf);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
enomem();
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unix.accept(serverfd:int) → clientfd:int, ip:uint32, port:uint16[, errno:int]
|
||||||
static int LuaUnixAccept(lua_State *L) {
|
static int LuaUnixAccept(lua_State *L) {
|
||||||
uint32_t addrsize;
|
uint32_t addrsize;
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
|
@ -967,6 +1039,40 @@ static int LuaUnixAccept(lua_State *L) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unix.poll({fd:int=events:int, ...}[, timeoutms:int])
|
||||||
|
// → {fd:int=revents:int, ...}[, errno:int]
|
||||||
|
static int LuaUnixPoll(lua_State *L) {
|
||||||
|
size_t nfds;
|
||||||
|
struct pollfd *fds;
|
||||||
|
int i, fd, olderr, events, timeoutms;
|
||||||
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
lua_pushnil(L);
|
||||||
|
for (fds = 0, nfds = 0; lua_next(L, 1);) {
|
||||||
|
if (lua_isinteger(L, -2)) {
|
||||||
|
fds = xrealloc(fds, ++nfds * sizeof(*fds));
|
||||||
|
fds[nfds - 1].fd = lua_tointeger(L, -2);
|
||||||
|
fds[nfds - 1].events = lua_tointeger(L, -1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
timeoutms = luaL_optinteger(L, 2, -1);
|
||||||
|
olderr = errno;
|
||||||
|
if ((events = poll(fds, nfds, timeoutms)) != -1) {
|
||||||
|
lua_createtable(L, events, 0);
|
||||||
|
for (i = 0; i < nfds; ++i) {
|
||||||
|
if (fds[i].revents && fds[i].fd >= 0) {
|
||||||
|
lua_pushinteger(L, fds[i].revents);
|
||||||
|
lua_rawseti(L, -2, fds[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(fds);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
free(fds);
|
||||||
|
return ReturnErrno(L, 1, olderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// unix.recvfrom(fd[, bufsiz[, flags]]) → data, ip, port[, errno]
|
// unix.recvfrom(fd[, bufsiz[, flags]]) → data, ip, port[, errno]
|
||||||
// flags can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
// flags can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc.
|
||||||
static int LuaUnixRecvfrom(lua_State *L) {
|
static int LuaUnixRecvfrom(lua_State *L) {
|
||||||
|
@ -1286,11 +1392,6 @@ static int LuaUnixWtermsig(lua_State *L) {
|
||||||
return ReturnInteger(L, WTERMSIG(luaL_checkinteger(L, 1)));
|
return ReturnInteger(L, WTERMSIG(luaL_checkinteger(L, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.reboot(how:int) → rc:int[, errno:int]
|
|
||||||
static int LuaUnixReboot(lua_State *L) {
|
|
||||||
return ReturnInteger(L, reboot(luaL_checkinteger(L, 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// UnixStat* object
|
// UnixStat* object
|
||||||
|
|
||||||
|
@ -1568,10 +1669,12 @@ static const luaL_Reg kLuaUnix[] = {
|
||||||
{"setuid", LuaUnixSetuid}, // set real user id of process
|
{"setuid", LuaUnixSetuid}, // set real user id of process
|
||||||
{"getgid", LuaUnixGetgid}, // get real group id of process
|
{"getgid", LuaUnixGetgid}, // get real group id of process
|
||||||
{"setgid", LuaUnixSetgid}, // set real group id of process
|
{"setgid", LuaUnixSetgid}, // set real group id of process
|
||||||
|
{"gethostname", LuaUnixGethostname}, // get hostname of this machine
|
||||||
{"clock_gettime", LuaUnixGettime}, // get timestamp w/ nano precision
|
{"clock_gettime", LuaUnixGettime}, // get timestamp w/ nano precision
|
||||||
{"nanosleep", LuaUnixNanosleep}, // sleep w/ nano precision
|
{"nanosleep", LuaUnixNanosleep}, // sleep w/ nano precision
|
||||||
{"socket", LuaUnixSocket}, // create network communication fd
|
{"socket", LuaUnixSocket}, // create network communication fd
|
||||||
{"socketpair", LuaUnixSocketpair}, // create bidirectional pipe
|
{"socketpair", LuaUnixSocketpair}, // create bidirectional pipe
|
||||||
|
{"poll", LuaUnixPoll}, // waits for file descriptor events
|
||||||
{"bind", LuaUnixBind}, // reserve network interface address
|
{"bind", LuaUnixBind}, // reserve network interface address
|
||||||
{"listen", LuaUnixListen}, // begin listening for clients
|
{"listen", LuaUnixListen}, // begin listening for clients
|
||||||
{"accept", LuaUnixAccept}, // create client fd for client
|
{"accept", LuaUnixAccept}, // create client fd for client
|
||||||
|
@ -1583,11 +1686,11 @@ static const luaL_Reg kLuaUnix[] = {
|
||||||
{"shutdown", LuaUnixShutdown}, // make socket half empty or full
|
{"shutdown", LuaUnixShutdown}, // make socket half empty or full
|
||||||
{"getpeername", LuaUnixGetpeername}, // get address of remote end
|
{"getpeername", LuaUnixGetpeername}, // get address of remote end
|
||||||
{"getsockname", LuaUnixGetsockname}, // get address of local end
|
{"getsockname", LuaUnixGetsockname}, // get address of local end
|
||||||
|
{"siocgifconf", LuaUnixSiocgifconf}, // get list of network interfaces
|
||||||
{"sigaction", LuaUnixSigaction}, // install signal handler
|
{"sigaction", LuaUnixSigaction}, // install signal handler
|
||||||
{"sigprocmask", LuaUnixSigprocmask}, // change signal mask
|
{"sigprocmask", LuaUnixSigprocmask}, // change signal mask
|
||||||
{"sigsuspend", LuaUnixSigsuspend}, // wait for signal
|
{"sigsuspend", LuaUnixSigsuspend}, // wait for signal
|
||||||
{"setitimer", LuaUnixSetitimer}, // set alarm clock
|
{"setitimer", LuaUnixSetitimer}, // set alarm clock
|
||||||
{"reboot", LuaUnixReboot}, // reboots system
|
|
||||||
{"strerror", LuaUnixStrerror}, // turn errno into string
|
{"strerror", LuaUnixStrerror}, // turn errno into string
|
||||||
{"strerrno", LuaUnixStrerrno}, // turn errno into string
|
{"strerrno", LuaUnixStrerrno}, // turn errno into string
|
||||||
{"strsignal", LuaUnixStrsignal}, // turn signal into string
|
{"strsignal", LuaUnixStrsignal}, // turn signal into string
|
||||||
|
@ -1765,12 +1868,5 @@ int LuaUnix(lua_State *L) {
|
||||||
LuaSetIntField(L, "LOG_INFO", LOG_INFO);
|
LuaSetIntField(L, "LOG_INFO", LOG_INFO);
|
||||||
LuaSetIntField(L, "LOG_DEBUG", LOG_DEBUG);
|
LuaSetIntField(L, "LOG_DEBUG", LOG_DEBUG);
|
||||||
|
|
||||||
// reboot() howto
|
|
||||||
LuaSetIntField(L, "RB_AUTOBOOT", RB_AUTOBOOT);
|
|
||||||
LuaSetIntField(L, "RB_POWER_OFF", RB_POWER_OFF);
|
|
||||||
LuaSetIntField(L, "RB_HALT_SYSTEM", RB_HALT_SYSTEM);
|
|
||||||
LuaSetIntField(L, "RB_SW_SUSPEND", RB_SW_SUSPEND);
|
|
||||||
LuaSetIntField(L, "RB_NOSYNC", RB_NOSYNC);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,9 @@ o/tinylinux/tool/net/redbean.com: \
|
||||||
o/$(MODE)/tool/net/demo/.init.lua.zip.o \
|
o/$(MODE)/tool/net/demo/.init.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/.reload.lua.zip.o \
|
o/$(MODE)/tool/net/demo/.reload.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||||
|
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||||
|
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/maxmind.lua.zip.o \
|
o/$(MODE)/tool/net/demo/maxmind.lua.zip.o \
|
||||||
|
@ -213,8 +215,9 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
||||||
o/$(MODE)/tool/net/largon2.o \
|
o/$(MODE)/tool/net/largon2.o \
|
||||||
o/$(MODE)/tool/net/net.pkg \
|
o/$(MODE)/tool/net/net.pkg \
|
||||||
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix2.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||||
|
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
o/$(MODE)/tool/net/demo/hello.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/redbean.lua.zip.o \
|
o/$(MODE)/tool/net/demo/redbean.lua.zip.o \
|
||||||
|
|
|
@ -6608,45 +6608,65 @@ static int ExitWorker(void) {
|
||||||
static const struct sock_filter kSandboxOnline[] = {
|
static const struct sock_filter kSandboxOnline[] = {
|
||||||
_SECCOMP_MACHINE(AUDIT_ARCH_X86_64), //
|
_SECCOMP_MACHINE(AUDIT_ARCH_X86_64), //
|
||||||
_SECCOMP_LOAD_SYSCALL_NR(), //
|
_SECCOMP_LOAD_SYSCALL_NR(), //
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0013), // readv
|
_SECCOMP_ALLOW_SYSCALL(0x013), // readv
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0014), // writev
|
_SECCOMP_ALLOW_SYSCALL(0x014), // writev
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0009), // mmap
|
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x000b), // munmap
|
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0000), // read
|
_SECCOMP_ALLOW_SYSCALL(0x000), // read
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0001), // write
|
_SECCOMP_ALLOW_SYSCALL(0x001), // write
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0003), // close
|
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0008), // lseek
|
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x000f), // rt_sigreturn
|
_SECCOMP_ALLOW_SYSCALL(0x04f), // getcwd
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00e7), // exit_group
|
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0106), // newfstatat
|
_SECCOMP_ALLOW_SYSCALL(0x066), // getuid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00e4), // clock_gettime
|
_SECCOMP_ALLOW_SYSCALL(0x068), // getgid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x003f), // uname
|
_SECCOMP_ALLOW_SYSCALL(0x06e), // getppid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0048), // fcntl
|
_SECCOMP_ALLOW_SYSCALL(0x06f), // getpgrp
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0029), // socket
|
_SECCOMP_ALLOW_SYSCALL(0x07c), // getsid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x002a), // connect
|
_SECCOMP_ALLOW_SYSCALL(0x06b), // geteuid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x002c), // sendto
|
_SECCOMP_ALLOW_SYSCALL(0x06c), // getegid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x002d), // recvfrom
|
_SECCOMP_ALLOW_SYSCALL(0x061), // getrlimit
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0036), // setsockopt
|
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x106), // newfstatat
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x048), // fcntl
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x029), // socket
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x02a), // connect
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x02c), // sendto
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x02d), // recvfrom
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x036), // setsockopt
|
||||||
_SECCOMP_LOG_AND_RETURN_ERRNO(1), // EPERM
|
_SECCOMP_LOG_AND_RETURN_ERRNO(1), // EPERM
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sock_filter kSandboxOffline[] = {
|
static const struct sock_filter kSandboxOffline[] = {
|
||||||
_SECCOMP_MACHINE(AUDIT_ARCH_X86_64), //
|
_SECCOMP_MACHINE(AUDIT_ARCH_X86_64), //
|
||||||
_SECCOMP_LOAD_SYSCALL_NR(), //
|
_SECCOMP_LOAD_SYSCALL_NR(), //
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0013), // readv
|
_SECCOMP_ALLOW_SYSCALL(0x013), // readv
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0014), // writev
|
_SECCOMP_ALLOW_SYSCALL(0x014), // writev
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0000), // read
|
_SECCOMP_ALLOW_SYSCALL(0x000), // read
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0001), // write
|
_SECCOMP_ALLOW_SYSCALL(0x001), // write
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0009), // mmap
|
_SECCOMP_ALLOW_SYSCALL(0x009), // mmap
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x000b), // munmap
|
_SECCOMP_ALLOW_SYSCALL(0x00b), // munmap
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0003), // close
|
_SECCOMP_ALLOW_SYSCALL(0x003), // close
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0008), // lseek
|
_SECCOMP_ALLOW_SYSCALL(0x008), // lseek
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x000f), // rt_sigreturn
|
_SECCOMP_ALLOW_SYSCALL(0x04f), // getcwd
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00e7), // exit_group
|
_SECCOMP_ALLOW_SYSCALL(0x027), // getpid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0106), // newfstatat
|
_SECCOMP_ALLOW_SYSCALL(0x066), // getuid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x00e4), // clock_gettime
|
_SECCOMP_ALLOW_SYSCALL(0x068), // getgid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x003f), // uname
|
_SECCOMP_ALLOW_SYSCALL(0x06e), // getppid
|
||||||
_SECCOMP_ALLOW_SYSCALL(0x0048), // fcntl
|
_SECCOMP_ALLOW_SYSCALL(0x06f), // getpgrp
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x07c), // getsid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x06b), // geteuid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x06c), // getegid
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x061), // getrlimit
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x00f), // rt_sigreturn
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x0e7), // exit_group
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x106), // newfstatat
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x0e4), // clock_gettime
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x03f), // uname
|
||||||
|
_SECCOMP_ALLOW_SYSCALL(0x048), // fcntl
|
||||||
_SECCOMP_LOG_AND_RETURN_ERRNO(1), // EPERM
|
_SECCOMP_LOG_AND_RETURN_ERRNO(1), // EPERM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue