Initial import
This commit is contained in:
47
libc/escape/aescape.c
Normal file
47
libc/escape/aescape.c
Normal 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
28
libc/escape/aescapec.c
Normal 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
28
libc/escape/aescapesh.c
Normal 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
64
libc/escape/cunescape.c
Normal 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
27
libc/escape/escape.h
Normal 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
57
libc/escape/escape.mk
Normal 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
68
libc/escape/escapec.c
Normal 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
123
libc/escape/escapedos.c
Normal 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
73
libc/escape/escapesh.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user