diff --git a/headers/compatibility/bsd/libutil.h b/headers/compatibility/bsd/libutil.h new file mode 100644 index 0000000000..ec18040f4b --- /dev/null +++ b/headers/compatibility/bsd/libutil.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 1996 Peter Wemm . + * All rights reserved. + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * ThinkSec AS and NAI Labs, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, is 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD: src/lib/libutil/libutil.h,v 1.42 2006/02/18 11:25:28 des Exp $ + */ + +#ifndef _LIBUTIL_H_ +#define _LIBUTIL_H_ + +#include + +#define PROPERTY_MAX_NAME 64 +#define PROPERTY_MAX_VALUE 512 + +/* for properties.c */ +typedef struct _property { + struct _property *next; + char *name; + char *value; +} *properties; + +#ifdef _SYS_PARAM_H_ +/* for pidfile.c */ +struct pidfh { + int pf_fd; + char pf_path[MAXPATHLEN + 1]; + __dev_t pf_dev; + ino_t pf_ino; +}; +#endif + +/* Avoid pulling in all the include files for no need */ +struct termios; +struct winsize; +struct utmp; +struct in_addr; + +__BEGIN_DECLS +void clean_environment(const char * const *_white, + const char * const *_more_white); +int extattr_namespace_to_string(int _attrnamespace, char **_string); +int extattr_string_to_namespace(const char *_string, int *_attrnamespace); +void login(struct utmp *_ut); +int login_tty(int _fd); +int logout(const char *_line); +void logwtmp(const char *_line, const char *_name, const char *_host); +void trimdomain(char *_fullhost, int _hostsize); +int openpty(int *_amaster, int *_aslave, char *_name, + struct termios *_termp, struct winsize *_winp); +int forkpty(int *_amaster, char *_name, + struct termios *_termp, struct winsize *_winp); +int humanize_number(char *_buf, size_t _len, int64_t _number, + const char *_suffix, int _scale, int _flags); +const char *uu_lockerr(int _uu_lockresult); +int uu_lock(const char *_ttyname); +int uu_unlock(const char *_ttyname); +int uu_lock_txfr(const char *_ttyname, pid_t _pid); +int _secure_path(const char *_path, uid_t _uid, gid_t _gid); +properties properties_read(int fd); +void properties_free(properties list); +char *property_find(properties list, const char *name); +char *auth_getval(const char *name); +int realhostname(char *host, size_t hsize, const struct in_addr *ip); +struct sockaddr; +int realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, + int addrlen); + +int kld_isloaded(const char *name); +int kld_load(const char *name); + +#ifdef _STDIO_H_ /* avoid adding new includes */ +char *fparseln(FILE *, size_t *, size_t *, const char[3], int); +#endif + +#ifdef _PWD_H_ +int pw_copy(int _ffd, int _tfd, const struct passwd *_pw, struct passwd *_old_pw); +struct passwd *pw_dup(const struct passwd *_pw); +int pw_edit(int _notsetuid); +int pw_equal(const struct passwd *_pw1, const struct passwd *_pw2); +void pw_fini(void); +int pw_init(const char *_dir, const char *_master); +char *pw_make(const struct passwd *_pw); +int pw_mkdb(const char *_user); +int pw_lock(void); +struct passwd *pw_scan(const char *_line, int _flags); +const char *pw_tempname(void); +int pw_tmp(int _mfd); +#endif + +#ifdef _SYS_PARAM_H_ +struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr); +int pidfile_write(struct pidfh *pfh); +int pidfile_close(struct pidfh *pfh); +int pidfile_remove(struct pidfh *pfh); +#endif + +__END_DECLS + +#define UU_LOCK_INUSE (1) +#define UU_LOCK_OK (0) +#define UU_LOCK_OPEN_ERR (-1) +#define UU_LOCK_READ_ERR (-2) +#define UU_LOCK_CREAT_ERR (-3) +#define UU_LOCK_WRITE_ERR (-4) +#define UU_LOCK_LINK_ERR (-5) +#define UU_LOCK_TRY_ERR (-6) +#define UU_LOCK_OWNER_ERR (-7) + +/* return values from realhostname() */ +#define HOSTNAME_FOUND (0) +#define HOSTNAME_INCORRECTNAME (1) +#define HOSTNAME_INVALIDADDR (2) +#define HOSTNAME_INVALIDNAME (3) + +/* fparseln(3) */ +#define FPARSELN_UNESCESC 0x01 +#define FPARSELN_UNESCCONT 0x02 +#define FPARSELN_UNESCCOMM 0x04 +#define FPARSELN_UNESCREST 0x08 +#define FPARSELN_UNESCALL 0x0f + +/* pw_scan() */ +#define PWSCAN_MASTER 0x01 +#define PWSCAN_WARN 0x02 + +/* humanize_number(3) */ +#define HN_DECIMAL 0x01 +#define HN_NOSPACE 0x02 +#define HN_B 0x04 +#define HN_DIVISOR_1000 0x08 + +#define HN_GETSCALE 0x10 +#define HN_AUTOSCALE 0x20 + +#endif /* !_LIBUTIL_H_ */ diff --git a/headers/compatibility/bsd/stdio.h b/headers/compatibility/bsd/stdio.h new file mode 100644 index 0000000000..e6255c6f3e --- /dev/null +++ b/headers/compatibility/bsd/stdio.h @@ -0,0 +1,22 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _BSD_STDIO_H_ +#define _BSD_STDIO_H_ + + +#include_next + + +#ifdef __cplusplus +extern "C" { +#endif + +char *fgetln(FILE *stream, size_t *_length); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSD_STDIO_H_ */ diff --git a/headers/compatibility/bsd/sys/cdefs.h b/headers/compatibility/bsd/sys/cdefs.h index 9809b7eba7..2438fba662 100644 --- a/headers/compatibility/bsd/sys/cdefs.h +++ b/headers/compatibility/bsd/sys/cdefs.h @@ -11,5 +11,6 @@ #define __FBSDID(x) #define __unused +#define protected #endif /* _BSD_SYS_CDEFS_H_ */ diff --git a/headers/compatibility/bsd/sys/time.h b/headers/compatibility/bsd/sys/time.h new file mode 100644 index 0000000000..f4ed507d46 --- /dev/null +++ b/headers/compatibility/bsd/sys/time.h @@ -0,0 +1,67 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +/* + * Copyright (c) 1982, 1986, 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. + */ +#ifndef _BSD_SYS_TIME_H_ +#define _BSD_SYS_TIME_H_ + + +#include_next + + +#define timerclear(tv) \ + ((tv)->tv_sec = (tv)->tv_usec = 0) +#define timerisset(tv) \ + ((tv)->tv_sec || (tv)->tv_usec) +#define timercmp(tv, uv, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#define timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + +#endif /* _BSD_SYS_TIME_H_ */ diff --git a/headers/compatibility/bsd/time.h b/headers/compatibility/bsd/time.h new file mode 100644 index 0000000000..85844f8c8a --- /dev/null +++ b/headers/compatibility/bsd/time.h @@ -0,0 +1,23 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _BSD_TIME_H_ +#define _BSD_TIME_H_ + + +#include_next + + +#ifdef __cplusplus +extern "C" { +#endif + +time_t timelocal(struct tm *tm); +time_t timegm(struct tm *tm); + +#ifdef __cplusplus +} +#endif + +#endif /* _BSD_TIME_H_ */ diff --git a/headers/compatibility/bsd/unistd.h b/headers/compatibility/bsd/unistd.h index 3cbfdc32f8..960d5895f4 100644 --- a/headers/compatibility/bsd/unistd.h +++ b/headers/compatibility/bsd/unistd.h @@ -13,7 +13,8 @@ extern "C" { #endif -int issetugid(void); +char *getpass(const char *prompt); +int issetugid(void); #ifdef __cplusplus } diff --git a/src/libs/bsd/Jamfile b/src/libs/bsd/Jamfile index 2e03a540be..e1147491d9 100644 --- a/src/libs/bsd/Jamfile +++ b/src/libs/bsd/Jamfile @@ -6,8 +6,11 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; SharedLibrary libbsd.so : err.c + fgetln.c + getpass.c issetugid.c progname.c stringlist.c + unvis.c vis.c ; diff --git a/src/libs/bsd/fgetln.c b/src/libs/bsd/fgetln.c new file mode 100644 index 0000000000..0d6dd4b672 --- /dev/null +++ b/src/libs/bsd/fgetln.c @@ -0,0 +1,66 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include +#include + + +#define LINE_LENGTH 4096 + + +char * +fgetln(FILE *stream, size_t *_length) +{ + // TODO: this function is not thread-safe + static size_t sBufferSize; + static char *sBuffer; + + size_t length, left; + char *line; + + if (sBuffer == NULL) { + sBuffer = (char *)malloc(LINE_LENGTH); + if (sBuffer == NULL) + return NULL; + + sBufferSize = LINE_LENGTH; + } + + line = sBuffer; + left = sBufferSize; + + for (;;) { + line = fgets(line, left, stream); + if (line == NULL) { + free(sBuffer); + sBuffer = NULL; + return NULL; + } + + length = strlen(line); + if (line[length - 1] != '\n' && length == sBufferSize - 1) { + // more data is following, enlarge buffer + char *newBuffer = realloc(sBuffer, sBufferSize + LINE_LENGTH); + if (newBuffer == NULL) { + free(sBuffer); + sBuffer = NULL; + return NULL; + } + + sBuffer = newBuffer; + sBufferSize += LINE_LENGTH; + line = sBuffer + length; + left += 1; + } else + break; + } + + return sBuffer; +} + diff --git a/src/libs/bsd/getpass.c b/src/libs/bsd/getpass.c new file mode 100644 index 0000000000..bdd993c9a5 --- /dev/null +++ b/src/libs/bsd/getpass.c @@ -0,0 +1,54 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include +#include +#include +#include + + +char * +getpass(const char *prompt) +{ + static char password[128]; + struct termios termios; + bool changed = false; + + // Turn off echo + + if (tcgetattr(fileno(stdin), &termios) == 0) { + struct termios noEchoTermios = termios; + + noEchoTermios.c_lflag &= ~(ECHO | ISIG); + changed = tcsetattr(fileno(stdin), TCSAFLUSH, &noEchoTermios) == 0; + } + + // Show prompt + fputs(prompt, stdout); + fflush(stdout); + + // Read password + if (fgets(password, sizeof(password), stdin) != NULL) { + size_t length = strlen(password); + + if (password[length - 1] == '\n') + password[length - 1] = '\0'; + + if (changed) { + // Manually move to the next line + putchar('\n'); + } + } + + // Restore termios setting + if (changed) + tcsetattr(fileno(stdin), TCSAFLUSH, &termios); + + return password; +} diff --git a/src/libs/bsd/unvis.c b/src/libs/bsd/unvis.c new file mode 100644 index 0000000000..35443d1154 --- /dev/null +++ b/src/libs/bsd/unvis.c @@ -0,0 +1,297 @@ +/*- + * 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. + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD: src/lib/libc/gen/unvis.c,v 1.9 2004/08/02 08:46:23 stefanf Exp $"); + +#include +#include +#include + +/* + * 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); +}