Initial import

This commit is contained in:
Justine Tunney
2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

47
libc/escape/aescape.c Normal file
View File

@@ -0,0 +1,47 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/escape/escape.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
/**
* Internal function aspecting escaping ops with allocating behavior.
* @see aescapesh(), aescapec()
*/
int aescape(char **escaped, size_t size, const char *unescaped, unsigned length,
int impl(char *escaped, unsigned size, const char *unescaped,
unsigned length)) {
int wrote;
char *p2;
if ((p2 = realloc(*escaped, size)) != NULL) {
*escaped = p2;
if ((wrote = impl(*escaped, size, unescaped, length)) != -1) {
if ((unsigned)wrote <= size - 1) {
return wrote;
} else {
assert(__builtin_return_address(0) != aescape);
return aescape(escaped, wrote + 1, unescaped, length, impl);
}
}
}
free_s(escaped);
return -1;
}

28
libc/escape/aescapec.c Normal file
View File

@@ -0,0 +1,28 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/escape/escape.h"
/**
* Delegates to escapec(), allocating as much memory as needed.
* @return bytes written excluding NUL, or -1 on alloc error or overflow
*/
int aescapec(char **escaped, const char *unescaped, unsigned length) {
return aescape(escaped, 32, unescaped, length, escapec);
}

28
libc/escape/aescapesh.c Normal file
View File

@@ -0,0 +1,28 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/escape/escape.h"
/**
* Delegates to escapesh(), allocating as much memory as needed.
* @return bytes written excluding NUL, or -1 on alloc error or overflow
*/
int aescapesh(char **escaped, const char *unescaped, unsigned length) {
return aescape(escaped, 32, unescaped, length, escapesh);
}

64
libc/escape/cunescape.c Normal file
View File

@@ -0,0 +1,64 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/escape/escape.h"
#include "libc/macros.h"
#include "libc/str/str.h"
// TODO(jart): implement me
/**
* Decodes backslash escape sequences in-place.
*
* We support the C standard definitions, and the gotchas that entails:
*
* \newline ← noop for multi-line str
* \' \" \? \\ ← we try hard to avoid \?
* \a \b \f \n \r \t \v \e ← \e is A++ GNU extension
* \ octal-digit ← base-8 literal encoding
* \ octal-digit octal-digit ← octal: super dependable
* \ octal-digit octal-digit octal-digit ← longstanding DEC legacy
* \x[0-9A-Fa-f]+ ← base16 literal encoding
* \u[0-9A-Fa-f]{4} ← UNICODEs
* \U[0-9A-Fa-f]{8} (astral planes) ← UNICODEs: Astral Planes
*
* @param n is # bytes in p
* @param p is byte array of string literal content
* @return new byte size of s, or -i to indicate first error at s[i]
* @note we do not check for NUL terminator on input
* @note array is zero-filled if shortened
* @see cescapec(), strlen()
*/
int cunescape(size_t n, char p[n]) {
unsigned char t[32];
unsigned i, j, m, tc, tn, mask;
for (m = n, i = 0; i < n; i += j) {
tc = sizeof(t);
tn = MIN(m - i, tc);
memset(t, 0, tc);
memcpy(t, p + i, tn);
for (mask = j = 0; j < tc; ++j) {
if (p[j] == '\\') mask |= 1u << j;
}
if (j < ARRAYLEN(t)) {
memcpy(p + i, t, tn);
}
}
return m;
}

27
libc/escape/escape.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_
#define COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
│ cosmopolitan § escaping ─╬─│┼
╚────────────────────────────────────────────────────────────────────────────│*/
unsigned cescapec(int c);
int escapec(char *buf, unsigned size, const char *unescaped, unsigned length)
paramsnonnull((3)) nothrow nocallback;
int escapesh(char *buf, unsigned size, const char *unescaped, unsigned length)
paramsnonnull((3));
bool escapedos(char16_t *buffer, unsigned buflen, const char16_t *unquoted,
unsigned len);
int aescapec(char **escaped, const char *unescaped, unsigned length)
paramsnonnull();
int aescapesh(char **escaped, const char *unescaped, unsigned length)
paramsnonnull();
int aescape(char **escaped, size_t size, const char *unescaped, unsigned length,
int impl(char *escaped, unsigned size, const char *unescaped,
unsigned length)) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_ */

57
libc/escape/escape.mk Normal file
View File

@@ -0,0 +1,57 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += LIBC_ESCAPE
LIBC_ESCAPE_ARTIFACTS += LIBC_ESCAPE_A
LIBC_ESCAPE = $(LIBC_ESCAPE_A_DEPS) $(LIBC_ESCAPE_A)
LIBC_ESCAPE_A = o/$(MODE)/libc/escape/escape.a
LIBC_ESCAPE_A_FILES := $(wildcard libc/escape/*)
LIBC_ESCAPE_A_HDRS = $(filter %.h,$(LIBC_ESCAPE_A_FILES))
LIBC_ESCAPE_A_SRCS_S = $(filter %.S,$(LIBC_ESCAPE_A_FILES))
LIBC_ESCAPE_A_SRCS_C = $(filter %.c,$(LIBC_ESCAPE_A_FILES))
LIBC_ESCAPE_A_SRCS = \
$(LIBC_ESCAPE_A_SRCS_S) \
$(LIBC_ESCAPE_A_SRCS_C)
LIBC_ESCAPE_A_OBJS = \
$(LIBC_ESCAPE_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_ESCAPE_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_ESCAPE_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_ESCAPE_A_CHECKS = \
$(LIBC_ESCAPE_A).pkg \
$(LIBC_ESCAPE_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_ESCAPE_A_DIRECTDEPS = \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV
LIBC_ESCAPE_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_ESCAPE_A_DIRECTDEPS),$($(x))))
$(LIBC_ESCAPE_A): \
libc/escape/ \
$(LIBC_ESCAPE_A).pkg \
$(LIBC_ESCAPE_A_OBJS)
$(LIBC_ESCAPE_A).pkg: \
$(LIBC_ESCAPE_A_OBJS) \
$(foreach x,$(LIBC_ESCAPE_A_DIRECTDEPS),$($(x)_A).pkg)
LIBC_ESCAPE_LIBS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)))
LIBC_ESCAPE_SRCS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_SRCS))
LIBC_ESCAPE_HDRS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_HDRS))
LIBC_ESCAPE_BINS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_BINS))
LIBC_ESCAPE_CHECKS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_CHECKS))
LIBC_ESCAPE_OBJS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_OBJS))
LIBC_ESCAPE_TESTS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_TESTS))
$(LIBC_ESCAPE_OBJS): $(BUILD_FILES) libc/escape/escape.mk
.PHONY: o/$(MODE)/libc/escape
o/$(MODE)/libc/escape: $(LIBC_ESCAPE_CHECKS)

68
libc/escape/escapec.c Normal file
View File

@@ -0,0 +1,68 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/escape/escape.h"
#include "libc/limits.h"
#include "libc/sysv/errfuns.h"
/**
* Escapes memory for inclusion in C string literals (or Python, etc.)
*
* The outer quotation marks are *not* added.
*
* @param buf is the output area, which can't overlap and, no matter
* what, a NUL-terminator will always be placed in the buffer at
* an appropriate place, provided buf!=NULL && size!=0
* @param size is the byte-length of the output area
* @param s is the data, which may have NUL characters
* @param l is the byte-length of s or -1 if s is NUL-terminated
* @return number of characters written, excluding NUL terminator; or,
* if the output buffer wasn't passed, or was too short, then the
* number of characters that *would* have been written is returned;
* since that's how the snprintf() API works; or -1 on overflow
* @see xaescapec() for an easier api
*/
int escapec(char *buf, unsigned size, const char *s, unsigned l) {
if (l >= INT_MAX) return eoverflow();
unsigned i, j = 0;
for (i = 0; i < l; ++i) {
unsigned t = cescapec(s[i]);
if (t) {
while (t) {
if (j < size) {
buf[j] = (unsigned char)t;
t >>= 8;
}
j++;
}
} else {
if (l == -1) {
break;
}
}
}
if (buf && size) {
if (j < size) {
buf[j] = '\0';
} else {
buf[size - 1] = '\0';
}
}
return j;
}

123
libc/escape/escapedos.c Normal file
View File

@@ -0,0 +1,123 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/escape/escape.h"
#include "libc/str/str.h"
asm(".ident\t\"\\n\\n\
NSSM (Public Domain)\\n\
Credit: Iain Patterson\n\
http://iain.cx/\"");
static textwindows bool shouldescapedos(const char16_t c) {
if (c == u'"') return true;
if (c == u'&') return true;
if (c == u'%') return true;
if (c == u'^') return true;
if (c == u'<') return true;
if (c == u'>') return true;
if (c == u'|') return true;
return false;
}
static textwindows bool shouldquotedos(const char16_t c) {
if (c == u' ') return true;
if (c == u'\t') return true;
if (c == u'\n') return true;
if (c == u'\v') return true;
if (c == u'"') return true;
if (c == u'*') return true;
return shouldescapedos(c);
}
/**
* Escapes command so DOS can run it.
*/
textwindows bool escapedos(char16_t *buffer, unsigned buflen,
const char16_t *unquoted, unsigned len) {
unsigned i, j, n;
if (len > buflen - 1) return false;
bool escape = false;
bool quotes = false;
for (i = 0; i < len; i++) {
if (shouldescapedos(unquoted[i])) {
escape = quotes = true;
break;
}
if (shouldquotedos(unquoted[i])) quotes = true;
}
if (!quotes) {
memmove(buffer, unquoted, (len + 1) * sizeof(char16_t));
return true;
}
/* "" */
unsigned quoted_len = 2;
if (escape) quoted_len += 2;
for (i = 0;; i++) {
n = 0;
while (i != len && unquoted[i] == u'\\') {
i++;
n++;
}
if (i == len) {
quoted_len += n * 2;
break;
} else if (unquoted[i] == u'"')
quoted_len += n * 2 + 2;
else
quoted_len += n + 1;
if (shouldescapedos(unquoted[i])) quoted_len += n;
}
if (quoted_len > buflen - 1) return false;
char16_t *s = buffer;
if (escape) *s++ = u'^';
*s++ = u'"';
for (i = 0;; i++) {
n = 0;
while (i != len && unquoted[i] == u'\\') {
i++;
n++;
}
if (i == len) {
for (j = 0; j < n * 2; j++) {
if (escape) *s++ = u'^';
*s++ = u'\\';
}
break;
} else if (unquoted[i] == u'"') {
for (j = 0; j < n * 2 + 1; j++) {
if (escape) *s++ = u'^';
*s++ = u'\\';
}
if (escape && shouldescapedos(unquoted[i])) *s++ = u'^';
*s++ = unquoted[i];
} else {
for (j = 0; j < n; j++) {
if (escape) *s++ = u'^';
*s++ = u'\\';
}
if (escape && shouldescapedos(unquoted[i])) *s++ = u'^';
*s++ = unquoted[i];
}
}
if (escape) *s++ = u'^';
*s++ = u'"';
*s++ = u'\0';
return true;
}

73
libc/escape/escapesh.c Normal file
View File

@@ -0,0 +1,73 @@
/*-*- 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 │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/dce.h"
#include "libc/escape/escape.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h"
#define SHQUOTE_PUTCHAR(c) \
do { \
if (buf != NULL && j < size - 1) { \
buf[j] = (c); \
} \
j++; \
} while (0)
/**
* Quotes memory for inclusion in single-quoted SystemV string literals.
*
* The outer quotation marks are *not* added.
*
* @param buf is the output area, which can't overlap and, no matter
* what, a NUL-terminator will always be placed in the buffer at
* an appropriate place, provided buf!=NULL && size!=0
* @param size is the byte-length of the output area
* @param s is the data, which may have NUL characters
* @param l is the byte-length of s
* @return number of characters written, excluding NUL terminator; or,
* if the output buffer wasn't passed, or was too short, then the
* number of characters that *would* have been written is returned;
* since that's how the snprintf() API works; and never < 0
* @see xaescapesh() for an easier api
*/
int escapesh(char *buf, unsigned size, const char *s, unsigned l) {
assert(size <= INT_MAX && l <= INT_MAX);
if (!IsTrustworthy() && l >= INT_MAX) abort();
unsigned j = 0;
for (unsigned i = 0; i < l; ++i) {
if (s[i] != '\'') {
SHQUOTE_PUTCHAR(s[i]);
} else {
const char *const s2 = "'\"'\"'";
unsigned l2 = 5;
for (unsigned k = 0; k < l2; ++k) {
SHQUOTE_PUTCHAR(s2[k]);
}
}
}
if (buf && size) {
buf[min(j, size - 1)] = '\0';
}
return j;
}