Merge pull request #388 from rayhayes/L1-Prod
Merge in latest changes for scp.
This commit is contained in:
commit
37477b654c
|
@ -266,6 +266,7 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\openssl-epoint.c" />
|
||||
<ClCompile Include="..\..\..\utf8.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)crypto-wrap.h" />
|
||||
|
|
|
@ -294,6 +294,9 @@
|
|||
<ClCompile Include="..\..\..\openssl-epoint.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\utf8.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)crypto-wrap.h">
|
||||
|
|
|
@ -854,12 +854,10 @@ int
|
|||
w32_ftruncate(int fd, off_t length) {
|
||||
CHECK_FD(fd);
|
||||
|
||||
if (!SetFilePointer(w32_fd_to_handle(fd), length, 0, FILE_BEGIN))
|
||||
return -1;
|
||||
if (!SetEndOfFile(w32_fd_to_handle(fd)))
|
||||
return -1;
|
||||
if (!SetFileValidData(w32_fd_to_handle(fd), length))
|
||||
return -1;
|
||||
if (!SetFilePointer(w32_fd_to_handle(fd), 0, 0, FILE_BEGIN))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -232,10 +232,45 @@ long long strtonum(const char *, long long, long long, const char **);
|
|||
# define mblen(x, y) (1)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_WCWIDTH
|
||||
# define wcwidth(x) (((x) >= 0x20 && (x) <= 0x7e) ? 1 : -1)
|
||||
/* force our no-op nl_langinfo and mbtowc */
|
||||
# undef HAVE_NL_LANGINFO
|
||||
# undef HAVE_MBTOWC
|
||||
# undef HAVE_LANGINFO_H
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NL_LANGINFO
|
||||
# define nl_langinfo(x) ""
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MBTOWC
|
||||
int mbtowc(wchar_t *, const char*, size_t);
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(HAVE_VASPRINTF) || !defined(HAVE_VSNPRINTF)
|
||||
# include <stdarg.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some platforms unconditionally undefine va_copy() so we define VA_COPY()
|
||||
* instead. This is known to be the case on at least some configurations of
|
||||
* AIX with the xlc compiler.
|
||||
*/
|
||||
#ifndef VA_COPY
|
||||
# ifdef HAVE_VA_COPY
|
||||
# define VA_COPY(dest, src) va_copy(dest, src)
|
||||
# else
|
||||
# ifdef HAVE___VA_COPY
|
||||
# define VA_COPY(dest, src) __va_copy(dest, src)
|
||||
# else
|
||||
# define VA_COPY(dest, src) (dest) = (src)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_VASPRINTF
|
||||
int vasprintf(char **, const char *, va_list);
|
||||
#endif
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
*/
|
||||
#define VIS_OCTAL 0x01 /* use octal \ddd format */
|
||||
#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */
|
||||
|
||||
#define VIS_ALL 0x400 /* encode all characters */
|
||||
/*
|
||||
* to alter set of characters encoded (default is to encode all
|
||||
* non-graphic except space, tab, and newline).
|
||||
|
|
214
scp.c
214
scp.c
|
@ -78,6 +78,7 @@
|
|||
#else
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <Shlwapi.h>
|
||||
#include "win32_dirent.h"
|
||||
#endif
|
||||
|
||||
|
@ -104,6 +105,7 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -122,10 +124,8 @@
|
|||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "progressmeter.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include <Shlwapi.h>
|
||||
#endif
|
||||
extern char *__progname;
|
||||
|
||||
#define COPY_BUFLEN 16384
|
||||
|
@ -319,125 +319,6 @@ int InitForMicrosoftWindows()
|
|||
return 0;
|
||||
}
|
||||
|
||||
// start of direntry functions in Windows NT like UNIX
|
||||
// opendir(), readdir(), closedir().
|
||||
// NT_DIR * nt_opendir(char *name) ;
|
||||
// struct nt_dirent *nt_readdir(NT_DIR *dirp);
|
||||
// int nt_closedir(NT_DIR *dirp) ;
|
||||
|
||||
// Windows NT directory structure content
|
||||
struct scp_dirent {
|
||||
char *d_name ; // name of the directory entry
|
||||
int d_ino; // UNIX inode
|
||||
//unsigned attrib ; // its attributes
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
long hFile;
|
||||
struct _finddata_t c_file;
|
||||
} SCPDIR;
|
||||
|
||||
|
||||
char * fixslashes(char * str)
|
||||
{
|
||||
int i;
|
||||
if (str == NULL)
|
||||
return str;
|
||||
|
||||
int len = (int)strlen(str);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (str[i] == '/')
|
||||
str[i] = '\\';
|
||||
return str;
|
||||
}
|
||||
|
||||
// force path separator to sep
|
||||
char * forcepathsep(char * str, char sep)
|
||||
{
|
||||
int i;
|
||||
// bail if str is null;
|
||||
if (str == NULL)
|
||||
return str;
|
||||
|
||||
// bail if sep isn't valid
|
||||
if ((sep != '\\') || (sep != '/'))
|
||||
return str;
|
||||
|
||||
char antisep = '/';
|
||||
|
||||
if (sep == '/')
|
||||
antisep = '\\';
|
||||
|
||||
int len = (int)strlen(str);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (str[i] == antisep)
|
||||
str[i] = sep;
|
||||
return str;
|
||||
}
|
||||
|
||||
// get the path separator character
|
||||
char getpathsep(char * path)
|
||||
{
|
||||
char sep = '/';
|
||||
char * p = strpbrk(path,"/\\");
|
||||
if (p != NULL)
|
||||
sep = p[0];
|
||||
|
||||
return sep;
|
||||
}
|
||||
|
||||
bool getRootFrompath(char * path, char * root)
|
||||
{
|
||||
strcpy(root,path);
|
||||
|
||||
char sep = getpathsep(root);
|
||||
forcepathsep(root,sep);
|
||||
char * lastslash = strrchr(root,sep);
|
||||
if (lastslash)
|
||||
*lastslash = 0x00;
|
||||
return (lastslash != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* get option letter from argument vector
|
||||
*/
|
||||
|
||||
char * getfilenamefrompath(char * path)
|
||||
{
|
||||
char * lastslash;
|
||||
char * lastbackslash;
|
||||
|
||||
lastslash = strrchr(path,'/');
|
||||
lastbackslash = strrchr(path, '\\');
|
||||
|
||||
if (lastslash == NULL && lastbackslash == NULL)
|
||||
{
|
||||
// no delimiters, just return the original string
|
||||
return path;
|
||||
}
|
||||
else if (lastslash == NULL)
|
||||
{
|
||||
// no slashes, return the backslash search minus the last char
|
||||
return ++lastbackslash;
|
||||
}
|
||||
else if (lastbackslash == NULL)
|
||||
{
|
||||
// no backslashes, return the slash search minus the last char
|
||||
return ++lastslash;
|
||||
}
|
||||
else
|
||||
{
|
||||
// string has both slashes and backslashes. return whichever is larger
|
||||
// (i.e. further down the string)
|
||||
lastslash++;
|
||||
lastbackslash++;
|
||||
return ((lastslash > lastbackslash)?lastslash:lastbackslash);
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define EMSG ""
|
||||
|
@ -526,33 +407,6 @@ sgetopt(int nargc,
|
|||
return(optopt); /* dump back option letter */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Open a directory stream on NAME.
|
||||
Return a SCPDIR stream on the directory, or NULL if it could not be opened. */
|
||||
SCPDIR * scp_opendir(char *name)
|
||||
{
|
||||
struct _finddata_t c_file;
|
||||
long hFile;
|
||||
SCPDIR *pdir;
|
||||
char searchstr[256];
|
||||
|
||||
sprintf_s(searchstr,sizeof(searchstr),"%s\\*.*",name); // add *.* to it for NT
|
||||
|
||||
if( (hFile = (long)_findfirst( searchstr, &c_file )) == -1L ) {
|
||||
if ( scpverbose)
|
||||
printf( "No files found for %s search.\n", name );
|
||||
return (SCPDIR *) NULL;
|
||||
}
|
||||
else {
|
||||
pdir = (SCPDIR *) malloc( sizeof(SCPDIR) );
|
||||
pdir->hFile = hFile ;
|
||||
pdir->c_file = c_file ;
|
||||
|
||||
return pdir ;
|
||||
}
|
||||
}
|
||||
|
||||
int _utimedir (char *name, struct _utimbuf *filetime)
|
||||
{
|
||||
int rc, chandle;
|
||||
|
@ -579,30 +433,6 @@ int _utimedir (char *name, struct _utimbuf *filetime)
|
|||
HANDLE hprocess=(HANDLE) 0; // we made it a global to stop child process(ssh) of scp
|
||||
#else
|
||||
|
||||
/* Read a directory entry from SCPDIRP.
|
||||
Return a pointer to a `struct scp_dirent' describing the entry,
|
||||
or NULL for EOF or error. The storage returned may be overwritten
|
||||
by a later readdir call on the same SCPDIR stream. */
|
||||
struct scp_dirent *readdir(SCPDIR *dirp)
|
||||
{
|
||||
struct scp_dirent *pdirentry;
|
||||
|
||||
for (;;) {
|
||||
if (_findnext(dirp->hFile, &(dirp->c_file)) == 0) {
|
||||
if ((strcmp(dirp->c_file.name, ".") == 0) ||
|
||||
(strcmp(dirp->c_file.name, "..") == 0)) {
|
||||
continue;
|
||||
}
|
||||
pdirentry = (struct scp_dirent *)malloc(sizeof(struct scp_dirent));
|
||||
pdirentry->d_name = dirp->c_file.name;
|
||||
pdirentry->d_ino = 1; // a fictious one like UNIX to say it is nonzero
|
||||
return pdirentry;
|
||||
}
|
||||
else {
|
||||
return (struct scp_dirent *) NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
|
@ -645,7 +475,7 @@ do_local_cmd(arglist *a)
|
|||
if (verbose_mode) {
|
||||
fprintf(stderr, "Executing:");
|
||||
for (i = 0; i < a->num; i++)
|
||||
fprintf(stderr, " %s", a->list[i]);
|
||||
fmprintf(stderr, " %s", a->list[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#ifdef WINDOWS
|
||||
|
@ -941,7 +771,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
|
|||
int pin[2], pout[2], reserved[2];
|
||||
|
||||
if (verbose_mode)
|
||||
fprintf(stderr,
|
||||
fmprintf(stderr,
|
||||
"Executing: program %s host %s, user %s, command %s\n",
|
||||
ssh_program, host,
|
||||
remuser ? remuser : "(unspecified)", cmd);
|
||||
|
@ -1018,7 +848,7 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
|
|||
int status;
|
||||
|
||||
if (verbose_mode)
|
||||
fprintf(stderr,
|
||||
fmprintf(stderr,
|
||||
"Executing: 2nd program %s host %s, user %s, command %s\n",
|
||||
ssh_program, host,
|
||||
remuser ? remuser : "(unspecified)", cmd);
|
||||
|
@ -1089,12 +919,19 @@ main(int argc, char **argv)
|
|||
extern int optind;
|
||||
|
||||
#ifdef WINDOWS
|
||||
/*
|
||||
* Initialize I/O wrappers.
|
||||
*/
|
||||
|
||||
w32posix_initialize();
|
||||
ConInit(STD_OUTPUT_HANDLE, TRUE);
|
||||
#endif
|
||||
|
||||
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
|
||||
sanitise_stdfd();
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
/* Copy argv, because we modify it */
|
||||
newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv));
|
||||
for (n = 0; n < argc; n++)
|
||||
|
@ -1247,7 +1084,7 @@ main(int argc, char **argv)
|
|||
exit(errs != 0);
|
||||
}
|
||||
if (tflag) {
|
||||
/* Receive data. */
|
||||
/* Receive data. */
|
||||
sink(argc, argv);
|
||||
exit(errs != 0);
|
||||
}
|
||||
|
@ -1569,9 +1406,8 @@ syserr: run_err("%s: %s", name, strerror(errno));
|
|||
snprintf(buf, sizeof buf, "C%04o %lld %s\n",
|
||||
(u_int) (stb.st_mode & FILEMODEMASK),
|
||||
(long long)stb.st_size, last);
|
||||
if (verbose_mode) {
|
||||
fprintf(stderr, "Sending file modes: %s", buf);
|
||||
}
|
||||
if (verbose_mode)
|
||||
fmprintf(stderr, "Sending file modes: %s", buf);
|
||||
(void) atomicio(vwrite, remout, buf, strlen(buf));
|
||||
if (response() < 0)
|
||||
goto next;
|
||||
|
@ -1607,8 +1443,6 @@ next: if (fd != -1) {
|
|||
haderr = errno;
|
||||
}
|
||||
unset_nonblock(remout);
|
||||
if (showprogress)
|
||||
stop_progress_meter();
|
||||
|
||||
if (fd != -1) {
|
||||
if (close(fd) < 0 && !haderr)
|
||||
|
@ -1620,6 +1454,8 @@ next: if (fd != -1) {
|
|||
else
|
||||
run_err("%s: %s", name, strerror(haderr));
|
||||
(void) response();
|
||||
if (showprogress)
|
||||
stop_progress_meter();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1635,7 +1471,7 @@ rsource(char *name, struct stat *statp)
|
|||
return;
|
||||
}
|
||||
last = strrchr(name, '/');
|
||||
if (last == 0)
|
||||
if (last == NULL)
|
||||
last = name;
|
||||
else
|
||||
last++;
|
||||
|
@ -1656,7 +1492,7 @@ rsource(char *name, struct stat *statp)
|
|||
free(wtmp);
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Entering directory: %s", path);
|
||||
fmprintf(stderr, "Entering directory: %s", path);
|
||||
#endif
|
||||
|
||||
(void) atomicio(vwrite, remout, path, strlen(path));
|
||||
|
@ -1741,7 +1577,7 @@ sink(int argc, char **argv)
|
|||
free(wtmp);
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Sink: %s", buf);
|
||||
fmprintf(stderr, "Sink: %s", buf);
|
||||
#endif
|
||||
if (buf[0] == '\01' || buf[0] == '\02') {
|
||||
if (iamremote == 0)
|
||||
|
@ -1922,8 +1758,6 @@ bad: run_err("%s: %s", np, strerror(errno));
|
|||
}
|
||||
}
|
||||
unset_nonblock(remin);
|
||||
if (showprogress)
|
||||
stop_progress_meter();
|
||||
if (count != 0 && wrerr == NO &&
|
||||
atomicio(vwrite, ofd, bp->buf, count) != count) {
|
||||
wrerr = YES;
|
||||
|
@ -1962,6 +1796,8 @@ bad: run_err("%s: %s", np, strerror(errno));
|
|||
wrerrno = errno;
|
||||
}
|
||||
(void) response();
|
||||
if (showprogress)
|
||||
stop_progress_meter();
|
||||
if (setimes && wrerr == NO) {
|
||||
setimes = 0;
|
||||
if (utimes(np, tv) < 0) {
|
||||
|
@ -2048,7 +1884,7 @@ run_err(const char *fmt,...)
|
|||
|
||||
if (!iamremote) {
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
vfmprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
@ -2094,7 +1930,7 @@ okname(char *cp0)
|
|||
} while (*++cp);
|
||||
return (1);
|
||||
|
||||
bad: fprintf(stderr, "%s: invalid user name\n", cp0);
|
||||
bad: fmprintf(stderr, "%s: invalid user name\n", cp0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
/* $OpenBSD: utf8.c,v 1.3 2016/05/30 12:57:21 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Utility functions for multibyte-character handling,
|
||||
* in particular to sanitize untrusted strings for terminal output.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
# include <langinfo.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
|
||||
# include <vis.h>
|
||||
#endif
|
||||
#ifdef HAVE_WCHAR_H
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
static int dangerous_locale(void);
|
||||
static int grow_dst(char **, size_t *, size_t, char **, size_t);
|
||||
static int vasnmprintf(char **, size_t, int *, const char *, va_list);
|
||||
|
||||
|
||||
/*
|
||||
* For US-ASCII and UTF-8 encodings, we can safely recover from
|
||||
* encoding errors and from non-printable characters. For any
|
||||
* other encodings, err to the side of caution and abort parsing:
|
||||
* For state-dependent encodings, recovery is impossible.
|
||||
* For arbitrary encodings, replacement of non-printable
|
||||
* characters would be non-trivial and too fragile.
|
||||
*/
|
||||
|
||||
static int
|
||||
dangerous_locale(void) {
|
||||
|
||||
#ifndef WINDOWS
|
||||
char *loc;
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
loc = nl_langinfo(CODESET);
|
||||
#endif
|
||||
|
||||
return strcmp(loc, "US-ASCII") && strcmp(loc, "UTF-8");
|
||||
#else
|
||||
wchar_t loc[LOCALE_NAME_MAX_LENGTH];
|
||||
|
||||
GetSystemDefaultLocaleName(loc, LOCALE_NAME_MAX_LENGTH);
|
||||
|
||||
return wcscmp(loc, L"US-ASCII") && wcscmp(loc, L"UTF-8");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
grow_dst(char **dst, size_t *sz, size_t maxsz, char **dp, size_t need)
|
||||
{
|
||||
char *tp;
|
||||
size_t tsz;
|
||||
|
||||
if (*dp + need < *dst + *sz)
|
||||
return 0;
|
||||
tsz = *sz + 128;
|
||||
if (tsz > maxsz)
|
||||
tsz = maxsz;
|
||||
if ((tp = realloc(*dst, tsz)) == NULL)
|
||||
return -1;
|
||||
*dp = tp + (*dp - *dst);
|
||||
*dst = tp;
|
||||
*sz = tsz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following two functions limit the number of bytes written,
|
||||
* including the terminating '\0', to sz. Unless wp is NULL,
|
||||
* they limit the number of display columns occupied to *wp.
|
||||
* Whichever is reached first terminates the output string.
|
||||
* To stay close to the standard interfaces, they return the number of
|
||||
* non-NUL bytes that would have been written if both were unlimited.
|
||||
* If wp is NULL, newline, carriage return, and tab are allowed;
|
||||
* otherwise, the actual number of columns occupied by what was
|
||||
* written is returned in *wp.
|
||||
*/
|
||||
|
||||
static int
|
||||
vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap)
|
||||
{
|
||||
char *src; /* Source string returned from vasprintf. */
|
||||
char *sp; /* Pointer into src. */
|
||||
char *dst; /* Destination string to be returned. */
|
||||
char *dp; /* Pointer into dst. */
|
||||
char *tp; /* Temporary pointer for dst. */
|
||||
size_t sz; /* Number of bytes allocated for dst. */
|
||||
wchar_t wc; /* Wide character at sp. */
|
||||
int len; /* Number of bytes in the character at sp. */
|
||||
int ret; /* Number of bytes needed to format src. */
|
||||
int width; /* Display width of the character wc. */
|
||||
int total_width, max_width, print;
|
||||
|
||||
src = NULL;
|
||||
if ((ret = vasprintf(&src, fmt, ap)) <= 0)
|
||||
goto fail;
|
||||
|
||||
sz = strlen(src) + 1;
|
||||
if ((dst = malloc(sz)) == NULL) {
|
||||
free(src);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (maxsz > INT_MAX)
|
||||
maxsz = INT_MAX;
|
||||
|
||||
sp = src;
|
||||
dp = dst;
|
||||
ret = 0;
|
||||
print = 1;
|
||||
total_width = 0;
|
||||
max_width = wp == NULL ? INT_MAX : *wp;
|
||||
while (*sp != '\0') {
|
||||
if ((len = mbtowc(&wc, sp, MB_CUR_MAX)) == -1) {
|
||||
(void)mbtowc(NULL, NULL, MB_CUR_MAX);
|
||||
if (dangerous_locale()) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
len = 1;
|
||||
width = -1;
|
||||
} else if (wp == NULL &&
|
||||
(wc == L'\n' || wc == L'\r' || wc == L'\t')) {
|
||||
/*
|
||||
* Don't use width uninitialized; the actual
|
||||
* value doesn't matter because total_width
|
||||
* is only returned for wp != NULL.
|
||||
*/
|
||||
width = 0;
|
||||
} else if ((width = wcwidth(wc)) == -1 &&
|
||||
dangerous_locale()) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Valid, printable character. */
|
||||
|
||||
if (width >= 0) {
|
||||
if (print && (dp - dst >= (int)maxsz - len ||
|
||||
total_width > max_width - width))
|
||||
print = 0;
|
||||
if (print) {
|
||||
if (grow_dst(&dst, &sz, maxsz,
|
||||
&dp, len) == -1) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
total_width += width;
|
||||
memcpy(dp, sp, len);
|
||||
dp += len;
|
||||
}
|
||||
sp += len;
|
||||
if (ret >= 0)
|
||||
ret += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Escaping required. */
|
||||
|
||||
while (len > 0) {
|
||||
if (print && (dp - dst >= (int)maxsz - 4 ||
|
||||
total_width > max_width - 4))
|
||||
print = 0;
|
||||
if (print) {
|
||||
if (grow_dst(&dst, &sz, maxsz,
|
||||
&dp, 4) == -1) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
tp = vis(dp, *sp, VIS_OCTAL | VIS_ALL, 0);
|
||||
width = tp - dp;
|
||||
total_width += width;
|
||||
dp = tp;
|
||||
} else
|
||||
width = 4;
|
||||
len--;
|
||||
sp++;
|
||||
if (ret >= 0)
|
||||
ret += width;
|
||||
}
|
||||
if (len > 0)
|
||||
break;
|
||||
}
|
||||
free(src);
|
||||
*dp = '\0';
|
||||
*str = dst;
|
||||
if (wp != NULL)
|
||||
*wp = total_width;
|
||||
|
||||
/*
|
||||
* If the string was truncated by the width limit but
|
||||
* would have fit into the size limit, the only sane way
|
||||
* to report the problem is using the return value, such
|
||||
* that the usual idiom "if (ret < 0 || ret >= sz) error"
|
||||
* works as expected.
|
||||
*/
|
||||
|
||||
if (ret < (int)maxsz && !print)
|
||||
ret = -1;
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
if (wp != NULL)
|
||||
*wp = 0;
|
||||
if (ret == 0) {
|
||||
*str = src;
|
||||
return 0;
|
||||
} else {
|
||||
*str = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
snmprintf(char *str, size_t sz, int *wp, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *cp;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vasnmprintf(&cp, sz, wp, fmt, ap);
|
||||
va_end(ap);
|
||||
if (cp != NULL) {
|
||||
(void)strlcpy(str, cp, sz);
|
||||
free(cp);
|
||||
} else
|
||||
*str = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* To stay close to the standard interfaces, the following functions
|
||||
* return the number of non-NUL bytes written.
|
||||
*/
|
||||
|
||||
int
|
||||
vfmprintf(FILE *stream, const char *fmt, va_list ap)
|
||||
{
|
||||
char *str;
|
||||
int ret;
|
||||
|
||||
if ((ret = vasnmprintf(&str, INT_MAX, NULL, fmt, ap)) < 0)
|
||||
return -1;
|
||||
if (fputs(str, stream) == EOF)
|
||||
ret = -1;
|
||||
free(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
fmprintf(FILE *stream, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vfmprintf(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
mprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vfmprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/* $OpenBSD: utf8.h,v 1.1 2016/05/25 23:48:45 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
int mprintf(const char *, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
int fmprintf(FILE *, const char *, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
int vfmprintf(FILE *, const char *, va_list);
|
||||
int snmprintf(char *, size_t, int *, const char *, ...)
|
||||
__attribute__((format(printf, 4, 5)));
|
Loading…
Reference in New Issue