*: switch everything to govis
Now that we have govis, move everything to using govis.{Vis,Unvis} and then remove the cvis build tags (because that code no longer exists). Signed-off-by: Aleksa Sarai <asarai@suse.de>
This commit is contained in:
parent
91d7ec8c89
commit
c5ec1c9f3a
21 changed files with 26 additions and 1252 deletions
4
Makefile
4
Makefile
|
@ -4,10 +4,10 @@ BUILDPATH := github.com/vbatts/go-mtree/cmd/gomtree
|
||||||
CWD := $(shell pwd)
|
CWD := $(shell pwd)
|
||||||
SOURCE_FILES := $(shell find . -type f -name "*.go")
|
SOURCE_FILES := $(shell find . -type f -name "*.go")
|
||||||
CLEAN_FILES := *~
|
CLEAN_FILES := *~
|
||||||
TAGS := cvis
|
TAGS :=
|
||||||
ARCHES := linux,386 linux,amd64 linux,arm linux,arm64 openbsd,amd64 windows,amd64 darwin,amd64
|
ARCHES := linux,386 linux,amd64 linux,arm linux,arm64 openbsd,amd64 windows,amd64 darwin,amd64
|
||||||
|
|
||||||
default: build validation
|
default: build validation
|
||||||
|
|
||||||
.PHONY: validation
|
.PHONY: validation
|
||||||
validation: .test .lint .vet .cli.test
|
validation: .test .lint .vet .cli.test
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
// +build cgo,!govis
|
|
||||||
|
|
||||||
package cvis
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
// The resulting string of Vis output could potentially be four times longer than
|
|
||||||
// the original. Vis must handle this possibility.
|
|
||||||
func TestVisLength(t *testing.T) {
|
|
||||||
testString := "All work and no play makes Jack a dull boy\n"
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
Vis(testString, DefaultVisFlags)
|
|
||||||
testString = testString + testString
|
|
||||||
}
|
|
||||||
}
|
|
293
cvis/unvis.c
293
cvis/unvis.c
|
@ -1,293 +0,0 @@
|
||||||
/*-
|
|
||||||
* Copyright (c) 1989, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 4. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(LIBC_SCCS) && !defined(lint)
|
|
||||||
static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93";
|
|
||||||
#endif /* LIBC_SCCS and not lint */
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include "vis.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* decode driven by state machine
|
|
||||||
*/
|
|
||||||
#define S_GROUND 0 /* haven't seen escape char */
|
|
||||||
#define S_START 1 /* start decoding special sequence */
|
|
||||||
#define S_META 2 /* metachar started (M) */
|
|
||||||
#define S_META1 3 /* metachar more, regular char (-) */
|
|
||||||
#define S_CTRL 4 /* control char started (^) */
|
|
||||||
#define S_OCTAL2 5 /* octal digit 2 */
|
|
||||||
#define S_OCTAL3 6 /* octal digit 3 */
|
|
||||||
#define S_HEX2 7 /* hex digit 2 */
|
|
||||||
|
|
||||||
#define S_HTTP 0x080 /* %HEXHEX escape */
|
|
||||||
|
|
||||||
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
|
|
||||||
#define ishex(c) ((((u_char)(c)) >= '0' && ((u_char)(c)) <= '9') || (((u_char)(c)) >= 'a' && ((u_char)(c)) <= 'f'))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* unvis - decode characters previously encoded by vis
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
unvis(char *cp, int c, int *astate, int flag)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (flag & UNVIS_END) {
|
|
||||||
if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
}
|
|
||||||
return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (*astate & ~S_HTTP) {
|
|
||||||
|
|
||||||
case S_GROUND:
|
|
||||||
*cp = 0;
|
|
||||||
if (c == '\\') {
|
|
||||||
*astate = S_START;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
if (flag & VIS_HTTPSTYLE && c == '%') {
|
|
||||||
*astate = S_START | S_HTTP;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
*cp = c;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
|
|
||||||
case S_START:
|
|
||||||
if (*astate & S_HTTP) {
|
|
||||||
if (ishex(tolower(c))) {
|
|
||||||
*cp = isdigit(c) ? (c - '0') : (tolower(c) - 'a');
|
|
||||||
*astate = S_HEX2;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch(c) {
|
|
||||||
case '\\':
|
|
||||||
*cp = c;
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case '0': case '1': case '2': case '3':
|
|
||||||
case '4': case '5': case '6': case '7':
|
|
||||||
*cp = (c - '0');
|
|
||||||
*astate = S_OCTAL2;
|
|
||||||
return (0);
|
|
||||||
case 'M':
|
|
||||||
*cp = 0200;
|
|
||||||
*astate = S_META;
|
|
||||||
return (0);
|
|
||||||
case '^':
|
|
||||||
*astate = S_CTRL;
|
|
||||||
return (0);
|
|
||||||
case 'n':
|
|
||||||
*cp = '\n';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 'r':
|
|
||||||
*cp = '\r';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 'b':
|
|
||||||
*cp = '\b';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 'a':
|
|
||||||
*cp = '\007';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 'v':
|
|
||||||
*cp = '\v';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 't':
|
|
||||||
*cp = '\t';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 'f':
|
|
||||||
*cp = '\f';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 's':
|
|
||||||
*cp = ' ';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case 'E':
|
|
||||||
*cp = '\033';
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
case '\n':
|
|
||||||
/*
|
|
||||||
* hidden newline
|
|
||||||
*/
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_NOCHAR);
|
|
||||||
case '$':
|
|
||||||
/*
|
|
||||||
* hidden marker
|
|
||||||
*/
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_NOCHAR);
|
|
||||||
}
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_SYNBAD);
|
|
||||||
|
|
||||||
case S_META:
|
|
||||||
if (c == '-')
|
|
||||||
*astate = S_META1;
|
|
||||||
else if (c == '^')
|
|
||||||
*astate = S_CTRL;
|
|
||||||
else {
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_SYNBAD);
|
|
||||||
}
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
case S_META1:
|
|
||||||
*astate = S_GROUND;
|
|
||||||
*cp |= c;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
|
|
||||||
case S_CTRL:
|
|
||||||
if (c == '?')
|
|
||||||
*cp |= 0177;
|
|
||||||
else
|
|
||||||
*cp |= c & 037;
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
|
|
||||||
case S_OCTAL2: /* second possible octal digit */
|
|
||||||
if (isoctal(c)) {
|
|
||||||
/*
|
|
||||||
* yes - and maybe a third
|
|
||||||
*/
|
|
||||||
*cp = (*cp << 3) + (c - '0');
|
|
||||||
*astate = S_OCTAL3;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* no - done with current sequence, push back passed char
|
|
||||||
*/
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALIDPUSH);
|
|
||||||
|
|
||||||
case S_OCTAL3: /* third possible octal digit */
|
|
||||||
*astate = S_GROUND;
|
|
||||||
if (isoctal(c)) {
|
|
||||||
*cp = (*cp << 3) + (c - '0');
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* we were done, push back passed char
|
|
||||||
*/
|
|
||||||
return (UNVIS_VALIDPUSH);
|
|
||||||
|
|
||||||
case S_HEX2: /* second mandatory hex digit */
|
|
||||||
if (ishex(tolower(c))) {
|
|
||||||
*cp = (isdigit(c) ? (*cp << 4) + (c - '0') : (*cp << 4) + (tolower(c) - 'a' + 10));
|
|
||||||
}
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_VALID);
|
|
||||||
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
* decoder in unknown state - (probably uninitialized)
|
|
||||||
*/
|
|
||||||
*astate = S_GROUND;
|
|
||||||
return (UNVIS_SYNBAD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* strunvis - decode src into dst
|
|
||||||
*
|
|
||||||
* Number of chars decoded into dst is returned, -1 on error.
|
|
||||||
* Dst is null terminated.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
strunvis(char *dst, const char *src)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
char *start = dst;
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
while ( (c = *src++) ) {
|
|
||||||
again:
|
|
||||||
switch (unvis(dst, c, &state, 0)) {
|
|
||||||
case UNVIS_VALID:
|
|
||||||
dst++;
|
|
||||||
break;
|
|
||||||
case UNVIS_VALIDPUSH:
|
|
||||||
dst++;
|
|
||||||
goto again;
|
|
||||||
case 0:
|
|
||||||
case UNVIS_NOCHAR:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
|
|
||||||
dst++;
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
strunvisx(char *dst, const char *src, int flag)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
char *start = dst;
|
|
||||||
int state = 0;
|
|
||||||
|
|
||||||
while ( (c = *src++) ) {
|
|
||||||
again:
|
|
||||||
switch (unvis(dst, c, &state, flag)) {
|
|
||||||
case UNVIS_VALID:
|
|
||||||
dst++;
|
|
||||||
break;
|
|
||||||
case UNVIS_VALIDPUSH:
|
|
||||||
dst++;
|
|
||||||
goto again;
|
|
||||||
case 0:
|
|
||||||
case UNVIS_NOCHAR:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
|
|
||||||
dst++;
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst - start);
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package cvis
|
|
||||||
|
|
||||||
// #include "vis.h"
|
|
||||||
// #include <stdlib.h>
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Unvis decodes the Vis() string encoding
|
|
||||||
func Unvis(src string) (string, error) {
|
|
||||||
cDst, cSrc := C.CString(string(make([]byte, len(src)+1))), C.CString(src)
|
|
||||||
defer C.free(unsafe.Pointer(cDst))
|
|
||||||
defer C.free(unsafe.Pointer(cSrc))
|
|
||||||
ret := C.strunvis(cDst, cSrc)
|
|
||||||
// TODO(vbatts) this needs to be confirmed against UnvisError
|
|
||||||
if ret == -1 {
|
|
||||||
return "", fmt.Errorf("failed to decode: %q", src)
|
|
||||||
}
|
|
||||||
return C.GoString(cDst), nil
|
|
||||||
}
|
|
202
cvis/vis.c
202
cvis/vis.c
|
@ -1,202 +0,0 @@
|
||||||
/*-
|
|
||||||
* Copyright (c) 1989, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 4. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(LIBC_SCCS) && !defined(lint)
|
|
||||||
static char sccsid[] = "@(#)vis.c 8.1 (Berkeley) 7/19/93";
|
|
||||||
#endif /* LIBC_SCCS and not lint */
|
|
||||||
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "vis.h"
|
|
||||||
|
|
||||||
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
|
|
||||||
|
|
||||||
/*
|
|
||||||
* vis - visually encode characters
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
vis(dst, c, flag, nextc)
|
|
||||||
char *dst;
|
|
||||||
int c, nextc;
|
|
||||||
int flag;
|
|
||||||
{
|
|
||||||
c = (unsigned char)c;
|
|
||||||
|
|
||||||
if (flag & VIS_HTTPSTYLE) {
|
|
||||||
/* Described in RFC 1808 */
|
|
||||||
if (!(isalnum(c) /* alpha-numeric */
|
|
||||||
/* safe */
|
|
||||||
|| c == '$' || c == '-' || c == '_' || c == '.' || c == '+'
|
|
||||||
/* extra */
|
|
||||||
|| c == '!' || c == '*' || c == '\'' || c == '('
|
|
||||||
|| c == ')' || c == ',')) {
|
|
||||||
*dst++ = '%';
|
|
||||||
snprintf(dst, 4, (c < 16 ? "0%X" : "%X"), c);
|
|
||||||
dst += 2;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flag & VIS_GLOB) &&
|
|
||||||
(c == '*' || c == '?' || c == '[' || c == '#'))
|
|
||||||
;
|
|
||||||
else if (isgraph(c) ||
|
|
||||||
((flag & VIS_SP) == 0 && c == ' ') ||
|
|
||||||
((flag & VIS_TAB) == 0 && c == '\t') ||
|
|
||||||
((flag & VIS_NL) == 0 && c == '\n') ||
|
|
||||||
((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
|
|
||||||
*dst++ = c;
|
|
||||||
if (c == '\\' && (flag & VIS_NOSLASH) == 0)
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag & VIS_CSTYLE) {
|
|
||||||
switch(c) {
|
|
||||||
case '\n':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'n';
|
|
||||||
goto done;
|
|
||||||
case '\r':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'r';
|
|
||||||
goto done;
|
|
||||||
case '\b':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'b';
|
|
||||||
goto done;
|
|
||||||
case '\a':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'a';
|
|
||||||
goto done;
|
|
||||||
case '\v':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'v';
|
|
||||||
goto done;
|
|
||||||
case '\t':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 't';
|
|
||||||
goto done;
|
|
||||||
case '\f':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 'f';
|
|
||||||
goto done;
|
|
||||||
case ' ':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = 's';
|
|
||||||
goto done;
|
|
||||||
case '\0':
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = '0';
|
|
||||||
if (isoctal(nextc)) {
|
|
||||||
*dst++ = '0';
|
|
||||||
*dst++ = '0';
|
|
||||||
}
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (((c & 0177) == ' ') || isgraph(c) || (flag & VIS_OCTAL)) {
|
|
||||||
*dst++ = '\\';
|
|
||||||
*dst++ = ((u_char)c >> 6 & 07) + '0';
|
|
||||||
*dst++ = ((u_char)c >> 3 & 07) + '0';
|
|
||||||
*dst++ = ((u_char)c & 07) + '0';
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((flag & VIS_NOSLASH) == 0)
|
|
||||||
*dst++ = '\\';
|
|
||||||
if (c & 0200) {
|
|
||||||
c &= 0177;
|
|
||||||
*dst++ = 'M';
|
|
||||||
}
|
|
||||||
if (iscntrl(c)) {
|
|
||||||
*dst++ = '^';
|
|
||||||
if (c == 0177)
|
|
||||||
*dst++ = '?';
|
|
||||||
else
|
|
||||||
*dst++ = c + '@';
|
|
||||||
} else {
|
|
||||||
*dst++ = '-';
|
|
||||||
*dst++ = c;
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* strvis, strvisx - visually encode characters from src into dst
|
|
||||||
*
|
|
||||||
* Dst must be 4 times the size of src to account for possible
|
|
||||||
* expansion. The length of dst, not including the trailing NUL,
|
|
||||||
* is returned.
|
|
||||||
*
|
|
||||||
* Strvisx encodes exactly len bytes from src into dst.
|
|
||||||
* This is useful for encoding a block of data.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
strvis(dst, src, flag)
|
|
||||||
char *dst;
|
|
||||||
const char *src;
|
|
||||||
int flag;
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
char *start;
|
|
||||||
|
|
||||||
for (start = dst; (c = *src); )
|
|
||||||
dst = vis(dst, c, flag, *++src);
|
|
||||||
*dst = '\0';
|
|
||||||
return (dst - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
strvisx(dst, src, len, flag)
|
|
||||||
char *dst;
|
|
||||||
const char *src;
|
|
||||||
size_t len;
|
|
||||||
int flag;
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
char *start;
|
|
||||||
|
|
||||||
for (start = dst; len > 1; len--) {
|
|
||||||
c = *src;
|
|
||||||
dst = vis(dst, c, flag, *++src);
|
|
||||||
}
|
|
||||||
if (len)
|
|
||||||
dst = vis(dst, *src, flag, '\0');
|
|
||||||
*dst = '\0';
|
|
||||||
|
|
||||||
return (dst - start);
|
|
||||||
}
|
|
28
cvis/vis.go
28
cvis/vis.go
|
@ -1,28 +0,0 @@
|
||||||
package cvis
|
|
||||||
|
|
||||||
// #include "vis.h"
|
|
||||||
// #include <stdlib.h>
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Vis is a wrapper around the C implementation
|
|
||||||
func Vis(src string, flags int) (string, error) {
|
|
||||||
// dst needs to be 4 times the length of str, must check appropriate size
|
|
||||||
if uint32(len(src)*4+1) >= math.MaxUint32/4 {
|
|
||||||
return "", fmt.Errorf("failed to encode: %q", src)
|
|
||||||
}
|
|
||||||
dst := string(make([]byte, 4*len(src)+1))
|
|
||||||
cDst, cSrc := C.CString(dst), C.CString(src)
|
|
||||||
defer C.free(unsafe.Pointer(cDst))
|
|
||||||
defer C.free(unsafe.Pointer(cSrc))
|
|
||||||
C.strvis(cDst, cSrc, C.int(flags))
|
|
||||||
|
|
||||||
return C.GoString(cDst), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultVisFlags are the common flags used in mtree string encoding
|
|
||||||
var DefaultVisFlags = C.VIS_WHITE | C.VIS_OCTAL | C.VIS_GLOB
|
|
90
cvis/vis.h
90
cvis/vis.h
|
@ -1,90 +0,0 @@
|
||||||
/*-
|
|
||||||
* Copyright (c) 1990, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. All advertising materials mentioning features or use of this software
|
|
||||||
* must display the following acknowledgement:
|
|
||||||
* This product includes software developed by the University of
|
|
||||||
* California, Berkeley and its contributors.
|
|
||||||
* 4. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @(#)vis.h 8.1 (Berkeley) 6/2/93
|
|
||||||
* $FreeBSD$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _VIS_H_
|
|
||||||
#define _VIS_H_
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* to select alternate encoding format
|
|
||||||
*/
|
|
||||||
#define VIS_OCTAL 0x01 /* use octal \ddd format */
|
|
||||||
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* to alter set of characters encoded (default is to encode all
|
|
||||||
* non-graphic except space, tab, and newline).
|
|
||||||
*/
|
|
||||||
#define VIS_SP 0x04 /* also encode space */
|
|
||||||
#define VIS_TAB 0x08 /* also encode tab */
|
|
||||||
#define VIS_NL 0x10 /* also encode newline */
|
|
||||||
#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
|
|
||||||
#define VIS_SAFE 0x20 /* only encode "unsafe" characters */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* other
|
|
||||||
*/
|
|
||||||
#define VIS_NOSLASH 0x40 /* inhibit printing '\' */
|
|
||||||
#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */
|
|
||||||
#define VIS_GLOB 0x100 /* encode glob(3) magics */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* unvis return codes
|
|
||||||
*/
|
|
||||||
#define UNVIS_VALID 1 /* character valid */
|
|
||||||
#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */
|
|
||||||
#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */
|
|
||||||
#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */
|
|
||||||
#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* unvis flags
|
|
||||||
*/
|
|
||||||
#define UNVIS_END 1 /* no more characters */
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
|
|
||||||
__BEGIN_DECLS
|
|
||||||
char *vis(char *, int, int, int);
|
|
||||||
int strvis(char *, const char *, int);
|
|
||||||
int strvisx(char *, const char *, size_t, int);
|
|
||||||
int strunvis(char *, const char *);
|
|
||||||
int strunvisx(char *, const char *, int);
|
|
||||||
int unvis(char *, int, int *, int);
|
|
||||||
__END_DECLS
|
|
||||||
|
|
||||||
#endif /* !_VIS_H_ */
|
|
6
entry.go
6
entry.go
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vbatts/go-mtree/pkg/govis"
|
||||||
)
|
)
|
||||||
|
|
||||||
type byPos []Entry
|
type byPos []Entry
|
||||||
|
@ -47,7 +49,7 @@ func (e Entry) Descend(filename string) *Entry {
|
||||||
func (e Entry) Find(filepath string) *Entry {
|
func (e Entry) Find(filepath string) *Entry {
|
||||||
resultnode := &e
|
resultnode := &e
|
||||||
for _, path := range strings.Split(filepath, "/") {
|
for _, path := range strings.Split(filepath, "/") {
|
||||||
encoded, err := Vis(path, DefaultVisFlags)
|
encoded, err := govis.Vis(path, DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -68,7 +70,7 @@ func (e Entry) Ascend() *Entry {
|
||||||
// Path provides the full path of the file, despite RelativeType or FullType. It
|
// Path provides the full path of the file, despite RelativeType or FullType. It
|
||||||
// will be in Unvis'd form.
|
// will be in Unvis'd form.
|
||||||
func (e Entry) Path() (string, error) {
|
func (e Entry) Path() (string, error) {
|
||||||
decodedName, err := Unvis(e.Name)
|
decodedName, err := govis.Unvis(e.Name, DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/vbatts/go-mtree/pkg/govis"
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -119,7 +120,7 @@ var (
|
||||||
linkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
|
linkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (KeyVal, error) {
|
||||||
if sys, ok := info.Sys().(*tar.Header); ok {
|
if sys, ok := info.Sys().(*tar.Header); ok {
|
||||||
if sys.Linkname != "" {
|
if sys.Linkname != "" {
|
||||||
linkname, err := Vis(sys.Linkname, DefaultVisFlags)
|
linkname, err := govis.Vis(sys.Linkname, DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyKV, err
|
return emptyKV, err
|
||||||
}
|
}
|
||||||
|
@ -133,7 +134,7 @@ var (
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyKV, err
|
return emptyKV, err
|
||||||
}
|
}
|
||||||
linkname, err := Vis(str, DefaultVisFlags)
|
linkname, err := govis.Vis(str, DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyKV, err
|
return emptyKV, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,14 @@ package mtree
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vbatts/go-mtree/pkg/govis"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DefaultVisFlags is the set of Vis flags used when encoding filenames and
|
||||||
|
// other similar entries.
|
||||||
|
const DefaultVisFlags govis.VisFlag = govis.VisWhite | govis.VisOctal | govis.VisGlob
|
||||||
|
|
||||||
// Keyword is the string name of a keyword, with some convenience functions for
|
// Keyword is the string name of a keyword, with some convenience functions for
|
||||||
// determining whether it is a default or bsd standard keyword.
|
// determining whether it is a default or bsd standard keyword.
|
||||||
type Keyword string
|
type Keyword string
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/vbatts/go-mtree/pkg/govis"
|
||||||
"github.com/vbatts/go-mtree/xattr"
|
"github.com/vbatts/go-mtree/xattr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ var (
|
||||||
}
|
}
|
||||||
klist := []KeyVal{}
|
klist := []KeyVal{}
|
||||||
for k, v := range hdr.Xattrs {
|
for k, v := range hdr.Xattrs {
|
||||||
encKey, err := Vis(k, DefaultVisFlags)
|
encKey, err := govis.Vis(k, DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyKV, err
|
return emptyKV, err
|
||||||
}
|
}
|
||||||
|
@ -84,7 +85,7 @@ var (
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyKV, err
|
return emptyKV, err
|
||||||
}
|
}
|
||||||
encKey, err := Vis(xlist[i], DefaultVisFlags)
|
encKey, err := govis.Vis(xlist[i], DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emptyKV, err
|
return emptyKV, err
|
||||||
}
|
}
|
||||||
|
|
8
tar.go
8
tar.go
|
@ -9,6 +9,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vbatts/go-mtree/pkg/govis"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Streamer creates a file hierarchy out of a tar stream
|
// Streamer creates a file hierarchy out of a tar stream
|
||||||
|
@ -128,7 +130,7 @@ hdrloop:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Alright, it's either file or directory
|
// Alright, it's either file or directory
|
||||||
encodedName, err := Vis(filepath.Base(hdr.Name), DefaultVisFlags)
|
encodedName, err := govis.Vis(filepath.Base(hdr.Name), DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tmpFile.Close()
|
tmpFile.Close()
|
||||||
os.Remove(tmpFile.Name())
|
os.Remove(tmpFile.Name())
|
||||||
|
@ -148,7 +150,7 @@ hdrloop:
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
linkname, err := Unvis(KeyVal(kv).Value())
|
linkname, err := govis.Unvis(KeyVal(kv).Value(), DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
break
|
break
|
||||||
|
@ -248,7 +250,7 @@ func populateTree(root, e *Entry, hdr *tar.Header) error {
|
||||||
dirNames := strings.Split(wd, "/")
|
dirNames := strings.Split(wd, "/")
|
||||||
parent := root
|
parent := root
|
||||||
for _, name := range dirNames[:] {
|
for _, name := range dirNames[:] {
|
||||||
encoded, err := Vis(name, DefaultVisFlags)
|
encoded, err := govis.Vis(name, DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
7
unvis.go
7
unvis.go
|
@ -1,7 +0,0 @@
|
||||||
package mtree
|
|
||||||
|
|
||||||
// Unvis is a wrapper for the C implementation of unvis, which decodes a string
|
|
||||||
// that potentially has characters that are encoded with Vis
|
|
||||||
func Unvis(src string) (string, error) {
|
|
||||||
return unvis(src)
|
|
||||||
}
|
|
11
unvis_c.go
11
unvis_c.go
|
@ -1,11 +0,0 @@
|
||||||
// +build cgo,cvis
|
|
||||||
|
|
||||||
package mtree
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/vbatts/go-mtree/cvis"
|
|
||||||
)
|
|
||||||
|
|
||||||
func unvis(src string) (string, error) {
|
|
||||||
return cvis.Unvis(src)
|
|
||||||
}
|
|
233
unvis_go.go
233
unvis_go.go
|
@ -1,233 +0,0 @@
|
||||||
// +build !cvis
|
|
||||||
|
|
||||||
package mtree
|
|
||||||
|
|
||||||
import "unicode"
|
|
||||||
|
|
||||||
func unvis(src string) (string, error) {
|
|
||||||
dst := []rune{}
|
|
||||||
var s state
|
|
||||||
for i, r := range src {
|
|
||||||
again:
|
|
||||||
err := unvisRune(&dst, r, &s, 0)
|
|
||||||
switch err {
|
|
||||||
case unvisValid:
|
|
||||||
break
|
|
||||||
case unvisValidPush:
|
|
||||||
goto again
|
|
||||||
case unvisNone:
|
|
||||||
fallthrough
|
|
||||||
case unvisNochar:
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if i == len(src)-1 {
|
|
||||||
unvisRune(&dst, r, &s, unvisEnd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str := ""
|
|
||||||
for _, ch := range dst {
|
|
||||||
str += string(ch)
|
|
||||||
}
|
|
||||||
return str, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unvisRune(dst *[]rune, r rune, s *state, flags VisFlag) error {
|
|
||||||
if (flags & unvisEnd) != 0 {
|
|
||||||
if *s == stateOctal2 || *s == stateOctal3 {
|
|
||||||
*s = stateGround
|
|
||||||
return unvisValid
|
|
||||||
}
|
|
||||||
if *s == stateGround {
|
|
||||||
return unvisNochar
|
|
||||||
}
|
|
||||||
return unvisErrSynbad
|
|
||||||
}
|
|
||||||
|
|
||||||
switch *s & ^stateHTTP {
|
|
||||||
case stateGround:
|
|
||||||
if r == '\\' {
|
|
||||||
*s = stateStart
|
|
||||||
return unvisNone
|
|
||||||
}
|
|
||||||
if flags&VisHttpstyle != 0 && r == '%' {
|
|
||||||
*s = stateStart | stateHTTP
|
|
||||||
return unvisNone
|
|
||||||
}
|
|
||||||
*dst = append(*dst, r)
|
|
||||||
return unvisValid
|
|
||||||
case stateStart:
|
|
||||||
if *s&stateHTTP != 0 && ishex(unicode.ToLower(r)) {
|
|
||||||
if unicode.IsNumber(r) {
|
|
||||||
*dst = append(*dst, r-'0')
|
|
||||||
} else {
|
|
||||||
*dst = append(*dst, unicode.ToLower(r)-'a')
|
|
||||||
}
|
|
||||||
*s = stateHex2
|
|
||||||
return unvisNone
|
|
||||||
}
|
|
||||||
switch r {
|
|
||||||
case '\\':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, r)
|
|
||||||
return unvisValid
|
|
||||||
case '0':
|
|
||||||
fallthrough
|
|
||||||
case '1':
|
|
||||||
fallthrough
|
|
||||||
case '2':
|
|
||||||
fallthrough
|
|
||||||
case '3':
|
|
||||||
fallthrough
|
|
||||||
case '4':
|
|
||||||
fallthrough
|
|
||||||
case '5':
|
|
||||||
fallthrough
|
|
||||||
case '6':
|
|
||||||
fallthrough
|
|
||||||
case '7':
|
|
||||||
*s = stateOctal2
|
|
||||||
*dst = append(*dst, r-'0')
|
|
||||||
return unvisNone
|
|
||||||
case 'M':
|
|
||||||
*s = stateMeta
|
|
||||||
*dst = append(*dst, rune(0200))
|
|
||||||
return unvisNone
|
|
||||||
case '^':
|
|
||||||
*s = stateCtrl
|
|
||||||
return unvisNone
|
|
||||||
case 'n':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\n')
|
|
||||||
return unvisValid
|
|
||||||
case 'r':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\r')
|
|
||||||
return unvisValid
|
|
||||||
case 'b':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\b')
|
|
||||||
return unvisValid
|
|
||||||
case 'a':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\007')
|
|
||||||
return unvisValid
|
|
||||||
case 'v':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\v')
|
|
||||||
return unvisValid
|
|
||||||
case 't':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\t')
|
|
||||||
return unvisValid
|
|
||||||
case 'f':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\f')
|
|
||||||
return unvisValid
|
|
||||||
case 's':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, ' ')
|
|
||||||
return unvisValid
|
|
||||||
case 'E':
|
|
||||||
*s = stateGround
|
|
||||||
*dst = append(*dst, '\033')
|
|
||||||
return unvisValid
|
|
||||||
case '\n':
|
|
||||||
// hidden newline
|
|
||||||
*s = stateGround
|
|
||||||
return unvisNochar
|
|
||||||
case '$':
|
|
||||||
// hidden marker
|
|
||||||
*s = stateGround
|
|
||||||
return unvisNochar
|
|
||||||
}
|
|
||||||
*s = stateGround
|
|
||||||
return unvisErrSynbad
|
|
||||||
case stateMeta:
|
|
||||||
if r == '-' {
|
|
||||||
*s = stateMeta1
|
|
||||||
} else if r == '^' {
|
|
||||||
*s = stateCtrl
|
|
||||||
} else {
|
|
||||||
*s = stateGround
|
|
||||||
return unvisErrSynbad
|
|
||||||
}
|
|
||||||
return unvisNone
|
|
||||||
case stateMeta1:
|
|
||||||
*s = stateGround
|
|
||||||
dp := *dst
|
|
||||||
dp[len(dp)-1] |= r
|
|
||||||
return unvisValid
|
|
||||||
case stateCtrl:
|
|
||||||
dp := *dst
|
|
||||||
if r == '?' {
|
|
||||||
dp[len(dp)-1] |= rune(0177)
|
|
||||||
} else {
|
|
||||||
dp[len(dp)-1] |= r & 037
|
|
||||||
}
|
|
||||||
*s = stateGround
|
|
||||||
return unvisValid
|
|
||||||
case stateOctal2:
|
|
||||||
if isoctal(r) {
|
|
||||||
dp := *dst
|
|
||||||
if len(dp) > 0 {
|
|
||||||
last := dp[len(dp)-1]
|
|
||||||
dp[len(dp)-1] = (last << 3) + (r - '0')
|
|
||||||
} else {
|
|
||||||
dp = append(dp, (0<<3)+(r-'0'))
|
|
||||||
}
|
|
||||||
*s = stateOctal3
|
|
||||||
return unvisNone
|
|
||||||
}
|
|
||||||
*s = stateGround
|
|
||||||
return unvisValidPush
|
|
||||||
case stateOctal3:
|
|
||||||
*s = stateGround
|
|
||||||
if isoctal(r) {
|
|
||||||
dp := *dst
|
|
||||||
if len(dp) > 0 {
|
|
||||||
last := dp[len(dp)-1]
|
|
||||||
dp[len(dp)-1] = (last << 3) + (r - '0')
|
|
||||||
} else {
|
|
||||||
dp = append(dp, (0<<3)+(r-'0'))
|
|
||||||
}
|
|
||||||
return unvisValid
|
|
||||||
}
|
|
||||||
return unvisValidPush
|
|
||||||
case stateHex2:
|
|
||||||
if ishex(unicode.ToLower(r)) {
|
|
||||||
last := rune(0)
|
|
||||||
dp := *dst
|
|
||||||
if len(dp) > 0 {
|
|
||||||
last = dp[len(dp)-1]
|
|
||||||
}
|
|
||||||
if unicode.IsNumber(r) {
|
|
||||||
dp = append(dp, (last<<4)+(r-'0'))
|
|
||||||
} else {
|
|
||||||
dp = append(dp, (last<<4)+(unicode.ToLower(r)-'a'+10))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*s = stateGround
|
|
||||||
return unvisValid
|
|
||||||
}
|
|
||||||
|
|
||||||
*s = stateGround
|
|
||||||
return unvisErrSynbad
|
|
||||||
}
|
|
||||||
|
|
||||||
type state int
|
|
||||||
|
|
||||||
const (
|
|
||||||
stateGround state = iota /* haven't seen escape char */
|
|
||||||
stateStart /* start decoding special sequence */
|
|
||||||
stateMeta /* metachar started (M) */
|
|
||||||
stateMeta1 /* metachar more, regular char (-) */
|
|
||||||
stateCtrl /* control char started (^) */
|
|
||||||
stateOctal2 /* octal digit 2 */
|
|
||||||
stateOctal3 /* octal digit 3 */
|
|
||||||
stateHex2 /* hex digit 2 */
|
|
||||||
|
|
||||||
stateHTTP state = 0x080 /* %HEXHEX escape */
|
|
||||||
)
|
|
|
@ -1,93 +0,0 @@
|
||||||
package mtree
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
type runeCheck func(rune) bool
|
|
||||||
|
|
||||||
func TestUnvisHelpers(t *testing.T) {
|
|
||||||
testset := []struct {
|
|
||||||
R rune
|
|
||||||
Check runeCheck
|
|
||||||
Expect bool
|
|
||||||
}{
|
|
||||||
{'a', ishex, true},
|
|
||||||
{'A', ishex, true},
|
|
||||||
{'z', ishex, false},
|
|
||||||
{'Z', ishex, false},
|
|
||||||
{'G', ishex, false},
|
|
||||||
{'1', ishex, true},
|
|
||||||
{'0', ishex, true},
|
|
||||||
{'9', ishex, true},
|
|
||||||
{'0', isoctal, true},
|
|
||||||
{'3', isoctal, true},
|
|
||||||
{'7', isoctal, true},
|
|
||||||
{'9', isoctal, false},
|
|
||||||
{'a', isoctal, false},
|
|
||||||
{'z', isoctal, false},
|
|
||||||
{'3', isalnum, true},
|
|
||||||
{'a', isalnum, true},
|
|
||||||
{';', isalnum, false},
|
|
||||||
{'!', isalnum, false},
|
|
||||||
{' ', isalnum, false},
|
|
||||||
{'3', isgraph, true},
|
|
||||||
{'a', isgraph, true},
|
|
||||||
{';', isgraph, true},
|
|
||||||
{'!', isgraph, true},
|
|
||||||
{' ', isgraph, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, ts := range testset {
|
|
||||||
got := ts.Check(ts.R)
|
|
||||||
if got != ts.Expect {
|
|
||||||
t.Errorf("%d: %q expected: %t; got %t", i, string(ts.R), ts.Expect, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnvisUnicode(t *testing.T) {
|
|
||||||
// Ensure that unicode strings are not messed up by Unvis.
|
|
||||||
for _, test := range []string{
|
|
||||||
"",
|
|
||||||
"this.is.a.normal_string",
|
|
||||||
"AC_Raíz_Certicámara_S.A..pem",
|
|
||||||
"NetLock_Arany_=Class_Gold=_Főtanúsítvány.pem",
|
|
||||||
"TÜBİTAK_UEKAE_Kök_Sertifika_Hizmet_Sağlayıcısı_-_Sürüm_3.pem",
|
|
||||||
} {
|
|
||||||
got, err := Unvis(test)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error doing unvis(%q): %s", test, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if got != test {
|
|
||||||
t.Errorf("expected %q to be unchanged, got %q", test, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVisUnvis(t *testing.T) {
|
|
||||||
// Round-trip testing.
|
|
||||||
for _, test := range []string{
|
|
||||||
"",
|
|
||||||
"this.is.a.normal_string",
|
|
||||||
"AC_Raíz_Certicámara_S.A..pem",
|
|
||||||
"NetLock_Arany_=Class_Gold=_Főtanúsítvány.pem",
|
|
||||||
"TÜBİTAK_UEKAE_Kök_Sertifika_Hizmet_Sağlayıcısı_-_Sürüm_3.pem",
|
|
||||||
"hello world [ this string needs=enco ding! ]",
|
|
||||||
"even \n more encoding necessary\a\a ",
|
|
||||||
"\024 <-- some more weird characters --> 你好,世界",
|
|
||||||
} {
|
|
||||||
enc, err := Vis(test, DefaultVisFlags)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error doing vis(%q): %s", test, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
dec, err := Unvis(enc)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error doing unvis(%q): %s", enc, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if dec != test {
|
|
||||||
t.Errorf("roundtrip failed: unvis(vis(%q) = %q) = %q", test, enc, dec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
89
vis.go
89
vis.go
|
@ -1,89 +0,0 @@
|
||||||
package mtree
|
|
||||||
|
|
||||||
import "unicode"
|
|
||||||
|
|
||||||
// Vis is a wrapper of the C implementation of the function vis, which encodes
|
|
||||||
// a character with a particular format/style.
|
|
||||||
// For most use-cases use DefaultVisFlags.
|
|
||||||
func Vis(src string, flags VisFlag) (string, error) {
|
|
||||||
return vis(src, flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultVisFlags are the typical flags used for encoding strings in mtree
|
|
||||||
// manifests.
|
|
||||||
var DefaultVisFlags = VisWhite | VisOctal | VisGlob
|
|
||||||
|
|
||||||
// VisFlag sets the extent of charactures to be encoded
|
|
||||||
type VisFlag int
|
|
||||||
|
|
||||||
// flags for encoding
|
|
||||||
const (
|
|
||||||
// to select alternate encoding format
|
|
||||||
VisOctal VisFlag = 0x01 // use octal \ddd format
|
|
||||||
VisCstyle VisFlag = 0x02 // use \[nrft0..] where appropriate
|
|
||||||
|
|
||||||
// to alter set of characters encoded (default is to encode all non-graphic
|
|
||||||
// except space, tab, and newline).
|
|
||||||
VisSp VisFlag = 0x04 // also encode space
|
|
||||||
VisTab VisFlag = 0x08 // also encode tab
|
|
||||||
VisNl VisFlag = 0x10 // also encode newline
|
|
||||||
VisWhite VisFlag = (VisSp | VisTab | VisNl)
|
|
||||||
VisSafe VisFlag = 0x20 // only encode "unsafe" characters
|
|
||||||
|
|
||||||
// other
|
|
||||||
VisNoSlash VisFlag = 0x40 // inhibit printing '\'
|
|
||||||
VisHttpstyle VisFlag = 0x80 // http-style escape % HEX HEX
|
|
||||||
VisGlob VisFlag = 0x100 // encode glob(3) magics
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
// errors used in the tokenized decoding strings
|
|
||||||
const (
|
|
||||||
// unvis return codes
|
|
||||||
unvisValid unvisErr = 1 // character valid
|
|
||||||
unvisValidPush unvisErr = 2 // character valid, push back passed char
|
|
||||||
unvisNochar unvisErr = 3 // valid sequence, no character produced
|
|
||||||
unvisErrSynbad unvisErr = -1 // unrecognized escape sequence
|
|
||||||
unvisErrUnrecoverable unvisErr = -2 // decoder in unknown state (unrecoverable)
|
|
||||||
unvisNone unvisErr = 0
|
|
||||||
|
|
||||||
// unvisEnd means there are no more characters
|
|
||||||
unvisEnd VisFlag = 1 // no more characters
|
|
||||||
)
|
|
||||||
|
|
||||||
// unvisErr are the return conditions for Unvis
|
|
||||||
type unvisErr int
|
|
||||||
|
|
||||||
func (ue unvisErr) Error() string {
|
|
||||||
switch ue {
|
|
||||||
case unvisValid:
|
|
||||||
return "character valid"
|
|
||||||
case unvisValidPush:
|
|
||||||
return "character valid, push back passed char"
|
|
||||||
case unvisNochar:
|
|
||||||
return "valid sequence, no character produced"
|
|
||||||
case unvisErrSynbad:
|
|
||||||
return "unrecognized escape sequence"
|
|
||||||
case unvisErrUnrecoverable:
|
|
||||||
return "decoder in unknown state (unrecoverable)"
|
|
||||||
}
|
|
||||||
return "Unknown Error"
|
|
||||||
}
|
|
||||||
|
|
||||||
func ishex(r rune) bool {
|
|
||||||
lr := unicode.ToLower(r)
|
|
||||||
return (lr >= '0' && lr <= '9') || (lr >= 'a' && lr <= 'f')
|
|
||||||
}
|
|
||||||
|
|
||||||
func isoctal(r rune) bool {
|
|
||||||
return r <= '7' && r >= '0'
|
|
||||||
}
|
|
||||||
|
|
||||||
// the ctype isgraph is "any printable character except space"
|
|
||||||
func isgraph(r rune) bool {
|
|
||||||
return unicode.IsPrint(r) && !unicode.IsSpace(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isalnum(r rune) bool {
|
|
||||||
return unicode.IsNumber(r) || unicode.IsLetter(r)
|
|
||||||
}
|
|
11
vis_c.go
11
vis_c.go
|
@ -1,11 +0,0 @@
|
||||||
// +build cgo,cvis
|
|
||||||
|
|
||||||
package mtree
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/vbatts/go-mtree/cvis"
|
|
||||||
)
|
|
||||||
|
|
||||||
func vis(src string, flags VisFlag) (string, error) {
|
|
||||||
return cvis.Vis(src, int(flags))
|
|
||||||
}
|
|
107
vis_go.go
107
vis_go.go
|
@ -1,107 +0,0 @@
|
||||||
// +build !cvis
|
|
||||||
|
|
||||||
package mtree
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"unicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
func vis(src string, flags VisFlag) (string, error) {
|
|
||||||
var ret string
|
|
||||||
for _, r := range src {
|
|
||||||
vStr, err := visRune(r, flags)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
ret = ret + vStr
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func visRune(r rune, flags VisFlag) (string, error) {
|
|
||||||
if flags&VisHttpstyle != 0 {
|
|
||||||
// Described in RFC 1808
|
|
||||||
if !isalnum(r) ||
|
|
||||||
/* safe */
|
|
||||||
r == '$' || r == '-' || r == '_' || r == '.' || r == '+' ||
|
|
||||||
/* extra */
|
|
||||||
r == '!' || r == '*' || r == '\'' || r == '(' ||
|
|
||||||
r == ')' || r == ',' {
|
|
||||||
if r < 16 {
|
|
||||||
return fmt.Sprintf("%%0%X", r), nil
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%%%X", r), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags&VisGlob) != 0 && (r == '*' || r == '?' || r == '[' || r == '#') {
|
|
||||||
// ... ?
|
|
||||||
} else if isgraph(r) ||
|
|
||||||
((flags&VisSp) == 0 && r == ' ') ||
|
|
||||||
((flags&VisTab) == 0 && r == '\t') ||
|
|
||||||
((flags&VisNl) == 0 && r == '\n') ||
|
|
||||||
((flags&VisSafe) != 0 && (r == '\b' || r == '\007' || r == '\r')) {
|
|
||||||
if r == '\\' && (flags&VisNoSlash) == 0 {
|
|
||||||
return fmt.Sprintf("%s\\", string(r)), nil
|
|
||||||
}
|
|
||||||
return string(r), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & VisCstyle) != 0 {
|
|
||||||
switch r {
|
|
||||||
case '\n':
|
|
||||||
return "\\n", nil
|
|
||||||
case '\r':
|
|
||||||
return "\\r", nil
|
|
||||||
case '\b':
|
|
||||||
return "\\b", nil
|
|
||||||
case '\a':
|
|
||||||
return "\\a", nil
|
|
||||||
case '\v':
|
|
||||||
return "\\v", nil
|
|
||||||
case '\t':
|
|
||||||
return "\\t", nil
|
|
||||||
case '\f':
|
|
||||||
return "\\f", nil
|
|
||||||
case ' ':
|
|
||||||
return "\\s", nil
|
|
||||||
case rune(0x0):
|
|
||||||
return "\\0", nil
|
|
||||||
/*
|
|
||||||
if isoctal(nextr) {
|
|
||||||
dst = append(dst, '0')
|
|
||||||
dst = append(dst, '0')
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((r & 0177) == ' ') || isgraph(r) || (flags&VisOctal) != 0 {
|
|
||||||
dst := make([]rune, 4)
|
|
||||||
dst[0] = '\\'
|
|
||||||
dst[1] = (r >> 6 & 07) + '0'
|
|
||||||
dst[2] = (r >> 3 & 07) + '0'
|
|
||||||
dst[3] = (r & 07) + '0'
|
|
||||||
return string(dst), nil
|
|
||||||
}
|
|
||||||
var dst []rune
|
|
||||||
if (flags & VisNoSlash) == 0 {
|
|
||||||
dst = append(dst, '\\')
|
|
||||||
}
|
|
||||||
if (r & 0200) != 0 {
|
|
||||||
r &= 0177
|
|
||||||
dst = append(dst, 'M')
|
|
||||||
}
|
|
||||||
if unicode.IsControl(r) {
|
|
||||||
dst = append(dst, '^')
|
|
||||||
if r == 0177 {
|
|
||||||
dst = append(dst, '?')
|
|
||||||
} else {
|
|
||||||
dst = append(dst, r+'@')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dst = append(dst, '-')
|
|
||||||
dst = append(dst, r)
|
|
||||||
}
|
|
||||||
return string(dst), nil
|
|
||||||
}
|
|
39
vis_test.go
39
vis_test.go
|
@ -1,39 +0,0 @@
|
||||||
package mtree
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestVisBasic(t *testing.T) {
|
|
||||||
testset := []struct {
|
|
||||||
Src, Dest string
|
|
||||||
}{
|
|
||||||
{"[", "\\133"},
|
|
||||||
{" ", "\\040"},
|
|
||||||
{" ", "\\011"},
|
|
||||||
{"dir with space", "dir\\040with\\040space"},
|
|
||||||
{"consec spaces", "consec\\040\\040\\040spaces"},
|
|
||||||
{"trailingsymbol[", "trailingsymbol\\133"},
|
|
||||||
{" [ leadingsymbols", "\\040\\133\\040leadingsymbols"},
|
|
||||||
{"no_need_for_encoding", "no_need_for_encoding"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range testset {
|
|
||||||
got, err := Vis(testset[i].Src, DefaultVisFlags)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("working with %q: %s", testset[i].Src, err)
|
|
||||||
}
|
|
||||||
if got != testset[i].Dest {
|
|
||||||
t.Errorf("%q: expected %#v; got %#v", testset[i].Src, testset[i].Dest, got)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
got, err = Unvis(got)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("working with %q: %s: %q", testset[i].Src, err, got)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if got != testset[i].Src {
|
|
||||||
t.Errorf("%q: expected %#v; got %#v", testset[i].Dest, testset[i].Src, got)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
4
walk.go
4
walk.go
|
@ -9,6 +9,8 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/vbatts/go-mtree/pkg/govis"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExcludeFunc is the type of function called on each path walked to determine
|
// ExcludeFunc is the type of function called on each path walked to determine
|
||||||
|
@ -165,7 +167,7 @@ func Walk(root string, excludes []ExcludeFunc, keywords []Keyword, fsEval FsEval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
encodedEntryName, err := Vis(entryPathName, DefaultVisFlags)
|
encodedEntryName, err := govis.Vis(entryPathName, DefaultVisFlags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue