diff options
author | peter <peter@FreeBSD.org> | 2013-08-11 20:03:12 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2013-08-11 20:03:12 +0000 |
commit | 5f2a1d653696ec5457bfd044f0ebcd873bfc3c80 (patch) | |
tree | 7c1ae67d07b93aea05bfea51c590c1112b65042b /contrib/nvi/common | |
parent | 324febaf01918418f99998aa5537126ac98c9df0 (diff) | |
download | FreeBSD-src-5f2a1d653696ec5457bfd044f0ebcd873bfc3c80.zip FreeBSD-src-5f2a1d653696ec5457bfd044f0ebcd873bfc3c80.tar.gz |
Update nvi-1.79 to 2.1.1-4334a8297f
This is the gsoc-2011 project to clean up and backport multibyte support
from other nvi forks in a form we can use.
USE_WIDECHAR is on unless building for the rescue crunchgen. This should
allow editing in the native locale encoding.
USE_ICONV depends on make.conf having 'WITH_ICONV=YES' for now. This
adds the ability to do things like edit a KOI8-R file while having $LANG
set to (say) en_US.UTF-8. iconv is used to transcode the characters for
display.
Other points:
* It uses gencat and catopen/etc instead of homegrown msg catalog stuff.
* A lot of stuff has been trimmed out, eg: the perl and tcl bindings which
we could never use in base anyway.
* It uses ncursesw when in widechar mode. This could be interesting.
GSoC info: http://www.google-melange.com/gsoc/proposal/review/google/gsoc2011/zy/1
Repo at: https://github.com/lichray/nvi2
Obtained from: Zhihao Yuan <lichray@gmail.com>
Diffstat (limited to 'contrib/nvi/common')
37 files changed, 3478 insertions, 2333 deletions
diff --git a/contrib/nvi/common/api.c b/contrib/nvi/common/api.c deleted file mode 100644 index 35d9f0c..0000000 --- a/contrib/nvi/common/api.c +++ /dev/null @@ -1,525 +0,0 @@ -/*- - * Copyright (c) 1992, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1992, 1993, 1994, 1995, 1996 - * Keith Bostic. All rights reserved. - * Copyright (c) 1995 - * George V. Neville-Neil. All rights reserved. - * - * See the LICENSE file for redistribution information. - */ - -#include "config.h" - -#ifndef lint -static const char sccsid[] = "@(#)api.c 8.26 (Berkeley) 10/14/96"; -#endif /* not lint */ - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/time.h> - -#include <bitstring.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <termios.h> -#include <unistd.h> - -#include "../common/common.h" - -extern GS *__global_list; /* XXX */ - -/* - * api_fscreen -- - * Return a pointer to the screen specified by the screen id - * or a file name. - * - * PUBLIC: SCR *api_fscreen __P((int, char *)); - */ -SCR * -api_fscreen(id, name) - int id; - char *name; -{ - GS *gp; - SCR *tsp; - - gp = __global_list; - - /* Search the displayed list. */ - for (tsp = gp->dq.cqh_first; - tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next) - if (name == NULL) { - if (id == tsp->id) - return (tsp); - } else if (!strcmp(name, tsp->frp->name)) - return (tsp); - - /* Search the hidden list. */ - for (tsp = gp->hq.cqh_first; - tsp != (void *)&gp->hq; tsp = tsp->q.cqe_next) - if (name == NULL) { - if (id == tsp->id) - return (tsp); - } else if (!strcmp(name, tsp->frp->name)) - return (tsp); - return (NULL); -} - -/* - * api_aline -- - * Append a line. - * - * PUBLIC: int api_aline __P((SCR *, recno_t, char *, size_t)); - */ -int -api_aline(sp, lno, line, len) - SCR *sp; - recno_t lno; - char *line; - size_t len; -{ - return (db_append(sp, 1, lno, line, len)); -} - -/* - * api_dline -- - * Delete a line. - * - * PUBLIC: int api_dline __P((SCR *, recno_t)); - */ -int -api_dline(sp, lno) - SCR *sp; - recno_t lno; -{ - return (db_delete(sp, lno)); -} - -/* - * api_gline -- - * Get a line. - * - * PUBLIC: int api_gline __P((SCR *, recno_t, char **, size_t *)); - */ -int -api_gline(sp, lno, linepp, lenp) - SCR *sp; - recno_t lno; - char **linepp; - size_t *lenp; -{ - int isempty; - - if (db_eget(sp, lno, linepp, lenp, &isempty)) { - if (isempty) - msgq(sp, M_ERR, "209|The file is empty"); - return (1); - } - return (0); -} - -/* - * api_iline -- - * Insert a line. - * - * PUBLIC: int api_iline __P((SCR *, recno_t, char *, size_t)); - */ -int -api_iline(sp, lno, line, len) - SCR *sp; - recno_t lno; - char *line; - size_t len; -{ - return (db_insert(sp, lno, line, len)); -} - -/* - * api_lline -- - * Return the line number of the last line in the file. - * - * PUBLIC: int api_lline __P((SCR *, recno_t *)); - */ -int -api_lline(sp, lnop) - SCR *sp; - recno_t *lnop; -{ - return (db_last(sp, lnop)); -} - -/* - * api_sline -- - * Set a line. - * - * PUBLIC: int api_sline __P((SCR *, recno_t, char *, size_t)); - */ -int -api_sline(sp, lno, line, len) - SCR *sp; - recno_t lno; - char *line; - size_t len; -{ - return (db_set(sp, lno, line, len)); -} - -/* - * api_getmark -- - * Get the mark. - * - * PUBLIC: int api_getmark __P((SCR *, int, MARK *)); - */ -int -api_getmark(sp, markname, mp) - SCR *sp; - int markname; - MARK *mp; -{ - return (mark_get(sp, (ARG_CHAR_T)markname, mp, M_ERR)); -} - -/* - * api_setmark -- - * Set the mark. - * - * PUBLIC: int api_setmark __P((SCR *, int, MARK *)); - */ -int -api_setmark(sp, markname, mp) - SCR *sp; - int markname; - MARK *mp; -{ - return (mark_set(sp, (ARG_CHAR_T)markname, mp, 1)); -} - -/* - * api_nextmark -- - * Return the first mark if next not set, otherwise return the - * subsequent mark. - * - * PUBLIC: int api_nextmark __P((SCR *, int, char *)); - */ -int -api_nextmark(sp, next, namep) - SCR *sp; - int next; - char *namep; -{ - LMARK *mp; - - mp = sp->ep->marks.lh_first; - if (next) - for (; mp != NULL; mp = mp->q.le_next) - if (mp->name == *namep) { - mp = mp->q.le_next; - break; - } - if (mp == NULL) - return (1); - *namep = mp->name; - return (0); -} - -/* - * api_getcursor -- - * Get the cursor. - * - * PUBLIC: int api_getcursor __P((SCR *, MARK *)); - */ -int -api_getcursor(sp, mp) - SCR *sp; - MARK *mp; -{ - mp->lno = sp->lno; - mp->cno = sp->cno; - return (0); -} - -/* - * api_setcursor -- - * Set the cursor. - * - * PUBLIC: int api_setcursor __P((SCR *, MARK *)); - */ -int -api_setcursor(sp, mp) - SCR *sp; - MARK *mp; -{ - size_t len; - - if (db_get(sp, mp->lno, DBG_FATAL, NULL, &len)) - return (1); - if (mp->cno < 0 || mp->cno > len) { - msgq(sp, M_ERR, "Cursor set to nonexistent column"); - return (1); - } - - /* Set the cursor. */ - sp->lno = mp->lno; - sp->cno = mp->cno; - return (0); -} - -/* - * api_emessage -- - * Print an error message. - * - * PUBLIC: void api_emessage __P((SCR *, char *)); - */ -void -api_emessage(sp, text) - SCR *sp; - char *text; -{ - msgq(sp, M_ERR, "%s", text); -} - -/* - * api_imessage -- - * Print an informational message. - * - * PUBLIC: void api_imessage __P((SCR *, char *)); - */ -void -api_imessage(sp, text) - SCR *sp; - char *text; -{ - msgq(sp, M_INFO, "%s", text); -} - -/* - * api_edit - * Create a new screen and return its id - * or edit a new file in the current screen. - * - * PUBLIC: int api_edit __P((SCR *, char *, SCR **, int)); - */ -int -api_edit(sp, file, spp, newscreen) - SCR *sp; - char *file; - SCR **spp; - int newscreen; -{ - ARGS *ap[2], a; - EXCMD cmd; - - if (file) { - ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, ap); - ex_cadd(&cmd, &a, file, strlen(file)); - } else - ex_cinit(&cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0, NULL); - if (newscreen) - cmd.flags |= E_NEWSCREEN; /* XXX */ - if (cmd.cmd->fn(sp, &cmd)) - return (1); - *spp = sp->nextdisp; - return (0); -} - -/* - * api_escreen - * End a screen. - * - * PUBLIC: int api_escreen __P((SCR *)); - */ -int -api_escreen(sp) - SCR *sp; -{ - EXCMD cmd; - - /* - * XXX - * If the interpreter exits anything other than the current - * screen, vi isn't going to update everything correctly. - */ - ex_cinit(&cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0, NULL); - return (cmd.cmd->fn(sp, &cmd)); -} - -/* - * api_swscreen -- - * Switch to a new screen. - * - * PUBLIC: int api_swscreen __P((SCR *, SCR *)); - */ -int -api_swscreen(sp, new) - SCR *sp, *new; -{ - /* - * XXX - * If the interpreter switches from anything other than the - * current screen, vi isn't going to update everything correctly. - */ - sp->nextdisp = new; - F_SET(sp, SC_SSWITCH); - - return (0); -} - -/* - * api_map -- - * Map a key. - * - * PUBLIC: int api_map __P((SCR *, char *, char *, size_t)); - */ -int -api_map(sp, name, map, len) - SCR *sp; - char *name, *map; - size_t len; -{ - ARGS *ap[3], a, b; - EXCMD cmd; - - ex_cinit(&cmd, C_MAP, 0, OOBLNO, OOBLNO, 0, ap); - ex_cadd(&cmd, &a, name, strlen(name)); - ex_cadd(&cmd, &b, map, len); - return (cmd.cmd->fn(sp, &cmd)); -} - -/* - * api_unmap -- - * Unmap a key. - * - * PUBLIC: int api_unmap __P((SCR *, char *)); - */ -int -api_unmap(sp, name) - SCR *sp; - char *name; -{ - ARGS *ap[2], a; - EXCMD cmd; - - ex_cinit(&cmd, C_UNMAP, 0, OOBLNO, OOBLNO, 0, ap); - ex_cadd(&cmd, &a, name, strlen(name)); - return (cmd.cmd->fn(sp, &cmd)); -} - -/* - * api_opts_get -- - * Return a option value as a string, in allocated memory. - * If the option is of type boolean, boolvalue is (un)set - * according to the value; otherwise boolvalue is -1. - * - * PUBLIC: int api_opts_get __P((SCR *, char *, char **, int *)); - */ -int -api_opts_get(sp, name, value, boolvalue) - SCR *sp; - char *name, **value; - int *boolvalue; -{ - OPTLIST const *op; - int offset; - - if ((op = opts_search(name)) == NULL) { - opts_nomatch(sp, name); - return (1); - } - - offset = op - optlist; - if (boolvalue != NULL) - *boolvalue = -1; - switch (op->type) { - case OPT_0BOOL: - case OPT_1BOOL: - MALLOC_RET(sp, *value, char *, strlen(op->name) + 2 + 1); - (void)sprintf(*value, - "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name); - if (boolvalue != NULL) - *boolvalue = O_ISSET(sp, offset); - break; - case OPT_NUM: - MALLOC_RET(sp, *value, char *, 20); - (void)sprintf(*value, "%lu", (u_long)O_VAL(sp, offset)); - break; - case OPT_STR: - if (O_STR(sp, offset) == NULL) { - MALLOC_RET(sp, *value, char *, 2); - value[0] = '\0'; - } else { - MALLOC_RET(sp, - *value, char *, strlen(O_STR(sp, offset)) + 1); - (void)sprintf(*value, "%s", O_STR(sp, offset)); - } - break; - } - return (0); -} - -/* - * api_opts_set -- - * Set options. - * - * PUBLIC: int api_opts_set __P((SCR *, char *, char *, u_long, int)); - */ -int -api_opts_set(sp, name, str_value, num_value, bool_value) - SCR *sp; - char *name, *str_value; - u_long num_value; - int bool_value; -{ - ARGS *ap[2], a, b; - OPTLIST const *op; - int rval; - size_t blen; - char *bp; - - if ((op = opts_search(name)) == NULL) { - opts_nomatch(sp, name); - return (1); - } - - switch (op->type) { - case OPT_0BOOL: - case OPT_1BOOL: - GET_SPACE_RET(sp, bp, blen, 64); - a.len = snprintf(bp, 64, "%s%s", bool_value ? "" : "no", name); - break; - case OPT_NUM: - GET_SPACE_RET(sp, bp, blen, 64); - a.len = snprintf(bp, 64, "%s=%lu", name, num_value); - break; - case OPT_STR: - GET_SPACE_RET(sp, bp, blen, 1024); - a.len = snprintf(bp, 1024, "%s=%s", name, str_value); - break; - } - a.bp = bp; - b.len = 0; - b.bp = NULL; - ap[0] = &a; - ap[1] = &b; - rval = opts_set(sp, ap, NULL); - - FREE_SPACE(sp, bp, blen); - - return (rval); -} - -/* - * api_run_str -- - * Execute a string as an ex command. - * - * PUBLIC: int api_run_str __P((SCR *, char *)); - */ -int -api_run_str(sp, cmd) - SCR *sp; - char *cmd; -{ - return (ex_run_str(sp, NULL, cmd, strlen(cmd), 0, 0)); -} diff --git a/contrib/nvi/common/args.h b/contrib/nvi/common/args.h index e84dc2c..b23699c 100644 --- a/contrib/nvi/common/args.h +++ b/contrib/nvi/common/args.h @@ -6,7 +6,7 @@ * * See the LICENSE file for redistribution information. * - * @(#)args.h 10.2 (Berkeley) 3/6/96 + * $Id: args.h,v 10.2 1996/03/06 19:50:07 bostic Exp $ */ /* diff --git a/contrib/nvi/common/common.h b/contrib/nvi/common/common.h index 0e13fc8..71f4c7f 100644 --- a/contrib/nvi/common/common.h +++ b/contrib/nvi/common/common.h @@ -6,16 +6,10 @@ * * See the LICENSE file for redistribution information. * - * @(#)common.h 10.13 (Berkeley) 9/25/96 + * $Id: common.h,v 10.22 2012/04/13 05:21:50 zy Exp $ */ /* - * Porting information built at configuration time. Included before - * any of nvi's include files. - */ -#include "port.h" - -/* * Pseudo-local includes. These are files that are unlikely to exist * on most machines to which we're porting vi, and we want to include * them in a very specific order, regardless. @@ -29,6 +23,8 @@ */ typedef struct _cb CB; typedef struct _csc CSC; +typedef struct _conv CONV; +typedef struct _conv_win CONVWIN; typedef struct _event EVENT; typedef struct _excmd EXCMD; typedef struct _exf EXF; @@ -48,7 +44,7 @@ typedef struct _tagq TAGQ; typedef struct _text TEXT; /* Autoindent state. */ -typedef enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_t; +typedef enum { C_NOTSET, C_CARATSET, C_ZEROSET } carat_t; /* Busy message types. */ typedef enum { BUSY_ON = 1, BUSY_OFF, BUSY_UPDATE } busy_t; @@ -86,6 +82,7 @@ typedef enum { SEQ_ABBREV, SEQ_COMMAND, SEQ_INPUT } seq_t; #include "seq.h" /* Required by screen.h. */ #include "util.h" /* Required by ex.h. */ #include "mark.h" /* Required by gs.h. */ +#include "conv.h" /* Required by ex.h and screen.h */ #include "../ex/ex.h" /* Required by gs.h. */ #include "gs.h" /* Required by screen.h. */ #include "screen.h" /* Required by exf.h. */ @@ -93,4 +90,4 @@ typedef enum { SEQ_ABBREV, SEQ_COMMAND, SEQ_INPUT } seq_t; #include "log.h" #include "mem.h" -#include "com_extern.h" +#include "extern.h" diff --git a/contrib/nvi/common/conv.c b/contrib/nvi/common/conv.c new file mode 100644 index 0000000..7803cec --- /dev/null +++ b/contrib/nvi/common/conv.c @@ -0,0 +1,446 @@ +/*- + * Copyright (c) 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * Copyright (c) 2011, 2012 + * Zhihao Yuan. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#ifndef lint +static const char sccsid[] = "$Id: conv.c,v 2.39 2013/07/01 23:28:13 zy Exp $"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <errno.h> +#include <limits.h> +#include <langinfo.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +#include "common.h" + +/* + * codeset -- + * Get the locale encoding. + * + * PUBLIC: char * codeset __P((void)); + */ +char * +codeset(void) { + static char *cs; + + if (cs == NULL) + cs = nl_langinfo(CODESET); + return cs; +} + +#ifdef USE_WIDECHAR +static int +raw2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, + size_t *tolen, CHAR_T **dst) +{ + int i; + CHAR_T **tostr = &cw->bp1.wc; + size_t *blen = &cw->blen1; + + BINC_RETW(NULL, *tostr, *blen, len); + + *tolen = len; + for (i = 0; i < len; ++i) + (*tostr)[i] = (u_char) str[i]; + + *dst = cw->bp1.wc; + + return 0; +} + +#define CONV_BUFFER_SIZE 512 +/* fill the buffer with codeset encoding of string pointed to by str + * left has the number of bytes left in str and is adjusted + * len contains the number of bytes put in the buffer + */ +#ifdef USE_ICONV +#define CONVERT(str, left, src, len) \ + do { \ + size_t outleft; \ + char *bp = buffer; \ + outleft = CONV_BUFFER_SIZE; \ + errno = 0; \ + if (iconv(id, (iconv_src_t)&str, &left, &bp, &outleft) == -1 && \ + errno != E2BIG) \ + goto err; \ + if ((len = CONV_BUFFER_SIZE - outleft) == 0) { \ + error = -left; \ + goto err; \ + } \ + src = buffer; \ + } while (0) + +#define IC_RESET() \ + do { \ + if (id != (iconv_t)-1) \ + iconv(id, NULL, NULL, NULL, NULL); \ + } while(0) +#else +#define CONVERT(str, left, src, len) +#define IC_RESET() +#endif + +static int +default_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, + size_t *tolen, CHAR_T **dst, iconv_t id) +{ + size_t i = 0, j; + CHAR_T **tostr = &cw->bp1.wc; + size_t *blen = &cw->blen1; + mbstate_t mbs; + size_t n; + ssize_t nlen = len; + char *src = (char *)str; +#ifdef USE_ICONV + char buffer[CONV_BUFFER_SIZE]; +#endif + size_t left = len; + int error = 1; + + BZERO(&mbs, 1); + BINC_RETW(NULL, *tostr, *blen, nlen); + +#ifdef USE_ICONV + if (id != (iconv_t)-1) + CONVERT(str, left, src, len); +#endif + + for (i = 0, j = 0; j < len; ) { + n = mbrtowc((*tostr)+i, src+j, len-j, &mbs); + /* NULL character converted */ + if (n == -2) error = -(len-j); + if (n == -1 || n == -2) goto err; + if (n == 0) n = 1; + j += n; + if (++i >= *blen) { + nlen += 256; + BINC_RETW(NULL, *tostr, *blen, nlen); + } + if (id != (iconv_t)-1 && j == len && left) { + CONVERT(str, left, src, len); + j = 0; + } + } + + error = 0; +err: + *tolen = i; + *dst = cw->bp1.wc; + IC_RESET(); + + return error; +} + +static int +fe_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, + size_t *tolen, CHAR_T **dst) +{ + return default_char2int(sp, str, len, cw, tolen, dst, + sp->conv.id[IC_FE_CHAR2INT]); +} + +static int +ie_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, + size_t *tolen, CHAR_T **dst) +{ + return default_char2int(sp, str, len, cw, tolen, dst, + sp->conv.id[IC_IE_CHAR2INT]); +} + +static int +cs_char2int(SCR *sp, const char * str, ssize_t len, CONVWIN *cw, + size_t *tolen, CHAR_T **dst) +{ + return default_char2int(sp, str, len, cw, tolen, dst, + (iconv_t)-1); +} + +static int +int2raw(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, + size_t *tolen, char **dst) +{ + int i; + char **tostr = &cw->bp1.c; + size_t *blen = &cw->blen1; + + BINC_RETC(NULL, *tostr, *blen, len); + + *tolen = len; + for (i = 0; i < len; ++i) + (*tostr)[i] = str[i]; + + *dst = cw->bp1.c; + + return 0; +} + +static int +default_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, + size_t *tolen, char **pdst, iconv_t id) +{ + size_t i, j, offset = 0; + char **tostr = &cw->bp1.c; + size_t *blen = &cw->blen1; + mbstate_t mbs; + size_t n; + ssize_t nlen = len + MB_CUR_MAX; + char *dst; + size_t buflen; +#ifdef USE_ICONV + char buffer[CONV_BUFFER_SIZE]; +#endif + int error = 1; + +/* convert first len bytes of buffer and append it to cw->bp + * len is adjusted => 0 + * offset contains the offset in cw->bp and is adjusted + * cw->bp is grown as required + */ +#ifdef USE_ICONV +#define CONVERT2(_buffer, lenp, cw, offset) \ + do { \ + char *bp = _buffer; \ + int ret; \ + do { \ + size_t outleft = cw->blen1 - offset; \ + char *obp = cw->bp1.c + offset; \ + if (cw->blen1 < offset + MB_CUR_MAX) { \ + nlen += 256; \ + BINC_RETC(NULL, cw->bp1.c, cw->blen1, nlen); \ + } \ + errno = 0; \ + ret = iconv(id, (iconv_src_t)&bp, lenp, &obp, &outleft); \ + if (ret == -1 && errno != E2BIG) \ + goto err; \ + offset = cw->blen1 - outleft; \ + } while (ret != 0); \ + } while (0) +#else +#define CONVERT2(_buffer, lenp, cw, offset) +#endif + + + BZERO(&mbs, 1); + BINC_RETC(NULL, *tostr, *blen, nlen); + dst = *tostr; buflen = *blen; + +#ifdef USE_ICONV + if (id != (iconv_t)-1) { + dst = buffer; buflen = CONV_BUFFER_SIZE; + } +#endif + + for (i = 0, j = 0; i < len; ++i) { + n = wcrtomb(dst+j, str[i], &mbs); + if (n == -1) goto err; + j += n; + if (buflen < j + MB_CUR_MAX) { + if (id != (iconv_t)-1) { + CONVERT2(buffer, &j, cw, offset); + } else { + nlen += 256; + BINC_RETC(NULL, *tostr, *blen, nlen); + dst = *tostr; buflen = *blen; + } + } + } + + n = wcrtomb(dst+j, L'\0', &mbs); + j += n - 1; /* don't count NUL at the end */ + *tolen = j; + + if (id != (iconv_t)-1) { + CONVERT2(buffer, &j, cw, offset); + CONVERT2(NULL, NULL, cw, offset); /* back to the initial state */ + *tolen = offset; + } + + error = 0; +err: + if (error) + *tolen = j; + *pdst = cw->bp1.c; + IC_RESET(); + + return error; +} + +static int +fe_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, + size_t *tolen, char **dst) +{ + return default_int2char(sp, str, len, cw, tolen, dst, + sp->conv.id[IC_FE_INT2CHAR]); +} + +static int +cs_int2char(SCR *sp, const CHAR_T * str, ssize_t len, CONVWIN *cw, + size_t *tolen, char **dst) +{ + return default_int2char(sp, str, len, cw, tolen, dst, + (iconv_t)-1); +} + +#endif + +/* + * conv_init -- + * Initialize the iconv environment. + * + * PUBLIC: void conv_init __P((SCR *, SCR *)); + */ +void +conv_init(SCR *orig, SCR *sp) +{ + int i; + + if (orig == NULL) + setlocale(LC_ALL, ""); + if (orig != NULL) + BCOPY(&orig->conv, &sp->conv, 1); +#ifdef USE_WIDECHAR + else { + char *ctype = setlocale(LC_CTYPE, NULL); + + /* + * XXX + * This hack fixes the libncursesw issue on FreeBSD. + */ + if (!strcmp(ctype, "ko_KR.CP949")) + setlocale(LC_CTYPE, "ko_KR.eucKR"); + else if (!strcmp(ctype, "zh_CN.GB2312")) + setlocale(LC_CTYPE, "zh_CN.eucCN"); + else if (!strcmp(ctype, "zh_CN.GBK")) + setlocale(LC_CTYPE, "zh_CN.GB18030"); + + /* + * Switch to 8bit mode if locale is C; + * LC_CTYPE should be reseted to C if unmatched. + */ + if (!strcmp(ctype, "C") || !strcmp(ctype, "POSIX")) { + sp->conv.sys2int = sp->conv.file2int = raw2int; + sp->conv.int2sys = sp->conv.int2file = int2raw; + sp->conv.input2int = raw2int; + } else { + sp->conv.sys2int = cs_char2int; + sp->conv.int2sys = cs_int2char; + sp->conv.file2int = fe_char2int; + sp->conv.int2file = fe_int2char; + sp->conv.input2int = ie_char2int; + } +#ifdef USE_ICONV + o_set(sp, O_INPUTENCODING, OS_STRDUP, codeset(), 0); +#endif + } +#endif + + /* iconv descriptors must be distinct to screens. */ + for (i = 0; i <= IC_IE_TO_UTF16; ++i) + sp->conv.id[i] = (iconv_t)-1; +#ifdef USE_ICONV + conv_enc(sp, O_INPUTENCODING, 0); +#endif +} + +/* + * conv_enc -- + * Convert file/input encoding. + * + * PUBLIC: int conv_enc __P((SCR *, int, char *)); + */ +int +conv_enc(SCR *sp, int option, char *enc) +{ +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + iconv_t *c2w, *w2c; + + switch (option) { + case O_FILEENCODING: + c2w = sp->conv.id + IC_FE_CHAR2INT; + w2c = sp->conv.id + IC_FE_INT2CHAR; + if (!enc) enc = O_STR(sp, O_FILEENCODING); + if (*c2w != (iconv_t)-1) + iconv_close(*c2w); + if (*w2c != (iconv_t)-1) + iconv_close(*w2c); + if (strcasecmp(codeset(), enc)) { + if ((*c2w = iconv_open(codeset(), enc)) == (iconv_t)-1) + goto err; + if ((*w2c = iconv_open(enc, codeset())) == (iconv_t)-1) + goto err; + } else *c2w = *w2c = (iconv_t)-1; + break; + case O_INPUTENCODING: + c2w = sp->conv.id + IC_IE_CHAR2INT; + w2c = sp->conv.id + IC_IE_TO_UTF16; + if (!enc) enc = O_STR(sp, O_INPUTENCODING); + if (*c2w != (iconv_t)-1) + iconv_close(*c2w); + if (*w2c != (iconv_t)-1) + iconv_close(*w2c); + if (strcasecmp(codeset(), enc)) { + if ((*c2w = iconv_open(codeset(), enc)) == (iconv_t)-1) + goto err; + } else *c2w = (iconv_t)-1; + /* UTF-16 can not be locale and can not be inputed. */ + if ((*w2c = iconv_open("utf-16be", enc)) == (iconv_t)-1) + goto err; + break; + } + + F_CLR(sp, SC_CONV_ERROR); + F_SET(sp, SC_SCR_REFORMAT); + + return 0; +err: +#endif + switch (option) { + case O_FILEENCODING: + msgq(sp, M_ERR, + "321|File encoding conversion not supported"); + break; + case O_INPUTENCODING: + msgq(sp, M_ERR, + "322|Input encoding conversion not supported"); + break; + } + return 1; +} + +/* + * conv_end -- + * Close the iconv descriptors, release the buffer. + * + * PUBLIC: void conv_end __P((SCR *)); + */ +void +conv_end(SCR *sp) +{ +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + int i; + for (i = 0; i <= IC_IE_TO_UTF16; ++i) + if (sp->conv.id[i] != (iconv_t)-1) + iconv_close(sp->conv.id[i]); + if (sp->cw.bp1.c != NULL) + free(sp->cw.bp1.c); +#endif +} diff --git a/contrib/nvi/common/conv.h b/contrib/nvi/common/conv.h new file mode 100644 index 0000000..b17c3bb --- /dev/null +++ b/contrib/nvi/common/conv.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * Copyright (c) 2011, 2012 + * Zhihao Yuan. All rights reserved. + * + * See the LICENSE file for redistribution information. + * + * $Id: conv.h,v 2.32 2013/03/11 01:20:53 zy Exp $ + */ + +#ifdef USE_ICONV +#include <iconv.h> +#ifdef ICONV_TRADITIONAL +typedef char ** iconv_src_t; +#else +typedef char const ** iconv_src_t; +#endif +#else +typedef int iconv_t; +#endif + +/* + * XXX + * We can not use MB_CUR_MAX here, since UTF-8 may report it as 6, but + * a sequence longer than 4 is deprecated by RFC 3629. + */ +#define KEY_NEEDSWIDE(sp, ch) \ + (INTISWIDE(ch) && KEY_LEN(sp, ch) <= 4) +#define KEY_COL(sp, ch) \ + (KEY_NEEDSWIDE(sp, ch) ? CHAR_WIDTH(sp, ch) : KEY_LEN(sp, ch)) + +enum { IC_FE_CHAR2INT, IC_FE_INT2CHAR, IC_IE_CHAR2INT, IC_IE_TO_UTF16 }; + +struct _conv_win { + union { + char *c; + CHAR_T *wc; + } bp1; + size_t blen1; +}; + +typedef int (*char2wchar_t) + (SCR *, const char *, ssize_t, struct _conv_win *, size_t *, CHAR_T **); +typedef int (*wchar2char_t) + (SCR *, const CHAR_T *, ssize_t, struct _conv_win *, size_t *, char **); + +struct _conv { + char2wchar_t sys2int; + wchar2char_t int2sys; + char2wchar_t file2int; + wchar2char_t int2file; + char2wchar_t input2int; + iconv_t id[IC_IE_TO_UTF16 + 1]; +}; diff --git a/contrib/nvi/common/cut.c b/contrib/nvi/common/cut.c index faceecd..11db42f 100644 --- a/contrib/nvi/common/cut.c +++ b/contrib/nvi/common/cut.c @@ -10,7 +10,7 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)cut.c 10.10 (Berkeley) 9/15/96"; +static const char sccsid[] = "$Id: cut.c,v 10.12 2012/02/11 15:52:33 zy Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -64,14 +64,15 @@ static void cb_rotate __P((SCR *)); * PUBLIC: int cut __P((SCR *, CHAR_T *, MARK *, MARK *, int)); */ int -cut(sp, namep, fm, tm, flags) - SCR *sp; - CHAR_T *namep; - MARK *fm, *tm; - int flags; +cut( + SCR *sp, + CHAR_T *namep, + MARK *fm, + MARK *tm, + int flags) { CB *cbp; - CHAR_T name; + CHAR_T name = '\0'; recno_t lno; int append, copy_one, copy_def; @@ -100,19 +101,19 @@ cut(sp, namep, fm, tm, flags) append = copy_one = copy_def = 0; if (namep != NULL) { name = *namep; - if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) && - (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) { + if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) && + (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) { copy_one = 1; cb_rotate(sp); } - if ((append = isupper(name)) == 1) { + if ((append = isupper(name))) { if (!copy_one) copy_def = 1; name = tolower(name); } namecb: CBNAME(sp, cbp, name); - } else if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) && - (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) { + } else if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) && + (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) { name = '1'; cb_rotate(sp); goto namecb; @@ -127,26 +128,25 @@ copyloop: if (cbp == NULL) { CALLOC_RET(sp, cbp, CB *, 1, sizeof(CB)); cbp->name = name; - CIRCLEQ_INIT(&cbp->textq); - LIST_INSERT_HEAD(&sp->gp->cutq, cbp, q); + TAILQ_INIT(cbp->textq); + SLIST_INSERT_HEAD(sp->gp->cutq, cbp, q); } else if (!append) { - text_lfree(&cbp->textq); + text_lfree(cbp->textq); cbp->len = 0; cbp->flags = 0; } -#define ENTIRE_LINE 0 /* In line mode, it's pretty easy, just cut the lines. */ if (LF_ISSET(CUT_LINEMODE)) { cbp->flags |= CB_LMODE; for (lno = fm->lno; lno <= tm->lno; ++lno) - if (cut_line(sp, lno, 0, 0, cbp)) + if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp)) goto cut_line_err; } else { /* - * Get the first line. A length of 0 causes cut_line - * to cut from the MARK to the end of the line. + * Get the first line. A length of ENTIRE_LINE causes + * cut_line to cut from the MARK to the end of the line. */ if (cut_line(sp, fm->lno, fm->cno, fm->lno != tm->lno ? ENTIRE_LINE : (tm->cno - fm->cno) + 1, cbp)) @@ -180,7 +180,7 @@ copyloop: return (0); cut_line_err: - text_lfree(&cbp->textq); + text_lfree(cbp->textq); cbp->len = 0; cbp->flags = 0; return (1); @@ -191,45 +191,29 @@ cut_line_err: * Rotate the numbered buffers up one. */ static void -cb_rotate(sp) - SCR *sp; +cb_rotate(SCR *sp) { - CB *cbp, *del_cbp; + CB *cbp, *del_cbp = NULL, *pre_cbp = NULL; - del_cbp = NULL; - for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next) + SLIST_FOREACH(cbp, sp->gp->cutq, q) { switch(cbp->name) { - case '1': - cbp->name = '2'; - break; - case '2': - cbp->name = '3'; - break; - case '3': - cbp->name = '4'; - break; - case '4': - cbp->name = '5'; - break; - case '5': - cbp->name = '6'; - break; - case '6': - cbp->name = '7'; - break; - case '7': - cbp->name = '8'; - break; - case '8': - cbp->name = '9'; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': + cbp->name += 1; break; case '9': + if (cbp == SLIST_FIRST(sp->gp->cutq)) + SLIST_REMOVE_HEAD(sp->gp->cutq, q); + else + SLIST_REMOVE_AFTER(pre_cbp, q); del_cbp = cbp; break; } + pre_cbp = cbp; + } if (del_cbp != NULL) { - LIST_REMOVE(del_cbp, q); - text_lfree(&del_cbp->textq); + text_lfree(del_cbp->textq); free(del_cbp); } } @@ -241,15 +225,16 @@ cb_rotate(sp) * PUBLIC: int cut_line __P((SCR *, recno_t, size_t, size_t, CB *)); */ int -cut_line(sp, lno, fcno, clen, cbp) - SCR *sp; - recno_t lno; - size_t fcno, clen; - CB *cbp; +cut_line( + SCR *sp, + recno_t lno, + size_t fcno, + size_t clen, + CB *cbp) { TEXT *tp; size_t len; - char *p; + CHAR_T *p; /* Get the line. */ if (db_get(sp, lno, DBG_FATAL, &p, &len)) @@ -264,14 +249,14 @@ cut_line(sp, lno, fcno, clen, cbp) * copy the portion we want, and reset the TEXT length. */ if (len != 0) { - if (clen == 0) + if (clen == ENTIRE_LINE) clen = len - fcno; - memcpy(tp->lb, p + fcno, clen); + MEMCPY(tp->lb, p + fcno, clen); tp->len = clen; } /* Append to the end of the cut buffer. */ - CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q); + TAILQ_INSERT_TAIL(cbp->textq, tp, q); cbp->len += tp->len; return (0); @@ -284,36 +269,36 @@ cut_line(sp, lno, fcno, clen, cbp) * PUBLIC: void cut_close __P((GS *)); */ void -cut_close(gp) - GS *gp; +cut_close(GS *gp) { CB *cbp; /* Free cut buffer list. */ - while ((cbp = gp->cutq.lh_first) != NULL) { - if (cbp->textq.cqh_first != (void *)&cbp->textq) - text_lfree(&cbp->textq); - LIST_REMOVE(cbp, q); + while ((cbp = SLIST_FIRST(gp->cutq)) != NULL) { + if (!TAILQ_EMPTY(cbp->textq)) + text_lfree(cbp->textq); + SLIST_REMOVE_HEAD(gp->cutq, q); free(cbp); } /* Free default cut storage. */ cbp = &gp->dcb_store; - if (cbp->textq.cqh_first != (void *)&cbp->textq) - text_lfree(&cbp->textq); + if (!TAILQ_EMPTY(cbp->textq)) + text_lfree(cbp->textq); } /* * text_init -- * Allocate a new TEXT structure. * - * PUBLIC: TEXT *text_init __P((SCR *, const char *, size_t, size_t)); + * PUBLIC: TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t)); */ TEXT * -text_init(sp, p, len, total_len) - SCR *sp; - const char *p; - size_t len, total_len; +text_init( + SCR *sp, + const CHAR_T *p, + size_t len, + size_t total_len) { TEXT *tp; @@ -321,14 +306,14 @@ text_init(sp, p, len, total_len) if (tp == NULL) return (NULL); /* ANSI C doesn't define a call to malloc(3) for 0 bytes. */ - if ((tp->lb_len = total_len) != 0) { + if ((tp->lb_len = total_len * sizeof(CHAR_T)) != 0) { MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len); if (tp->lb == NULL) { free(tp); return (NULL); } if (p != NULL && len != 0) - memcpy(tp->lb, p, len); + MEMCPY(tp->lb, p, len); } tp->len = len; return (tp); @@ -341,13 +326,12 @@ text_init(sp, p, len, total_len) * PUBLIC: void text_lfree __P((TEXTH *)); */ void -text_lfree(headp) - TEXTH *headp; +text_lfree(TEXTH *headp) { TEXT *tp; - while ((tp = headp->cqh_first) != (void *)headp) { - CIRCLEQ_REMOVE(headp, tp, q); + while ((tp = TAILQ_FIRST(headp)) != NULL) { + TAILQ_REMOVE(headp, tp, q); text_free(tp); } } @@ -359,8 +343,7 @@ text_lfree(headp) * PUBLIC: void text_free __P((TEXT *)); */ void -text_free(tp) - TEXT *tp; +text_free(TEXT *tp) { if (tp->lb != NULL) free(tp->lb); diff --git a/contrib/nvi/common/cut.h b/contrib/nvi/common/cut.h index 43f3ca8..30e9350 100644 --- a/contrib/nvi/common/cut.h +++ b/contrib/nvi/common/cut.h @@ -6,16 +6,17 @@ * * See the LICENSE file for redistribution information. * - * @(#)cut.h 10.5 (Berkeley) 4/3/96 + * $Id: cut.h,v 10.10 2012/02/11 15:52:33 zy Exp $ */ typedef struct _texth TEXTH; /* TEXT list head structure. */ -CIRCLEQ_HEAD(_texth, _text); +TAILQ_HEAD(_texth, _text); /* Cut buffers. */ struct _cb { - LIST_ENTRY(_cb) q; /* Linked list of cut buffers. */ - TEXTH textq; /* Linked list of TEXT structures. */ + SLIST_ENTRY(_cb) q; /* Linked list of cut buffers. */ + TEXTH textq[1]; /* Linked list of TEXT structures. */ + /* XXXX Needed ? Can non ascii-chars be cut buffer names ? */ CHAR_T name; /* Cut buffer name. */ size_t len; /* Total length of cut text. */ @@ -25,13 +26,15 @@ struct _cb { /* Lines/blocks of text. */ struct _text { /* Text: a linked list of lines. */ - CIRCLEQ_ENTRY(_text) q; /* Linked list of text structures. */ - char *lb; /* Line buffer. */ + TAILQ_ENTRY(_text) q; /* Linked list of text structures. */ + CHAR_T *lb; /* Line buffer. */ size_t lb_len; /* Line buffer length. */ size_t len; /* Line length. */ /* These fields are used by the vi text input routine. */ recno_t lno; /* 1-N: file line. */ + +#define ENTIRE_LINE ((size_t)-1) /* cno: end of the line. */ size_t cno; /* 0-N: file character in line. */ size_t ai; /* 0-N: autoindent bytes. */ size_t insert; /* 0-N: bytes to insert (push). */ @@ -65,8 +68,7 @@ struct _text { /* Text: a linked list of lines. */ #define CBNAME(sp, cbp, nch) { \ CHAR_T L__name; \ L__name = isupper(nch) ? tolower(nch) : (nch); \ - for (cbp = sp->gp->cutq.lh_first; \ - cbp != NULL; cbp = cbp->q.le_next) \ + SLIST_FOREACH(cbp, sp->gp->cutq, q) \ if (cbp->name == L__name) \ break; \ } diff --git a/contrib/nvi/common/delete.c b/contrib/nvi/common/delete.c index 001788f..bb476c0 100644 --- a/contrib/nvi/common/delete.c +++ b/contrib/nvi/common/delete.c @@ -10,11 +10,12 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)delete.c 10.12 (Berkeley) 10/23/96"; +static const char sccsid[] = "$Id: delete.c,v 10.18 2012/02/11 15:52:33 zy Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> +#include <sys/time.h> #include <bitstring.h> #include <errno.h> @@ -32,14 +33,15 @@ static const char sccsid[] = "@(#)delete.c 10.12 (Berkeley) 10/23/96"; * PUBLIC: int del __P((SCR *, MARK *, MARK *, int)); */ int -del(sp, fm, tm, lmode) - SCR *sp; - MARK *fm, *tm; - int lmode; +del( + SCR *sp, + MARK *fm, + MARK *tm, + int lmode) { recno_t lno; size_t blen, len, nlen, tlen; - char *bp, *p; + CHAR_T *bp, *p; int eof, rval; bp = NULL; @@ -66,7 +68,7 @@ del(sp, fm, tm, lmode) if (tm->lno == lno) { if (db_get(sp, lno, DBG_FATAL, &p, &len)) return (1); - eof = tm->cno >= len ? 1 : 0; + eof = tm->cno != ENTIRE_LINE && tm->cno >= len ? 1 : 0; } else eof = 1; if (eof) { @@ -80,8 +82,8 @@ del(sp, fm, tm, lmode) } if (db_get(sp, fm->lno, DBG_FATAL, &p, &len)) return (1); - GET_SPACE_RET(sp, bp, blen, fm->cno); - memcpy(bp, p, fm->cno); + GET_SPACE_RETW(sp, bp, blen, fm->cno); + MEMCPY(bp, p, fm->cno); if (db_set(sp, fm->lno, bp, fm->cno)) return (1); goto done; @@ -92,10 +94,11 @@ del(sp, fm, tm, lmode) if (tm->lno == fm->lno) { if (db_get(sp, fm->lno, DBG_FATAL, &p, &len)) return (1); - GET_SPACE_RET(sp, bp, blen, len); + GET_SPACE_RETW(sp, bp, blen, len); if (fm->cno != 0) - memcpy(bp, p, fm->cno); - memcpy(bp + fm->cno, p + (tm->cno + 1), len - (tm->cno + 1)); + MEMCPY(bp, p, fm->cno); + MEMCPY(bp + fm->cno, p + (tm->cno + 1), + len - (tm->cno + 1)); if (db_set(sp, fm->lno, bp, len - ((tm->cno - fm->cno) + 1))) goto err; @@ -110,8 +113,8 @@ del(sp, fm, tm, lmode) if ((tlen = fm->cno) != 0) { if (db_get(sp, fm->lno, DBG_FATAL, &p, NULL)) return (1); - GET_SPACE_RET(sp, bp, blen, tlen + 256); - memcpy(bp, p, tlen); + GET_SPACE_RETW(sp, bp, blen, tlen + 256); + MEMCPY(bp, p, tlen); } /* Copy the end partial line into place. */ @@ -130,11 +133,11 @@ del(sp, fm, tm, lmode) goto err; } if (tlen == 0) { - GET_SPACE_RET(sp, bp, blen, nlen); + GET_SPACE_RETW(sp, bp, blen, nlen); } else - ADD_SPACE_RET(sp, bp, blen, nlen); + ADD_SPACE_RETW(sp, bp, blen, nlen); - memcpy(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1)); + MEMCPY(bp + tlen, p + (tm->cno + 1), len - (tm->cno + 1)); tlen += len - (tm->cno + 1); } @@ -155,6 +158,6 @@ done: rval = 0; if (0) err: rval = 1; if (bp != NULL) - FREE_SPACE(sp, bp, blen); + FREE_SPACEW(sp, bp, blen); return (rval); } diff --git a/contrib/nvi/common/encoding.c b/contrib/nvi/common/encoding.c new file mode 100644 index 0000000..6de509e --- /dev/null +++ b/contrib/nvi/common/encoding.c @@ -0,0 +1,230 @@ +/*- + * Copyright (c) 2011, 2012 + * Zhihao Yuan. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#ifndef lint +static const char sccsid[] = "$Id: encoding.c,v 1.4 2011/12/13 19:40:52 zy Exp $"; +#endif /* not lint */ + +#include <sys/types.h> + +int looks_utf8 __P((const char *, size_t)); +int looks_utf16 __P((const char *, size_t)); +int decode_utf8 __P((const char *)); +int decode_utf16 __P((const char *, int)); + +#define F 0 /* character never appears in text */ +#define T 1 /* character appears in plain ASCII text */ +#define I 2 /* character appears in ISO-8859 text */ +#define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */ + +static char text_chars[256] = { + /* BEL BS HT LF FF CR */ + F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */ + /* ESC */ + F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */ + T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */ + /* NEL */ + X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */ + X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */ + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */ +}; + +/* + * looks_utf8 -- + * Decide whether some text looks like UTF-8. Returns: + * + * -1: invalid UTF-8 + * 0: uses odd control characters, so doesn't look like text + * 1: 7-bit text + * 2: definitely UTF-8 text (valid high-bit set bytes) + * + * Based on RFC 3629. UTF-8 with BOM is not accepted. + * + * PUBLIC: int looks_utf8 __P((const char *, size_t)); + */ +int +looks_utf8(const char *ibuf, size_t nbytes) +{ + const u_char *buf = (u_char *)ibuf; + size_t i; + int n; + int gotone = 0, ctrl = 0; + + for (i = 0; i < nbytes; i++) { + if ((buf[i] & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */ + /* + * Even if the whole file is valid UTF-8 sequences, + * still reject it if it uses weird control characters. + */ + + if (text_chars[buf[i]] != T) + ctrl = 1; + } else if ((buf[i] & 0x40) == 0) { /* 10xxxxxx never 1st byte */ + return -1; + } else { /* 11xxxxxx begins UTF-8 */ + int following; + + if ((buf[i] & 0x20) == 0) /* 110xxxxx */ + if (buf[i] > 0xC1) /* C0, C1 */ + following = 1; + else return -1; + else if ((buf[i] & 0x10) == 0) /* 1110xxxx */ + following = 2; + else if ((buf[i] & 0x08) == 0) /* 11110xxx */ + if (buf[i] < 0xF5) + following = 3; + else return -1; /* F5, F6, F7 */ + else + return -1; /* F8~FF */ + + for (n = 0; n < following; n++) { + i++; + if (i >= nbytes) + goto done; + + if (buf[i] & 0x40) /* 10xxxxxx */ + return -1; + } + + gotone = 1; + } + } +done: + return ctrl ? 0 : (gotone ? 2 : 1); +} + +/* + * looks_utf16 -- + * Decide whether some text looks like UTF-16. Returns: + * + * 0: invalid UTF-16 + * 1: Little-endian UTF-16 + * 2: Big-endian UTF-16 + * + * PUBLIC: int looks_utf16 __P((const char *, size_t)); + */ +int +looks_utf16(const char *ibuf, size_t nbytes) +{ + const u_char *buf = (u_char *)ibuf; + int bigend; + size_t i; + unsigned int c; + int bom; + int following = 0; + + if (nbytes < 2) + return 0; + + bom = buf[0] << 8 ^ buf[1]; + if (bom == 0xFFFE) + bigend = 0; + else if (bom == 0xFEFF) + bigend = 1; + else + return 0; + + for (i = 2; i + 1 < nbytes; i += 2) { + if (bigend) + c = buf[i] << 8 ^ buf[i + 1]; + else + c = buf[i] ^ buf[i + 1] << 8; + + if (!following) + if (c < 0xD800 || c > 0xDFFF) + if (c < 128 && text_chars[c] != T) + return 0; + else + following = 0; + else if (c > 0xDBFF) + return 0; + else { + following = 1; + continue; + } + else if (c < 0xDC00 || c > 0xDFFF) + return 0; + } + + return 1 + bigend; +} + +#undef F +#undef T +#undef I +#undef X + +/* + * decode_utf8 -- + * Decode a UTF-8 character from byte string to Unicode. + * Returns -1 if the first byte is a not UTF-8 leader. + * + * Based on RFC 3629, but without error detection. + * + * PUBLIC: int decode_utf8 __P((const char *)); + */ +int decode_utf8(const char *ibuf) { + const u_char *buf = (u_char *)ibuf; + int u = -1; + + if ((buf[0] & 0x80) == 0) + u = buf[0]; + else if ((buf[0] & 0x40) == 0); + else { + if ((buf[0] & 0x20) == 0) + u = (buf[0] ^ 0xC0) << 6 ^ (buf[1] ^ 0x80); + else if ((buf[0] & 0x10) == 0) + u = (buf[0] ^ 0xE0) << 12 ^ (buf[1] ^ 0x80) << 6 + ^ (buf[2] ^ 0x80); + else if (((buf[0] & 0x08) == 0)) + u = (buf[0] ^ 0xF0) << 18 ^ (buf[1] ^ 0x80) << 12 + ^ (buf[2] ^ 0x80) << 6 ^ (buf[3] ^ 0x80); + } + return u; +} + +/* + * decode_utf16 -- + * Decode a UTF-16 character from byte string to Unicode. + * Returns -1 if the first unsigned integer is invalid. + * + * No error detection on supplementary bytes. + * + * PUBLIC: int decode_utf16 __P((const char *, int)); + */ +int decode_utf16(const char* ibuf, int bigend) { + const u_char *buf = (u_char *)ibuf; + int u = -1; + unsigned int w1, w2; + + if (bigend) + w1 = buf[0] << 8 ^ buf[1]; + else + w1 = buf[0] ^ buf[1] << 8; + + if (w1 < 0xD800 || w1 > 0xDFFF) + u = w1; + else if (w1 > 0xDBFF); + else { + if (bigend) + w2 = buf[2] << 8 ^ buf[3]; + else + w2 = buf[2] ^ buf[3] << 8; + u = ((w1 ^ 0xD800) << 10 ^ (w2 ^ 0xDC00)) + 0x10000; + } + return u; +} diff --git a/contrib/nvi/common/exf.c b/contrib/nvi/common/exf.c index b0c438d..6579ab2 100644 --- a/contrib/nvi/common/exf.c +++ b/contrib/nvi/common/exf.c @@ -5,23 +5,18 @@ * Keith Bostic. All rights reserved. * * See the LICENSE file for redistribution information. - * */ #include "config.h" #ifndef lint -#if 0 -static const char sccsid[] = "@(#)exf.c 10.49 (Berkeley) 10/10/96"; -#endif -static const char rcsid[] = - "$FreeBSD$"; +static const char sccsid[] = "$Id: exf.c,v 10.62 2013/07/01 23:28:13 zy Exp $"; #endif /* not lint */ -#include <sys/param.h> -#include <sys/types.h> /* XXX: param.h may not have included types.h */ +#include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> +#include <sys/time.h> /* * We include <sys/file.h>, because the flock(2) and open(2) #defines @@ -44,6 +39,7 @@ static const char rcsid[] = static int file_backup __P((SCR *, char *, char *)); static void file_cinit __P((SCR *)); +static void file_encinit __P((SCR *)); static void file_comment __P((SCR *)); static int file_spath __P((SCR *, FREF *, struct stat *, int *)); @@ -60,12 +56,12 @@ static int file_spath __P((SCR *, FREF *, struct stat *, int *)); * vi now remembers the last location in any file that it has ever edited, * not just the previously edited file. * - * PUBLIC: FREF *file_add __P((SCR *, CHAR_T *)); + * PUBLIC: FREF *file_add __P((SCR *, char *)); */ FREF * -file_add(sp, name) - SCR *sp; - CHAR_T *name; +file_add( + SCR *sp, + char *name) { GS *gp; FREF *frp, *tfrp; @@ -81,15 +77,12 @@ file_add(sp, name) */ gp = sp->gp; if (name != NULL) - for (frp = gp->frefq.cqh_first; - frp != (FREF *)&gp->frefq; frp = frp->q.cqe_next) { + TAILQ_FOREACH_SAFE(frp, gp->frefq, q, tfrp) { if (frp->name == NULL) { - tfrp = frp->q.cqe_next; - CIRCLEQ_REMOVE(&gp->frefq, frp, q); + TAILQ_REMOVE(gp->frefq, frp, q); if (frp->name != NULL) free(frp->name); free(frp); - frp = tfrp; continue; } if (!strcmp(frp->name, name)) @@ -114,7 +107,7 @@ file_add(sp, name) } /* Append into the chain of file names. */ - CIRCLEQ_INSERT_TAIL(&gp->frefq, frp, q); + TAILQ_INSERT_TAIL(gp->frefq, frp, q); return (frp); } @@ -128,18 +121,18 @@ file_add(sp, name) * PUBLIC: int file_init __P((SCR *, FREF *, char *, int)); */ int -file_init(sp, frp, rcv_name, flags) - SCR *sp; - FREF *frp; - char *rcv_name; - int flags; +file_init( + SCR *sp, + FREF *frp, + char *rcv_name, + int flags) { EXF *ep; - RECNOINFO oinfo; + RECNOINFO oinfo = { 0 }; struct stat sb; size_t psize; int fd, exists, open_err, readonly; - char *oname, tname[MAXPATHLEN]; + char *oname, *tname; open_err = readonly = 0; @@ -169,7 +162,7 @@ file_init(sp, frp, rcv_name, flags) */ CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF)); ep->c_lno = ep->c_nlines = OOBLNO; - ep->rcv_fd = ep->fcntl_fd = -1; + ep->rcv_fd = -1; F_SET(ep, F_FIRSTMODIFY); /* @@ -187,52 +180,56 @@ file_init(sp, frp, rcv_name, flags) */ oname = frp->name; if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) { - if (opts_empty(sp, O_TMP_DIRECTORY, 0)) + struct stat sb; + + if (opts_empty(sp, O_TMPDIR, 0)) + goto err; + if ((tname = + join(O_STR(sp, O_TMPDIR), "vi.XXXXXXXXXX")) == NULL) { + msgq(sp, M_SYSERR, NULL); goto err; - (void)snprintf(tname, sizeof(tname), - "%s/vi.XXXXXXXXXX", O_STR(sp, O_TMP_DIRECTORY)); - if ((fd = mkstemp(tname)) == -1) { + } + if ((fd = mkstemp(tname)) == -1 || fstat(fd, &sb)) { + free(tname); msgq(sp, M_SYSERR, "237|Unable to create temporary file"); goto err; } (void)close(fd); - if (frp->name == NULL) + frp->tname = tname; + if (frp->name == NULL) { F_SET(frp, FR_TMPFILE); - if ((frp->tname = strdup(tname)) == NULL || - frp->name == NULL && (frp->name = strdup(tname)) == NULL) { - if (frp->tname != NULL) - free(frp->tname); - msgq(sp, M_SYSERR, NULL); - (void)unlink(tname); - goto err; + if ((frp->name = strdup(tname)) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } } oname = frp->tname; psize = 1024; if (!LF_ISSET(FS_OPENERR)) F_SET(frp, FR_NEWFILE); - time(&ep->mtime); + ep->mtim = sb.st_mtimespec; } else { /* * XXX * A seat of the pants calculation: try to keep the file in - * 15 pages or less. Don't use a page size larger than 10K + * 15 pages or less. Don't use a page size larger than 16K * (vi should have good locality) or smaller than 1K. */ psize = ((sb.st_size / 15) + 1023) / 1024; - if (psize > 10) - psize = 10; + if (psize > 16) + psize = 16; if (psize == 0) psize = 1; - psize *= 1024; + psize = p2roundup(psize) << 10; F_SET(ep, F_DEVSET); ep->mdev = sb.st_dev; ep->minode = sb.st_ino; - ep->mtime = sb.st_mtime; + ep->mtim = sb.st_mtimespec; if (!S_ISREG(sb.st_mode)) msgq_str(sp, M_ERR, oname, @@ -240,7 +237,6 @@ file_init(sp, frp, rcv_name, flags) } /* Set up recovery. */ - memset(&oinfo, 0, sizeof(RECNOINFO)); oinfo.bval = '\n'; /* Always set. */ oinfo.psize = psize; oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0; @@ -338,8 +334,7 @@ file_init(sp, frp, rcv_name, flags) * an error. */ if (rcv_name == NULL) - switch (file_lock(sp, oname, - &ep->fcntl_fd, ep->db->fd(ep->db), 0)) { + switch (file_lock(sp, oname, ep->db->fd(ep->db), 0)) { case LOCK_FAILED: F_SET(frp, FR_UNLOCKED); break; @@ -396,9 +391,9 @@ file_init(sp, frp, rcv_name, flags) * probably isn't a problem for vi when it's running standalone. */ if (readonly || F_ISSET(sp, SC_READONLY) || - !F_ISSET(frp, FR_NEWFILE) && + (!F_ISSET(frp, FR_NEWFILE) && (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) || - access(frp->name, W_OK))) + access(frp->name, W_OK)))) O_SET(sp, O_READONLY); else O_CLR(sp, O_READONLY); @@ -408,6 +403,9 @@ file_init(sp, frp, rcv_name, flags) sp->ep = ep; sp->frp = frp; + /* Detect and set the file encoding */ + file_encinit(sp); + /* Set the initial cursor position, queue initial command. */ file_cinit(sp); @@ -446,16 +444,16 @@ oerr: if (F_ISSET(ep, F_RCV_ON)) * try and open. */ static int -file_spath(sp, frp, sbp, existsp) - SCR *sp; - FREF *frp; - struct stat *sbp; - int *existsp; +file_spath( + SCR *sp, + FREF *frp, + struct stat *sbp, + int *existsp) { - CHAR_T savech; + int savech; size_t len; int found; - char *name, *p, *t, path[MAXPATHLEN]; + char *name, *p, *t, *path; /* * If the name is NULL or an explicit reference (i.e., the first @@ -466,8 +464,8 @@ file_spath(sp, frp, sbp, existsp) *existsp = 0; return (0); } - if (name[0] == '/' || name[0] == '.' && - (name[1] == '/' || name[1] == '.' && name[2] == '/')) { + if (name[0] == '/' || (name[0] == '.' && + (name[1] == '/' || (name[1] == '.' && name[2] == '/')))) { *existsp = !stat(name, sbp); return (0); } @@ -481,16 +479,24 @@ file_spath(sp, frp, sbp, existsp) /* Try the O_PATH option values. */ for (found = 0, p = t = O_STR(sp, O_PATH);; ++p) if (*p == ':' || *p == '\0') { - if (t < p - 1) { + /* + * Ignore the empty strings and ".", since we've already + * tried the current directory. + */ + if (t < p && (p - t != 1 || *t != '.')) { savech = *p; *p = '\0'; - len = snprintf(path, - sizeof(path), "%s/%s", t, name); + if ((path = join(t, name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + break; + } + len = strlen(path); *p = savech; if (!stat(path, sbp)) { found = 1; break; } + free(path); } t = p + 1; if (*p == '\0') @@ -499,10 +505,8 @@ file_spath(sp, frp, sbp, existsp) /* If we found it, build a new pathname and discard the old one. */ if (found) { - MALLOC_RET(sp, p, char *, len + 1); - memcpy(p, path, len + 1); free(frp->name); - frp->name = p; + frp->name = path; } *existsp = found; return (0); @@ -513,13 +517,14 @@ file_spath(sp, frp, sbp, existsp) * Set up the initial cursor position. */ static void -file_cinit(sp) - SCR *sp; +file_cinit(SCR *sp) { GS *gp; MARK m; size_t len; int nb; + CHAR_T *wp; + size_t wlen; /* Set some basic defaults. */ sp->lno = 1; @@ -553,8 +558,9 @@ file_cinit(sp) sp->lno = 1; sp->cno = 0; } - if (ex_run_str(sp, - "-c option", gp->c_option, strlen(gp->c_option), 1, 1)) + CHAR2INT(sp, gp->c_option, strlen(gp->c_option) + 1, + wp, wlen); + if (ex_run_str(sp, "-c option", wp, wlen - 1, 1, 1)) return; gp->c_option = NULL; } else if (F_ISSET(sp, SC_EX)) { @@ -622,10 +628,10 @@ file_cinit(sp) * PUBLIC: int file_end __P((SCR *, EXF *, int)); */ int -file_end(sp, ep, force) - SCR *sp; - EXF *ep; - int force; +file_end( + SCR *sp, + EXF *ep, + int force) { FREF *frp; @@ -670,7 +676,7 @@ file_end(sp, ep, force) free(frp->tname); frp->tname = NULL; if (F_ISSET(frp, FR_TMPFILE)) { - CIRCLEQ_REMOVE(&sp->gp->frefq, frp, q); + TAILQ_REMOVE(sp->gp->frefq, frp, q); if (frp->name != NULL) free(frp->name); free(frp); @@ -712,14 +718,14 @@ file_end(sp, ep, force) if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath)) msgq_str(sp, M_SYSERR, ep->rcv_mpath, "243|%s: remove"); } - if (ep->fcntl_fd != -1) - (void)close(ep->fcntl_fd); if (ep->rcv_fd != -1) (void)close(ep->rcv_fd); if (ep->rcv_path != NULL) free(ep->rcv_path); if (ep->rcv_mpath != NULL) free(ep->rcv_mpath); + if (ep->c_blen > 0) + free(ep->c_lp); free(ep); return (0); @@ -734,11 +740,12 @@ file_end(sp, ep, force) * PUBLIC: int file_write __P((SCR *, MARK *, MARK *, char *, int)); */ int -file_write(sp, fm, tm, name, flags) - SCR *sp; - MARK *fm, *tm; - char *name; - int flags; +file_write( + SCR *sp, + MARK *fm, + MARK *tm, + char *name, + int flags) { enum { NEWFILE, OLDFILE } mtype; struct stat sb; @@ -749,7 +756,7 @@ file_write(sp, fm, tm, name, flags) size_t len; u_long nlno, nch; int fd, nf, noname, oflags, rval; - char *p, *s, *t, buf[MAXPATHLEN + 64]; + char *p, *s, *t, buf[1024]; const char *msgstr; ep = sp->ep; @@ -812,9 +819,9 @@ file_write(sp, fm, tm, name, flags) mtype = NEWFILE; else { if (noname && !LF_ISSET(FS_FORCE | FS_APPEND) && - (F_ISSET(ep, F_DEVSET) && - (sb.st_dev != ep->mdev || sb.st_ino != ep->minode) || - sb.st_mtime != ep->mtime)) { + ((F_ISSET(ep, F_DEVSET) && + (sb.st_dev != ep->mdev || sb.st_ino != ep->minode)) || + timespeccmp(&sb.st_mtimespec, &ep->mtim, !=))) { msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE) ? "250|%s: file modified more recently than this copy; use ! to override" : "251|%s: file modified more recently than this copy"); @@ -873,25 +880,10 @@ success_open: SIGUNBLOCK; /* Try and get a lock. */ - if (!noname && file_lock(sp, NULL, NULL, fd, 0) == LOCK_UNAVAIL) + if (!noname && file_lock(sp, NULL, fd, 0) == LOCK_UNAVAIL) msgq_str(sp, M_ERR, name, "252|%s: write lock was unavailable"); -#if __linux__ - /* - * XXX - * In libc 4.5.x, fdopen(fd, "w") clears the O_APPEND flag (if set). - * This bug is fixed in libc 4.6.x. - * - * This code works around this problem for libc 4.5.x users. - * Note that this code is harmless if you're using libc 4.6.x. - */ - if (LF_ISSET(FS_APPEND) && lseek(fd, (off_t)0, SEEK_END) < 0) { - msgq(sp, M_SYSERR, name); - return (1); - } -#endif - /* * Use stdio for buffering. * @@ -925,13 +917,13 @@ success_open: */ if (noname) if (stat(name, &sb)) - time(&ep->mtime); + timepoint_system(&ep->mtim); else { F_SET(ep, F_DEVSET); ep->mdev = sb.st_dev; ep->minode = sb.st_ino; - ep->mtime = sb.st_mtime; + ep->mtim = sb.st_mtimespec; } /* @@ -1023,9 +1015,10 @@ success_open: * recreate the file. So, let's not risk it. */ static int -file_backup(sp, name, bname) - SCR *sp; - char *name, *bname; +file_backup( + SCR *sp, + char *name, + char *bname) { struct dirent *dp; struct stat sb; @@ -1035,6 +1028,10 @@ file_backup(sp, name, bname) size_t blen; int flags, maxnum, nr, num, nw, rfd, wfd, version; char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192]; + CHAR_T *wp; + size_t wlen; + size_t nlen; + char *d = NULL; rfd = wfd = -1; bp = estr = wfname = NULL; @@ -1064,15 +1061,20 @@ file_backup(sp, name, bname) * * Shell and file name expand the option's value. */ - argv_init(sp, &cmd); - ex_cinit(&cmd, 0, 0, 0, 0, 0, NULL); + ex_cinit(sp, &cmd, 0, 0, 0, 0, 0); if (bname[0] == 'N') { version = 1; ++bname; } else version = 0; - if (argv_exp2(sp, &cmd, bname, strlen(bname))) + CHAR2INT(sp, bname, strlen(bname), wp, wlen); + if ((wp = v_wstrdup(sp, wp, wlen)) == NULL) + return (1); + if (argv_exp2(sp, &cmd, wp, wlen)) { + free(wp); return (1); + } + free(wp); /* * 0 args: impossible. @@ -1095,9 +1097,13 @@ file_backup(sp, name, bname) * by one. */ if (version) { - GET_SPACE_GOTO(sp, bp, blen, cmd.argv[0]->len * 2 + 50); - for (t = bp, slash = NULL, - p = cmd.argv[0]->bp; p[0] != '\0'; *t++ = *p++) + GET_SPACE_GOTOC(sp, bp, blen, cmd.argv[0]->len * 2 + 50); + INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, + p, nlen); + d = strdup(p); + p = d; + for (t = bp, slash = NULL; + p[0] != '\0'; *t++ = *p++) if (p[0] == '%') { if (p[1] != '%') *t++ = '%'; @@ -1118,7 +1124,8 @@ file_backup(sp, name, bname) p = slash + 1; } if (dirp == NULL) { - estr = cmd.argv[0]->bp; + INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, + estr, nlen); goto err; } @@ -1132,7 +1139,8 @@ file_backup(sp, name, bname) wfname = bp; } else { bp = NULL; - wfname = cmd.argv[0]->bp; + INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, + wfname, nlen); } /* Open the backup file, avoiding lurkers. */ @@ -1192,22 +1200,69 @@ err: if (rfd != -1) } if (estr) msgq_str(sp, M_SYSERR, estr, "%s"); + if (d != NULL) + free(d); if (bp != NULL) FREE_SPACE(sp, bp, blen); return (1); } /* + * file_encinit -- + * Read the first line and set the O_FILEENCODING. + */ +static void +file_encinit(SCR *sp) +{ +#if defined(USE_WIDECHAR) && defined(USE_ICONV) + size_t len; + char *p; + size_t blen = 0; + char buf[4096]; /* not need to be '\0'-terminated */ + recno_t ln = 1; + EXF *ep; + + ep = sp->ep; + + while (!db_rget(sp, ln++, &p, &len)) { + if (blen + len > sizeof(buf)) + len = sizeof(buf) - blen; + memcpy(buf + blen, p, len); + blen += len; + if (blen == sizeof(buf)) + break; + else + buf[blen++] = '\n'; + } + + /* + * Detect UTF-8 and fallback to the locale/preset encoding. + * + * XXX + * A manually set O_FILEENCODING indicates the "fallback + * encoding", but UTF-8, which can be safely detected, is not + * inherited from the old screen. + */ + if (looks_utf8(buf, blen) > 1) + o_set(sp, O_FILEENCODING, OS_STRDUP, "utf-8", 0); + else if (!O_ISSET(sp, O_FILEENCODING) || + !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-8", 5)) + o_set(sp, O_FILEENCODING, OS_STRDUP, codeset(), 0); + + conv_enc(sp, O_FILEENCODING, 0); +#endif +} + +/* * file_comment -- * Skip the first comment. */ static void -file_comment(sp) - SCR *sp; +file_comment(SCR *sp) { recno_t lno; size_t len; - char *p; + CHAR_T *p; for (lno = 1; !db_get(sp, lno, 0, &p, &len) && len == 0; ++lno); if (p == NULL) @@ -1250,9 +1305,10 @@ file_comment(sp) * PUBLIC: int file_m1 __P((SCR *, int, int)); */ int -file_m1(sp, force, flags) - SCR *sp; - int force, flags; +file_m1( + SCR *sp, + int force, + int flags) { EXF *ep; @@ -1290,9 +1346,9 @@ file_m1(sp, force, flags) * PUBLIC: int file_m2 __P((SCR *, int)); */ int -file_m2(sp, force) - SCR *sp; - int force; +file_m2( + SCR *sp, + int force) { EXF *ep; @@ -1322,9 +1378,9 @@ file_m2(sp, force) * PUBLIC: int file_m3 __P((SCR *, int)); */ int -file_m3(sp, force) - SCR *sp; - int force; +file_m3( + SCR *sp, + int force) { EXF *ep; @@ -1358,9 +1414,9 @@ file_m3(sp, force) * PUBLIC: int file_aw __P((SCR *, int)); */ int -file_aw(sp, flags) - SCR *sp; - int flags; +file_aw( + SCR *sp, + int flags) { if (!F_ISSET(sp->ep, F_MODIFIED)) return (0); @@ -1419,9 +1475,9 @@ file_aw(sp, flags) * PUBLIC: void set_alt_name __P((SCR *, char *)); */ void -set_alt_name(sp, name) - SCR *sp; - char *name; +set_alt_name( + SCR *sp, + char *name) { if (sp->alt_name != NULL) free(sp->alt_name); @@ -1435,35 +1491,18 @@ set_alt_name(sp, name) * file_lock -- * Get an exclusive lock on a file. * - * XXX - * The default locking is flock(2) style, not fcntl(2). The latter is - * known to fail badly on some systems, and its only advantage is that - * it occasionally works over NFS. - * - * Furthermore, the semantics of fcntl(2) are wrong. The problems are - * two-fold: you can't close any file descriptor associated with the file - * without losing all of the locks, and you can't get an exclusive lock - * unless you have the file open for writing. Someone ought to be shot, - * but it's probably too late, they may already have reproduced. To get - * around these problems, nvi opens the files for writing when it can and - * acquires a second file descriptor when it can't. The recovery files - * are examples of the former, they're always opened for writing. The DB - * files can't be opened for writing because the semantics of DB are that - * files opened for writing are flushed back to disk when the DB session - * is ended. So, in that case we have to acquire an extra file descriptor. - * - * PUBLIC: lockr_t file_lock __P((SCR *, char *, int *, int, int)); + * PUBLIC: lockr_t file_lock __P((SCR *, char *, int, int)); */ lockr_t -file_lock(sp, name, fdp, fd, iswrite) - SCR *sp; - char *name; - int *fdp, fd, iswrite; +file_lock( + SCR *sp, + char *name, + int fd, + int iswrite) { if (!O_ISSET(sp, O_LOCKFILES)) return (LOCK_SUCCESS); -#ifdef HAVE_LOCK_FLOCK /* Hurrah! We've got flock(2). */ /* * !!! * We need to distinguish a lock not being available for the file @@ -1481,59 +1520,4 @@ file_lock(sp, name, fdp, fd, iswrite) || errno == EWOULDBLOCK #endif ? LOCK_UNAVAIL : LOCK_FAILED); -#endif -#ifdef HAVE_LOCK_FCNTL /* Gag me. We've got fcntl(2). */ -{ - struct flock arg; - int didopen, sverrno; - - arg.l_type = F_WRLCK; - arg.l_whence = 0; /* SEEK_SET */ - arg.l_start = arg.l_len = 0; - arg.l_pid = 0; - - /* - * If the file descriptor isn't opened for writing, it must fail. - * If we fail because we can't get a read/write file descriptor, - * we return LOCK_SUCCESS, believing that the file is readonly - * and that will be sufficient to warn the user. - */ - if (!iswrite) { - if (name == NULL || fdp == NULL) - return (LOCK_FAILED); - if ((fd = open(name, O_RDWR, 0)) == -1) - return (LOCK_SUCCESS); - *fdp = fd; - didopen = 1; - } - - errno = 0; - if (!fcntl(fd, F_SETLK, &arg)) { - fcntl(fd, F_SETFD, 1); - return (LOCK_SUCCESS); - } - - if (didopen) { - sverrno = errno; - (void)close(fd); - errno = sverrno; - } - - /* - * !!! - * We need to distinguish a lock not being available for the file - * from the file system not supporting locking. Fcntl is documented - * as returning EACCESS and EAGAIN; add EWOULDBLOCK for good measure, - * and assume they are the former. There's no portable way to do this. - */ - return (errno == EACCES || errno == EAGAIN -#ifdef EWOULDBLOCK - || errno == EWOULDBLOCK -#endif - ? LOCK_UNAVAIL : LOCK_FAILED); -} -#endif -#if !defined(HAVE_LOCK_FLOCK) && !defined(HAVE_LOCK_FCNTL) - return (LOCK_SUCCESS); -#endif } diff --git a/contrib/nvi/common/exf.h b/contrib/nvi/common/exf.h index cdfaa82..8f70d51 100644 --- a/contrib/nvi/common/exf.h +++ b/contrib/nvi/common/exf.h @@ -6,7 +6,7 @@ * * See the LICENSE file for redistribution information. * - * @(#)exf.h 10.7 (Berkeley) 7/9/96 + * $Id: exf.h,v 10.10 2012/07/06 16:03:37 zy Exp $ */ /* Undo direction. */ /* @@ -18,8 +18,9 @@ struct _exf { /* Underlying database state. */ DB *db; /* File db structure. */ - char *c_lp; /* Cached line. */ + CHAR_T *c_lp; /* Cached line. */ size_t c_len; /* Cached line length. */ + size_t c_blen; /* Cached line buffer length. */ recno_t c_lno; /* Cached line number. */ recno_t c_nlines; /* Cached lines in the file. */ @@ -31,17 +32,12 @@ struct _exf { MARK l_cursor; /* Log cursor position. */ dir_t lundo; /* Last undo direction. */ - LIST_HEAD(_markh, _lmark) marks;/* Linked list of file MARK's. */ + /* Linked list of file MARK's. */ + SLIST_HEAD(_markh, _lmark) marks[1]; - /* - * XXX - * Mtime should be a struct timespec, but time_t is more portable. - */ - dev_t mdev; /* Device. */ - ino_t minode; /* Inode. */ - time_t mtime; /* Last modification time. */ - - int fcntl_fd; /* Fcntl locking fd; see exf.c. */ + dev_t mdev; /* Device. */ + ino_t minode; /* Inode. */ + struct timespec mtim; /* Last modification time. */ /* * Recovery in general, and these fields specifically, are described diff --git a/contrib/nvi/common/extern.h b/contrib/nvi/common/extern.h new file mode 100644 index 0000000..20672e3 --- /dev/null +++ b/contrib/nvi/common/extern.h @@ -0,0 +1,132 @@ +char * codeset __P((void)); +void conv_init __P((SCR *, SCR *)); +int conv_enc __P((SCR *, int, char *)); +void conv_end __P((SCR *)); +int cut __P((SCR *, CHAR_T *, MARK *, MARK *, int)); +int cut_line __P((SCR *, recno_t, size_t, size_t, CB *)); +void cut_close __P((GS *)); +TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t)); +void text_lfree __P((TEXTH *)); +void text_free __P((TEXT *)); +int del __P((SCR *, MARK *, MARK *, int)); +int looks_utf8 __P((const char *, size_t)); +int looks_utf16 __P((const char *, size_t)); +int decode_utf8 __P((const char *)); +int decode_utf16 __P((const char *, int)); +FREF *file_add __P((SCR *, char *)); +int file_init __P((SCR *, FREF *, char *, int)); +int file_end __P((SCR *, EXF *, int)); +int file_write __P((SCR *, MARK *, MARK *, char *, int)); +int file_m1 __P((SCR *, int, int)); +int file_m2 __P((SCR *, int)); +int file_m3 __P((SCR *, int)); +int file_aw __P((SCR *, int)); +void set_alt_name __P((SCR *, char *)); +lockr_t file_lock __P((SCR *, char *, int, int)); +int v_key_init __P((SCR *)); +void v_key_ilookup __P((SCR *)); +size_t v_key_len __P((SCR *, ARG_CHAR_T)); +char *v_key_name __P((SCR *, ARG_CHAR_T)); +e_key_t v_key_val __P((SCR *, ARG_CHAR_T)); +int v_event_push __P((SCR *, EVENT *, CHAR_T *, size_t, u_int)); +int v_event_get __P((SCR *, EVENT *, int, u_int32_t)); +void v_event_err __P((SCR *, EVENT *)); +int v_event_flush __P((SCR *, u_int)); +int db_eget __P((SCR *, recno_t, CHAR_T **, size_t *, int *)); +int db_get __P((SCR *, recno_t, u_int32_t, CHAR_T **, size_t *)); +int db_delete __P((SCR *, recno_t)); +int db_append __P((SCR *, int, recno_t, CHAR_T *, size_t)); +int db_insert __P((SCR *, recno_t, CHAR_T *, size_t)); +int db_set __P((SCR *, recno_t, CHAR_T *, size_t)); +int db_exist __P((SCR *, recno_t)); +int db_last __P((SCR *, recno_t *)); +int db_rget __P((SCR *, recno_t, char **, size_t *)); +int db_rset __P((SCR *, recno_t, char *, size_t)); +void db_err __P((SCR *, recno_t)); +int log_init __P((SCR *, EXF *)); +int log_end __P((SCR *, EXF *)); +int log_cursor __P((SCR *)); +int log_line __P((SCR *, recno_t, u_int)); +int log_mark __P((SCR *, LMARK *)); +int log_backward __P((SCR *, MARK *)); +int log_setline __P((SCR *)); +int log_forward __P((SCR *, MARK *)); +int editor __P((GS *, int, char *[])); +void v_end __P((GS *)); +int mark_init __P((SCR *, EXF *)); +int mark_end __P((SCR *, EXF *)); +int mark_get __P((SCR *, ARG_CHAR_T, MARK *, mtype_t)); +int mark_set __P((SCR *, ARG_CHAR_T, MARK *, int)); +int mark_insdel __P((SCR *, lnop_t, recno_t)); +void msgq __P((SCR *, mtype_t, const char *, ...)); +void msgq_wstr __P((SCR *, mtype_t, const CHAR_T *, const char *)); +void msgq_str __P((SCR *, mtype_t, const char *, const char *)); +void mod_rpt __P((SCR *)); +void msgq_status __P((SCR *, recno_t, u_int)); +int msg_open __P((SCR *, char *)); +void msg_close __P((GS *)); +const char *msg_cmsg __P((SCR *, cmsg_t, size_t *)); +const char *msg_cat __P((SCR *, const char *, size_t *)); +char *msg_print __P((SCR *, const char *, int *)); +int opts_init __P((SCR *, int *)); +int opts_set __P((SCR *, ARGS *[], char *)); +int o_set __P((SCR *, int, u_int, char *, u_long)); +int opts_empty __P((SCR *, int, int)); +void opts_dump __P((SCR *, enum optdisp)); +int opts_save __P((SCR *, FILE *)); +OPTLIST const *opts_search __P((CHAR_T *)); +void opts_nomatch __P((SCR *, CHAR_T *)); +int opts_copy __P((SCR *, SCR *)); +void opts_free __P((SCR *)); +int f_altwerase __P((SCR *, OPTION *, char *, u_long *)); +int f_columns __P((SCR *, OPTION *, char *, u_long *)); +int f_lines __P((SCR *, OPTION *, char *, u_long *)); +int f_lisp __P((SCR *, OPTION *, char *, u_long *)); +int f_msgcat __P((SCR *, OPTION *, char *, u_long *)); +int f_print __P((SCR *, OPTION *, char *, u_long *)); +int f_readonly __P((SCR *, OPTION *, char *, u_long *)); +int f_recompile __P((SCR *, OPTION *, char *, u_long *)); +int f_reformat __P((SCR *, OPTION *, char *, u_long *)); +int f_ttywerase __P((SCR *, OPTION *, char *, u_long *)); +int f_w300 __P((SCR *, OPTION *, char *, u_long *)); +int f_w1200 __P((SCR *, OPTION *, char *, u_long *)); +int f_w9600 __P((SCR *, OPTION *, char *, u_long *)); +int f_window __P((SCR *, OPTION *, char *, u_long *)); +int f_encoding __P((SCR *, OPTION *, char *, u_long *)); +int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int)); +int rcv_tmp __P((SCR *, EXF *, char *)); +int rcv_init __P((SCR *)); +int rcv_sync __P((SCR *, u_int)); +int rcv_list __P((SCR *)); +int rcv_read __P((SCR *, FREF *)); +int screen_init __P((GS *, SCR *, SCR **)); +int screen_end __P((SCR *)); +SCR *screen_next __P((SCR *)); +int f_search __P((SCR *, + MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int)); +int b_search __P((SCR *, + MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int)); +void search_busy __P((SCR *, busy_t)); +int seq_set __P((SCR *, CHAR_T *, + size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int)); +int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t)); +int seq_free __P((SEQ *)); +SEQ *seq_find + __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *)); +void seq_close __P((GS *)); +int seq_dump __P((SCR *, seq_t, int)); +int seq_save __P((SCR *, FILE *, char *, seq_t)); +int e_memcmp __P((CHAR_T *, EVENT *, size_t)); +void *binc __P((SCR *, void *, size_t *, size_t)); +int nonblank __P((SCR *, recno_t, size_t *)); +char *tail __P((char *)); +char *join __P((char *, char *)); +char *expanduser __P((char *)); +char *quote __P((char *)); +char *v_strdup __P((SCR *, const char *, size_t)); +CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t)); +enum nresult nget_uslong __P((u_long *, const CHAR_T *, CHAR_T **, int)); +enum nresult nget_slong __P((long *, const CHAR_T *, CHAR_T **, int)); +void timepoint_steady __P((struct timespec *)); +void timepoint_system __P((struct timespec *)); +void TRACE __P((SCR *, const char *, ...)); diff --git a/contrib/nvi/common/gs.h b/contrib/nvi/common/gs.h index e5a43a6..33a0245 100644 --- a/contrib/nvi/common/gs.h +++ b/contrib/nvi/common/gs.h @@ -6,11 +6,13 @@ * * See the LICENSE file for redistribution information. * - * @(#)gs.h 10.34 (Berkeley) 9/24/96 + * $Id: gs.h,v 11.0 2012/10/17 06:34:37 zy Exp $ */ #define TEMPORARY_FILE_STRING "/tmp" /* Default temporary file name. */ +#include <nl_types.h> + /* * File reference structure (FREF). The structure contains the name of the * file, along with the information that follows the name. @@ -19,7 +21,7 @@ * The read-only bit follows the file name, not the file itself. */ struct _fref { - CIRCLEQ_ENTRY(_fref) q; /* Linked list of file references. */ + TAILQ_ENTRY(_fref) q; /* Linked list of file references. */ char *name; /* File name. */ char *tname; /* Backing temporary file name. */ @@ -56,20 +58,15 @@ struct _gs { char *progname; /* Programe name. */ int id; /* Last allocated screen id. */ - CIRCLEQ_HEAD(_dqh, _scr) dq; /* Displayed screens. */ - CIRCLEQ_HEAD(_hqh, _scr) hq; /* Hidden screens. */ + TAILQ_HEAD(_dqh, _scr) dq[1]; /* Displayed screens. */ + TAILQ_HEAD(_hqh, _scr) hq[1]; /* Hidden screens. */ SCR *ccl_sp; /* Colon command-line screen. */ - void *perl_interp; /* Perl interpreter. */ - void *tcl_interp; /* Tcl_Interp *: Tcl interpreter. */ - void *cl_private; /* Curses support private area. */ - void *ip_private; /* IP support private area. */ - void *tk_private; /* Tk/Tcl support private area. */ /* File references. */ - CIRCLEQ_HEAD(_frefh, _fref) frefq; + TAILQ_HEAD(_frefh, _fref) frefq[1]; #define GO_COLUMNS 0 /* Global options: columns. */ #define GO_LINES 1 /* Global options: lines. */ @@ -77,10 +74,10 @@ struct _gs { #define GO_TERM 3 /* Global options: terminal type. */ OPTION opts[GO_TERM + 1]; - DB *msg; /* Message catalog DB. */ - MSGH msgq; /* User message list. */ + nl_catd catd; /* Message catalog descriptor. */ + MSGH msgq[1]; /* User message list. */ #define DEFAULT_NOPRINT '\1' /* Emergency non-printable character. */ - CHAR_T noprint; /* Cached, unprintable character. */ + int noprint; /* Cached, unprintable character. */ char *tmp_bp; /* Temporary buffer. */ size_t tmp_blen; /* Temporary buffer size. */ @@ -89,8 +86,9 @@ struct _gs { * Ex command structures (EXCMD). Defined here because ex commands * exist outside of any particular screen or file. */ -#define EXCMD_RUNNING(gp) ((gp)->ecq.lh_first->clen != 0) - LIST_HEAD(_excmdh, _excmd) ecq; /* Ex command linked list. */ +#define EXCMD_RUNNING(gp) (SLIST_FIRST((gp)->ecq)->clen != 0) + /* Ex command linked list. */ + SLIST_HEAD(_excmdh, _excmd) ecq[1]; EXCMD excmd; /* Default ex command structure. */ char *if_name; /* Current associated file. */ recno_t if_lno; /* Current associated line number. */ @@ -108,30 +106,28 @@ struct _gs { CB *dcbp; /* Default cut buffer pointer. */ CB dcb_store; /* Default cut buffer storage. */ - LIST_HEAD(_cuth, _cb) cutq; /* Linked list of cut buffers. */ + SLIST_HEAD(_cuth, _cb) cutq[1]; /* Linked list of cut buffers. */ -#define MAX_BIT_SEQ 128 /* Max + 1 fast check character. */ - LIST_HEAD(_seqh, _seq) seqq; /* Linked list of maps, abbrevs. */ - bitstr_t bit_decl(seqb, MAX_BIT_SEQ); +#define MAX_BIT_SEQ 0x7f /* Max + 1 fast check character. */ + SLIST_HEAD(_seqh, _seq) seqq[1];/* Linked list of maps, abbrevs. */ + bitstr_t bit_decl(seqb, MAX_BIT_SEQ + 1); -#define MAX_FAST_KEY 254 /* Max fast check character.*/ +#define MAX_FAST_KEY 0xff /* Max fast check character.*/ #define KEY_LEN(sp, ch) \ - ((unsigned char)(ch) <= MAX_FAST_KEY ? \ + (((ch) & ~MAX_FAST_KEY) == 0 ? \ sp->gp->cname[(unsigned char)ch].len : v_key_len(sp, ch)) #define KEY_NAME(sp, ch) \ - ((unsigned char)(ch) <= MAX_FAST_KEY ? \ + (((ch) & ~MAX_FAST_KEY) == 0 ? \ sp->gp->cname[(unsigned char)ch].name : v_key_name(sp, ch)) struct { - CHAR_T name[MAX_CHARACTER_COLUMNS + 1]; + char name[MAX_CHARACTER_COLUMNS + 1]; u_int8_t len; } cname[MAX_FAST_KEY + 1]; /* Fast lookup table. */ #define KEY_VAL(sp, ch) \ - ((unsigned char)(ch) <= MAX_FAST_KEY ? \ - sp->gp->special_key[(unsigned char)ch] : \ - (unsigned char)(ch) > sp->gp->max_special ? 0 : v_key_val(sp,ch)) - CHAR_T max_special; /* Max special character. */ - u_char /* Fast lookup table. */ + (((ch) & ~MAX_FAST_KEY) == 0 ? \ + sp->gp->special_key[(unsigned char)ch] : v_key_val(sp,ch)) + e_key_t /* Fast lookup table. */ special_key[MAX_FAST_KEY + 1]; /* Flags. */ @@ -149,6 +145,8 @@ struct _gs { /* Screen interface functions. */ /* Add a string to the screen. */ int (*scr_addstr) __P((SCR *, const char *, size_t)); + /* Add a string to the screen. */ + int (*scr_waddstr) __P((SCR *, const CHAR_T *, size_t)); /* Toggle a screen attribute. */ int (*scr_attr) __P((SCR *, scr_attr_t, int)); /* Terminal baud rate. */ @@ -157,12 +155,16 @@ struct _gs { int (*scr_bell) __P((SCR *)); /* Display a busy message. */ void (*scr_busy) __P((SCR *, const char *, busy_t)); + /* Prepare child. */ + int (*scr_child) __P((SCR *)); /* Clear to the end of the line. */ int (*scr_clrtoeol) __P((SCR *)); /* Return the cursor location. */ int (*scr_cursor) __P((SCR *, size_t *, size_t *)); /* Delete a line. */ int (*scr_deleteln) __P((SCR *)); + /* Discard a screen. */ + int (*scr_discard) __P((SCR *, SCR **)); /* Get a keyboard event. */ int (*scr_event) __P((SCR *, EVENT *, u_int32_t, int)); /* Ex: screen adjustment routine. */ @@ -183,8 +185,12 @@ struct _gs { int (*scr_refresh) __P((SCR *, int)); /* Rename the file. */ int (*scr_rename) __P((SCR *, char *, int)); + /* Reply to an event. */ + int (*scr_reply) __P((SCR *, int, char *)); /* Set the screen type. */ int (*scr_screen) __P((SCR *, u_int32_t)); + /* Split the screen. */ + int (*scr_split) __P((SCR *, SCR *)); /* Suspend the editor. */ int (*scr_suspend) __P((SCR *, int *)); /* Print usage message. */ diff --git a/contrib/nvi/common/key.c b/contrib/nvi/common/key.c index e1311ab..652b8f3 100644 --- a/contrib/nvi/common/key.c +++ b/contrib/nvi/common/key.c @@ -10,7 +10,7 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)key.c 10.33 (Berkeley) 9/24/96"; +static const char sccsid[] = "$Id: key.c,v 10.53 2013/03/11 01:20:53 yamt Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -21,10 +21,10 @@ static const char sccsid[] = "@(#)key.c 10.33 (Berkeley) 9/24/96"; #include <ctype.h> #include <errno.h> #include <limits.h> -#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <unistd.h> #include "common.h" @@ -100,32 +100,15 @@ static int nkeylist = * PUBLIC: int v_key_init __P((SCR *)); */ int -v_key_init(sp) - SCR *sp; +v_key_init(SCR *sp) { - CHAR_T ch; + int ch; GS *gp; KEYLIST *kp; int cnt; gp = sp->gp; - /* - * XXX - * 8-bit only, for now. Recompilation should get you any 8-bit - * character set, as long as nul isn't a character. - */ - (void)setlocale(LC_ALL, ""); -#if __linux__ - /* - * In libc 4.5.26, setlocale(LC_ALL, ""), doesn't setup the table - * for ctype(3c) correctly. This bug is fixed in libc 4.6.x. - * - * This code works around this problem for libc 4.5.x users. - * Note that this code is harmless if you're using libc 4.6.x. - */ - (void)setlocale(LC_CTYPE, ""); -#endif v_key_ilookup(sp); v_keyval(sp, K_CNTRLD, KEY_VEOF); @@ -137,15 +120,11 @@ v_key_init(sp) qsort(keylist, nkeylist, sizeof(keylist[0]), v_key_cmp); /* Initialize the fast lookup table. */ - for (gp->max_special = 0, kp = keylist, cnt = nkeylist; cnt--; ++kp) { - if (gp->max_special < kp->value) - gp->max_special = kp->value; - if (kp->ch <= MAX_FAST_KEY) - gp->special_key[kp->ch] = kp->value; - } + for (kp = keylist, cnt = nkeylist; cnt--; ++kp) + gp->special_key[kp->ch] = kp->value; /* Find a non-printable character to use as a message separator. */ - for (ch = 1; ch <= MAX_CHAR_T; ++ch) + for (ch = 1; ch <= UCHAR_MAX; ++ch) if (!isprint(ch)) { gp->noprint = ch; break; @@ -166,10 +145,10 @@ v_key_init(sp) * in the table, so we check for that first. */ static void -v_keyval(sp, val, name) - SCR *sp; - int val; - scr_keyval_t name; +v_keyval( + SCR *sp, + int val, + scr_keyval_t name) { KEYLIST *kp; CHAR_T ch; @@ -203,17 +182,20 @@ v_keyval(sp, val, name) * PUBLIC: void v_key_ilookup __P((SCR *)); */ void -v_key_ilookup(sp) - SCR *sp; +v_key_ilookup(SCR *sp) { - CHAR_T ch, *p, *t; + UCHAR_T ch; + char *p, *t; GS *gp; size_t len; - for (gp = sp->gp, ch = 0; ch <= MAX_FAST_KEY; ++ch) + for (gp = sp->gp, ch = 0;; ++ch) { for (p = gp->cname[ch].name, t = v_key_name(sp, ch), len = gp->cname[ch].len = sp->clen; len--;) *p++ = *t++; + if (ch == MAX_FAST_KEY) + break; + } } /* @@ -224,9 +206,9 @@ v_key_ilookup(sp) * PUBLIC: size_t v_key_len __P((SCR *, ARG_CHAR_T)); */ size_t -v_key_len(sp, ch) - SCR *sp; - ARG_CHAR_T ch; +v_key_len( + SCR *sp, + ARG_CHAR_T ch) { (void)v_key_name(sp, ch); return (sp->clen); @@ -237,30 +219,43 @@ v_key_len(sp, ch) * Return the string that will display the key. This routine * is the backup for the KEY_NAME() macro. * - * PUBLIC: CHAR_T *v_key_name __P((SCR *, ARG_CHAR_T)); + * PUBLIC: char *v_key_name __P((SCR *, ARG_CHAR_T)); */ -CHAR_T * -v_key_name(sp, ach) - SCR *sp; - ARG_CHAR_T ach; +char * +v_key_name( + SCR *sp, + ARG_CHAR_T ach) { - static const CHAR_T hexdigit[] = "0123456789abcdef"; - static const CHAR_T octdigit[] = "01234567"; - CHAR_T ch, *chp, mask; + static const char hexdigit[] = "0123456789abcdef"; + static const char octdigit[] = "01234567"; + int ch; size_t len; - int cnt, shift; + char *chp; + + /* + * Cache the last checked character. It won't be a problem + * since nvi will rescan the mapping when settings changed. + */ + if (ach && sp->lastc == ach) + return (sp->cname); + sp->lastc = ach; + +#ifdef USE_WIDECHAR + len = wctomb(sp->cname, ach); + if (len > MB_CUR_MAX) +#endif + sp->cname[(len = 1)-1] = (u_char)ach; - ch = ach; + ch = (u_char)sp->cname[0]; + sp->cname[len] = '\0'; /* See if the character was explicitly declared printable or not. */ if ((chp = O_STR(sp, O_PRINT)) != NULL) - for (; *chp != '\0'; ++chp) - if (*chp == ch) - goto pr; + if (strstr(chp, sp->cname) != NULL) + goto done; if ((chp = O_STR(sp, O_NOPRINT)) != NULL) - for (; *chp != '\0'; ++chp) - if (*chp == ch) - goto nopr; + if (strstr(chp, sp->cname) != NULL) + goto nopr; /* * Historical (ARPA standard) mappings. Printable characters are left @@ -274,41 +269,55 @@ v_key_name(sp, ach) * told that this is a reasonable assumption... * * XXX - * This code will only work with CHAR_T's that are multiples of 8-bit - * bytes. - * - * XXX - * NB: There's an assumption here that all printable characters take - * up a single column on the screen. This is not always correct. + * The code prints non-printable wide characters in 4 or 5 digits + * Unicode escape sequences, so only supports plane 0 to 15. */ - if (isprint(ch)) { -pr: sp->cname[0] = ch; - len = 1; + if (ISPRINT(ach)) goto done; - } nopr: if (iscntrl(ch) && (ch < 0x20 || ch == 0x7f)) { sp->cname[0] = '^'; sp->cname[1] = ch == 0x7f ? '?' : '@' + ch; len = 2; - } else if (O_ISSET(sp, O_OCTAL)) { -#define BITS (sizeof(CHAR_T) * 8) -#define SHIFT (BITS - BITS % 3) -#define TOPMASK (BITS % 3 == 2 ? 3 : 1) << (BITS - BITS % 3) + goto done; + } +#ifdef USE_WIDECHAR + if (INTISWIDE(ach)) { + int uc = -1; + + if (!strcmp(codeset(), "UTF-8")) + uc = decode_utf8(sp->cname); +#ifdef USE_ICONV + else { + char buf[sizeof(sp->cname)] = ""; + size_t left = sizeof(sp->cname); + char *in = sp->cname; + char *out = buf; + iconv(sp->conv.id[IC_IE_TO_UTF16], + (iconv_src_t)&in, &len, &out, &left); + iconv(sp->conv.id[IC_IE_TO_UTF16], + NULL, NULL, NULL, NULL); + uc = decode_utf16(buf, 1); + } +#endif + if (uc >= 0) { + len = snprintf(sp->cname, sizeof(sp->cname), + uc < 0x10000 ? "\\u%04x" : "\\U%05X", uc); + goto done; + } + } +#endif + if (O_ISSET(sp, O_OCTAL)) { sp->cname[0] = '\\'; - sp->cname[1] = octdigit[(ch & TOPMASK) >> SHIFT]; - shift = SHIFT - 3; - for (len = 2, mask = 7 << (SHIFT - 3), - cnt = BITS / 3; cnt-- > 0; mask >>= 3, shift -= 3) - sp->cname[len++] = octdigit[(ch & mask) >> shift]; + sp->cname[1] = octdigit[(ch & 0300) >> 6]; + sp->cname[2] = octdigit[(ch & 070) >> 3]; + sp->cname[3] = octdigit[ ch & 07 ]; } else { sp->cname[0] = '\\'; sp->cname[1] = 'x'; - for (len = 2, chp = (u_int8_t *)&ch, - cnt = sizeof(CHAR_T); cnt-- > 0; ++chp) { - sp->cname[len++] = hexdigit[(*chp & 0xf0) >> 4]; - sp->cname[len++] = hexdigit[*chp & 0x0f]; - } + sp->cname[2] = hexdigit[(ch & 0xf0) >> 4]; + sp->cname[3] = hexdigit[ ch & 0x0f ]; } + len = 4; done: sp->cname[sp->clen = len] = '\0'; return (sp->cname); } @@ -318,12 +327,12 @@ done: sp->cname[sp->clen = len] = '\0'; * Fill in the value for a key. This routine is the backup * for the KEY_VAL() macro. * - * PUBLIC: int v_key_val __P((SCR *, ARG_CHAR_T)); + * PUBLIC: e_key_t v_key_val __P((SCR *, ARG_CHAR_T)); */ -int -v_key_val(sp, ch) - SCR *sp; - ARG_CHAR_T ch; +e_key_t +v_key_val( + SCR *sp, + ARG_CHAR_T ch) { KEYLIST k, *kp; @@ -345,12 +354,12 @@ v_key_val(sp, ch) * PUBLIC: int v_event_push __P((SCR *, EVENT *, CHAR_T *, size_t, u_int)); */ int -v_event_push(sp, p_evp, p_s, nitems, flags) - SCR *sp; - EVENT *p_evp; /* Push event. */ - CHAR_T *p_s; /* Push characters. */ - size_t nitems; /* Number of items to push. */ - u_int flags; /* CH_* flags. */ +v_event_push( + SCR *sp, + EVENT *p_evp, /* Push event. */ + CHAR_T *p_s, /* Push characters. */ + size_t nitems, /* Number of items to push. */ + u_int flags) /* CH_* flags. */ { EVENT *evp; GS *gp; @@ -375,8 +384,8 @@ v_event_push(sp, p_evp, p_s, nitems, flags) if (total >= gp->i_nelem && v_event_grow(sp, MAX(total, 64))) return (1); if (gp->i_cnt) - MEMMOVE(gp->i_event + TERM_PUSH_SHIFT + nitems, - gp->i_event + gp->i_next, gp->i_cnt); + BCOPY(gp->i_event + gp->i_next, + gp->i_event + TERM_PUSH_SHIFT + nitems, gp->i_cnt); gp->i_next = TERM_PUSH_SHIFT; /* Put the new items into the queue. */ @@ -399,9 +408,9 @@ copy: gp->i_cnt += nitems; * Append events onto the tail of the buffer. */ static int -v_event_append(sp, argp) - SCR *sp; - EVENT *argp; +v_event_append( + SCR *sp, + EVENT *argp) { CHAR_T *s; /* Characters. */ EVENT *evp; @@ -526,11 +535,11 @@ v_event_append(sp, argp) * PUBLIC: int v_event_get __P((SCR *, EVENT *, int, u_int32_t)); */ int -v_event_get(sp, argp, timeout, flags) - SCR *sp; - EVENT *argp; - int timeout; - u_int32_t flags; +v_event_get( + SCR *sp, + EVENT *argp, + int timeout, + u_int32_t flags) { EVENT *evp, ev; GS *gp; @@ -630,7 +639,8 @@ newmap: evp = &gp->i_event[gp->i_next]; */ if (istimeout || F_ISSET(&evp->e_ch, CH_NOMAP) || !LF_ISSET(EC_MAPCOMMAND | EC_MAPINPUT) || - evp->e_c < MAX_BIT_SEQ && !bit_test(gp->seqb, evp->e_c)) + ((evp->e_c & ~MAX_BIT_SEQ) == 0 && + !bit_test(gp->seqb, evp->e_c))) goto nomap; /* Search the map. */ @@ -664,7 +674,7 @@ newmap: evp = &gp->i_event[gp->i_next]; /* If no map, return the character. */ if (qp == NULL) { -nomap: if (!isdigit(evp->e_c) && LF_ISSET(EC_MAPNODIGIT)) +nomap: if (!ISDIGIT(evp->e_c) && LF_ISSET(EC_MAPNODIGIT)) goto not_digit; *argp = *evp; QREM(1); @@ -676,7 +686,7 @@ nomap: if (!isdigit(evp->e_c) && LF_ISSET(EC_MAPNODIGIT)) * of the map is it, pretend we haven't seen the character. */ if (LF_ISSET(EC_MAPNODIGIT) && - qp->output != NULL && !isdigit(qp->output[0])) { + qp->output != NULL && !ISDIGIT(qp->output[0])) { not_digit: argp->e_c = CH_NOT_DIGIT; argp->e_value = K_NOTUSED; argp->e_event = E_CHARACTER; @@ -744,16 +754,16 @@ not_digit: argp->e_c = CH_NOT_DIGIT; * Walk the screen lists, sync'ing files to their backup copies. */ static void -v_sync(sp, flags) - SCR *sp; - int flags; +v_sync( + SCR *sp, + int flags) { GS *gp; gp = sp->gp; - for (sp = gp->dq.cqh_first; sp != (void *)&gp->dq; sp = sp->q.cqe_next) + TAILQ_FOREACH(sp, gp->dq, q) rcv_sync(sp, flags); - for (sp = gp->hq.cqh_first; sp != (void *)&gp->hq; sp = sp->q.cqe_next) + TAILQ_FOREACH(sp, gp->hq, q) rcv_sync(sp, flags); } @@ -764,9 +774,9 @@ v_sync(sp, flags) * PUBLIC: void v_event_err __P((SCR *, EVENT *)); */ void -v_event_err(sp, evp) - SCR *sp; - EVENT *evp; +v_event_err( + SCR *sp, + EVENT *evp) { switch (evp->e_event) { case E_CHARACTER: @@ -778,9 +788,6 @@ v_event_err(sp, evp) case E_INTERRUPT: msgq(sp, M_ERR, "279|Unexpected interrupt event"); break; - case E_QUIT: - msgq(sp, M_ERR, "280|Unexpected quit event"); - break; case E_REPAINT: msgq(sp, M_ERR, "281|Unexpected repaint event"); break; @@ -793,9 +800,6 @@ v_event_err(sp, evp) case E_WRESIZE: msgq(sp, M_ERR, "316|Unexpected resize event"); break; - case E_WRITE: - msgq(sp, M_ERR, "287|Unexpected write event"); - break; /* * Theoretically, none of these can occur, as they're handled at the @@ -820,9 +824,9 @@ v_event_err(sp, evp) * PUBLIC: int v_event_flush __P((SCR *, u_int)); */ int -v_event_flush(sp, flags) - SCR *sp; - u_int flags; +v_event_flush( + SCR *sp, + u_int flags) { GS *gp; int rval; @@ -838,9 +842,9 @@ v_event_flush(sp, flags) * Grow the terminal queue. */ static int -v_event_grow(sp, add) - SCR *sp; - int add; +v_event_grow( + SCR *sp, + int add) { GS *gp; size_t new_nelem, olen; @@ -848,7 +852,7 @@ v_event_grow(sp, add) gp = sp->gp; new_nelem = gp->i_nelem + add; olen = gp->i_nelem * sizeof(gp->i_event[0]); - BINC_RET(sp, gp->i_event, olen, new_nelem * sizeof(gp->i_event[0])); + BINC_RET(sp, EVENT, gp->i_event, olen, new_nelem * sizeof(gp->i_event[0])); gp->i_nelem = olen / sizeof(gp->i_event[0]); return (0); } @@ -858,8 +862,9 @@ v_event_grow(sp, add) * Compare two keys for sorting. */ static int -v_key_cmp(ap, bp) - const void *ap, *bp; +v_key_cmp( + const void *ap, + const void *bp) { return (((KEYLIST *)ap)->ch - ((KEYLIST *)bp)->ch); } diff --git a/contrib/nvi/common/key.h b/contrib/nvi/common/key.h index 76fb64f..3eeca12 100644 --- a/contrib/nvi/common/key.h +++ b/contrib/nvi/common/key.h @@ -6,27 +6,47 @@ * * See the LICENSE file for redistribution information. * - * @(#)key.h 10.18 (Berkeley) 6/30/96 + * $Id: key.h,v 10.55 2012/10/07 01:31:17 zy Exp $ */ -/* - * Fundamental character types. - * - * CHAR_T An integral type that can hold any character. - * ARG_CHAR_T The type of a CHAR_T when passed as an argument using - * traditional promotion rules. It should also be able - * to be compared against any CHAR_T for equality without - * problems. - * MAX_CHAR_T The maximum value of any character. - * - * If no integral type can hold a character, don't even try the port. - */ -typedef u_char CHAR_T; -typedef u_int ARG_CHAR_T; -#define MAX_CHAR_T 0xff +#include "multibyte.h" + +#ifdef USE_WIDECHAR +#define FILE2INT5(sp,buf,n,nlen,w,wlen) \ + sp->conv.file2int(sp, n, nlen, &buf, &wlen, &w) +#define INT2FILE(sp,w,wlen,n,nlen) \ + sp->conv.int2file(sp, w, wlen, &sp->cw, &nlen, &n) +#define CHAR2INT5(sp,buf,n,nlen,w,wlen) \ + sp->conv.sys2int(sp, n, nlen, &buf, &wlen, &w) +#define INT2CHAR(sp,w,wlen,n,nlen) \ + sp->conv.int2sys(sp, w, wlen, &sp->cw, &nlen, &n) +#define INPUT2INT5(sp,cw,n,nlen,w,wlen) \ + sp->conv.input2int(sp, n, nlen, &(cw), &wlen, &w) +#define CONST +#define CHAR_WIDTH(sp, ch) wcwidth(ch) +#define INTISWIDE(c) (wctob(c) == EOF) +#else +#define FILE2INT5(sp,buf,n,nlen,w,wlen) \ + (w = n, wlen = nlen, 0) +#define INT2FILE(sp,w,wlen,n,nlen) \ + (n = w, nlen = wlen, 0) +#define CHAR2INT5(sp,buf,n,nlen,w,wlen) \ + (w = n, wlen = nlen, 0) +#define INT2CHAR(sp,w,wlen,n,nlen) \ + (n = w, nlen = wlen, 0) +#define INPUT2INT5(sp,buf,n,nlen,w,wlen) \ + (w = n, wlen = nlen, 0) +#define CONST const +#define INTISWIDE(c) 0 +#define CHAR_WIDTH(sp, ch) 1 +#endif +#define FILE2INT(sp,n,nlen,w,wlen) \ + FILE2INT5(sp,sp->cw,n,nlen,w,wlen) +#define CHAR2INT(sp,n,nlen,w,wlen) \ + CHAR2INT5(sp,sp->cw,n,nlen,w,wlen) /* The maximum number of columns any character can take up on a screen. */ -#define MAX_CHARACTER_COLUMNS 4 +#define MAX_CHARACTER_COLUMNS 7 /* * Event types. @@ -42,14 +62,12 @@ typedef enum { E_EOF, /* End of input (NOT ^D). */ E_ERR, /* Input error. */ E_INTERRUPT, /* Interrupt. */ - E_QUIT, /* Quit. */ E_REPAINT, /* Repaint: e_flno, e_tlno set. */ E_SIGHUP, /* SIGHUP. */ E_SIGTERM, /* SIGTERM. */ E_STRING, /* Input string: e_csp, e_len set. */ E_TIMEOUT, /* Timeout. */ E_WRESIZE, /* Window resize. */ - E_WRITE /* Write. */ } e_event_t; /* @@ -124,7 +142,7 @@ struct _event { typedef struct _keylist { e_key_t value; /* Special value. */ - CHAR_T ch; /* Key. */ + int ch; /* Key. */ } KEYLIST; extern KEYLIST keylist[]; @@ -137,15 +155,13 @@ extern KEYLIST keylist[]; /* * Ex/vi commands are generally separated by whitespace characters. We * can't use the standard isspace(3) macro because it returns true for - * characters like ^K in the ASCII character set. The 4.4BSD isblank(3) - * macro does exactly what we want, but it's not portable yet. + * characters like ^K in the ASCII character set. The POSIX isblank(3) + * has the same problem for non-ASCII locale, so we need a standalone one. * * XXX * Note side effect, ch is evaluated multiple times. */ -#ifndef isblank -#define isblank(ch) ((ch) == ' ' || (ch) == '\t') -#endif +#define cmdskip(ch) ((ch) == ' ' || (ch) == '\t') /* The "standard" tab width, for displaying things to users. */ #define STANDARD_TAB 6 diff --git a/contrib/nvi/common/line.c b/contrib/nvi/common/line.c index bcb9e0c..0bceccf 100644 --- a/contrib/nvi/common/line.c +++ b/contrib/nvi/common/line.c @@ -10,7 +10,7 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)line.c 10.21 (Berkeley) 9/15/96"; +static const char sccsid[] = "$Id: line.c,v 10.26 2011/08/12 12:36:41 zy Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -32,15 +32,15 @@ static int scr_update __P((SCR *, recno_t, lnop_t, int)); * db_eget -- * Front-end to db_get, special case handling for empty files. * - * PUBLIC: int db_eget __P((SCR *, recno_t, char **, size_t *, int *)); + * PUBLIC: int db_eget __P((SCR *, recno_t, CHAR_T **, size_t *, int *)); */ int -db_eget(sp, lno, pp, lenp, isemptyp) - SCR *sp; - recno_t lno; /* Line number. */ - char **pp; /* Pointer store. */ - size_t *lenp; /* Length store. */ - int *isemptyp; +db_eget( + SCR *sp, + recno_t lno, /* Line number. */ + CHAR_T **pp, /* Pointer store. */ + size_t *lenp, /* Length store. */ + int *isemptyp) { recno_t l1; @@ -60,7 +60,7 @@ db_eget(sp, lno, pp, lenp, isemptyp) return (1); /* If the file isn't empty, fail loudly. */ - if (lno != 0 && lno != 1 || l1 != 0) { + if ((lno != 0 && lno != 1) || l1 != 0) { db_err(sp, lno); return (1); } @@ -76,20 +76,23 @@ db_eget(sp, lno, pp, lenp, isemptyp) * Look in the text buffers for a line, followed by the cache, followed * by the database. * - * PUBLIC: int db_get __P((SCR *, recno_t, u_int32_t, char **, size_t *)); + * PUBLIC: int db_get __P((SCR *, recno_t, u_int32_t, CHAR_T **, size_t *)); */ int -db_get(sp, lno, flags, pp, lenp) - SCR *sp; - recno_t lno; /* Line number. */ - u_int32_t flags; - char **pp; /* Pointer store. */ - size_t *lenp; /* Length store. */ +db_get( + SCR *sp, + recno_t lno, /* Line number. */ + u_int32_t flags, + CHAR_T **pp, /* Pointer store. */ + size_t *lenp) /* Length store. */ { DBT data, key; EXF *ep; TEXT *tp; recno_t l1, l2; + CHAR_T *wp; + size_t wlen; + size_t nlen; /* * The underlying recno stuff handles zero by returning NULL, but @@ -113,14 +116,14 @@ db_get(sp, lno, flags, pp, lenp) * is there. */ if (F_ISSET(sp, SC_TINPUT)) { - l1 = ((TEXT *)sp->tiq.cqh_first)->lno; - l2 = ((TEXT *)sp->tiq.cqh_last)->lno; + l1 = ((TEXT *)TAILQ_FIRST(sp->tiq))->lno; + l2 = ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno; if (l1 <= lno && l2 >= lno) { #if defined(DEBUG) && 0 TRACE(sp, "retrieve TEXT buffer line %lu\n", (u_long)lno); #endif - for (tp = sp->tiq.cqh_first; - tp->lno != lno; tp = tp->q.cqe_next); + for (tp = TAILQ_FIRST(sp->tiq); + tp->lno != lno; tp = TAILQ_NEXT(tp, q)); if (lenp != NULL) *lenp = tp->len; if (pp != NULL) @@ -149,32 +152,52 @@ db_get(sp, lno, flags, pp, lenp) ep->c_lno = OOBLNO; nocache: + nlen = 1024; +retry: /* Get the line from the underlying database. */ key.data = &lno; key.size = sizeof(lno); switch (ep->db->get(ep->db, &key, &data, 0)) { - case -1: + case -1: goto err2; case 1: err1: if (LF_ISSET(DBG_FATAL)) err2: db_err(sp, lno); +alloc_err: err3: if (lenp != NULL) *lenp = 0; if (pp != NULL) *pp = NULL; return (1); + case 0: + if (data.size > nlen) { + nlen = data.size; + goto retry; + } + } + + if (FILE2INT(sp, data.data, data.size, wp, wlen)) { + if (!F_ISSET(sp, SC_CONV_ERROR)) { + F_SET(sp, SC_CONV_ERROR); + msgq(sp, M_ERR, "324|Conversion error on line %d", lno); + } + goto err3; } /* Reset the cache. */ + if (wp != data.data) { + BINC_GOTOW(sp, ep->c_lp, ep->c_blen, wlen); + MEMCPY(ep->c_lp, wp, wlen); + } else + ep->c_lp = data.data; ep->c_lno = lno; - ep->c_len = data.size; - ep->c_lp = data.data; + ep->c_len = wlen; #if defined(DEBUG) && 0 TRACE(sp, "retrieve DB line %lu\n", (u_long)lno); #endif if (lenp != NULL) - *lenp = data.size; + *lenp = wlen; if (pp != NULL) *pp = ep->c_lp; return (0); @@ -187,9 +210,9 @@ err3: if (lenp != NULL) * PUBLIC: int db_delete __P((SCR *, recno_t)); */ int -db_delete(sp, lno) - SCR *sp; - recno_t lno; +db_delete( + SCR *sp, + recno_t lno) { DBT key; EXF *ep; @@ -242,18 +265,20 @@ db_delete(sp, lno) * db_append -- * Append a line into the file. * - * PUBLIC: int db_append __P((SCR *, int, recno_t, char *, size_t)); + * PUBLIC: int db_append __P((SCR *, int, recno_t, CHAR_T *, size_t)); */ int -db_append(sp, update, lno, p, len) - SCR *sp; - int update; - recno_t lno; - char *p; - size_t len; +db_append( + SCR *sp, + int update, + recno_t lno, + CHAR_T *p, + size_t len) { DBT data, key; EXF *ep; + char *fp; + size_t flen; int rval; #if defined(DEBUG) && 0 @@ -265,11 +290,13 @@ db_append(sp, update, lno, p, len) return (1); } + INT2FILE(sp, p, len, fp, flen); + /* Update file. */ key.data = &lno; key.size = sizeof(lno); - data.data = p; - data.size = len; + data.data = fp; + data.size = flen; SIGBLOCK; if (ep->db->put(ep->db, &key, &data, R_IAFTER) == -1) { msgq(sp, M_SYSERR, @@ -316,17 +343,19 @@ db_append(sp, update, lno, p, len) * db_insert -- * Insert a line into the file. * - * PUBLIC: int db_insert __P((SCR *, recno_t, char *, size_t)); + * PUBLIC: int db_insert __P((SCR *, recno_t, CHAR_T *, size_t)); */ int -db_insert(sp, lno, p, len) - SCR *sp; - recno_t lno; - char *p; - size_t len; +db_insert( + SCR *sp, + recno_t lno, + CHAR_T *p, + size_t len) { DBT data, key; EXF *ep; + char *fp; + size_t flen; int rval; #if defined(DEBUG) && 0 @@ -339,11 +368,13 @@ db_insert(sp, lno, p, len) return (1); } + INT2FILE(sp, p, len, fp, flen); + /* Update file. */ key.data = &lno; key.size = sizeof(lno); - data.data = p; - data.size = len; + data.data = fp; + data.size = flen; SIGBLOCK; if (ep->db->put(ep->db, &key, &data, R_IBEFORE) == -1) { msgq(sp, M_SYSERR, @@ -381,23 +412,24 @@ db_insert(sp, lno, p, len) * db_set -- * Store a line in the file. * - * PUBLIC: int db_set __P((SCR *, recno_t, char *, size_t)); + * PUBLIC: int db_set __P((SCR *, recno_t, CHAR_T *, size_t)); */ int -db_set(sp, lno, p, len) - SCR *sp; - recno_t lno; - char *p; - size_t len; +db_set( + SCR *sp, + recno_t lno, + CHAR_T *p, + size_t len) { DBT data, key; EXF *ep; + char *fp; + size_t flen; #if defined(DEBUG) && 0 TRACE(sp, "replace line %lu: len %lu {%.*s}\n", (u_long)lno, (u_long)len, MIN(len, 20), p); #endif - /* Check for no underlying file. */ if ((ep = sp->ep) == NULL) { ex_emsg(sp, NULL, EXM_NOFILEYET); @@ -407,11 +439,13 @@ db_set(sp, lno, p, len) /* Log before change. */ log_line(sp, lno, LOG_LINE_RESET_B); + INT2FILE(sp, p, len, fp, flen); + /* Update file. */ key.data = &lno; key.size = sizeof(lno); - data.data = p; - data.size = len; + data.data = fp; + data.size = flen; SIGBLOCK; if (ep->db->put(ep->db, &key, &data, 0) == -1) { msgq(sp, M_SYSERR, @@ -443,9 +477,9 @@ db_set(sp, lno, p, len) * PUBLIC: int db_exist __P((SCR *, recno_t)); */ int -db_exist(sp, lno) - SCR *sp; - recno_t lno; +db_exist( + SCR *sp, + recno_t lno) { EXF *ep; @@ -464,8 +498,8 @@ db_exist(sp, lno) */ if (ep->c_nlines != OOBLNO) return (lno <= (F_ISSET(sp, SC_TINPUT) ? - ep->c_nlines + (((TEXT *)sp->tiq.cqh_last)->lno - - ((TEXT *)sp->tiq.cqh_first)->lno) : ep->c_nlines)); + ep->c_nlines + (((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno - + ((TEXT *)TAILQ_FIRST(sp->tiq))->lno) : ep->c_nlines)); /* Go get the line. */ return (!db_get(sp, lno, 0, NULL, NULL)); @@ -478,13 +512,15 @@ db_exist(sp, lno) * PUBLIC: int db_last __P((SCR *, recno_t *)); */ int -db_last(sp, lnop) - SCR *sp; - recno_t *lnop; +db_last( + SCR *sp, + recno_t *lnop) { DBT data, key; EXF *ep; recno_t lno; + CHAR_T *wp; + size_t wlen; /* Check for no underlying file. */ if ((ep = sp->ep) == NULL) { @@ -499,8 +535,8 @@ db_last(sp, lnop) if (ep->c_nlines != OOBLNO) { *lnop = ep->c_nlines; if (F_ISSET(sp, SC_TINPUT)) - *lnop += ((TEXT *)sp->tiq.cqh_last)->lno - - ((TEXT *)sp->tiq.cqh_first)->lno; + *lnop += ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno - + ((TEXT *)TAILQ_FIRST(sp->tiq))->lno; return (0); } @@ -508,27 +544,104 @@ db_last(sp, lnop) key.size = sizeof(lno); switch (ep->db->seq(ep->db, &key, &data, R_LAST)) { - case -1: + case -1: +alloc_err: msgq(sp, M_SYSERR, "007|unable to get last line"); *lnop = 0; return (1); - case 1: + case 1: *lnop = 0; return (0); - default: - break; + case 0: + ; } - /* Fill the cache. */ memcpy(&lno, key.data, sizeof(lno)); - ep->c_nlines = ep->c_lno = lno; - ep->c_len = data.size; - ep->c_lp = data.data; + + if (lno != ep->c_lno) { + FILE2INT(sp, data.data, data.size, wp, wlen); + + /* Fill the cache. */ + if (wp != data.data) { + BINC_GOTOW(sp, ep->c_lp, ep->c_blen, wlen); + MEMCPY(ep->c_lp, wp, wlen); + } else + ep->c_lp = data.data; + ep->c_lno = lno; + ep->c_len = wlen; + } + ep->c_nlines = lno; /* Return the value. */ *lnop = (F_ISSET(sp, SC_TINPUT) && - ((TEXT *)sp->tiq.cqh_last)->lno > lno ? - ((TEXT *)sp->tiq.cqh_last)->lno : lno); + ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno > lno ? + ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno : lno); + return (0); +} + +/* + * db_rget -- + * Retrieve a raw line from database. No cache, no conversion. + * + * PUBLIC: int db_rget __P((SCR *, recno_t, char **, size_t *)); + */ +int +db_rget( + SCR *sp, + recno_t lno, /* Line number. */ + char **pp, /* Pointer store. */ + size_t *lenp) /* Length store. */ +{ + DBT data, key; + EXF *ep; + + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) + return (1); + + /* Get the line from the underlying database. */ + key.data = &lno; + key.size = sizeof(lno); + if (ep->db->get(ep->db, &key, &data, 0)) + /* We do not report error, and do not ensure the size! */ + return (1); + + if (lenp != NULL) + *lenp = data.size; + if (pp != NULL) + *pp = data.data; + return (0); +} + +/* + * db_rset -- + * Store a line in the file. No log, no conversion. + * + * PUBLIC: int db_rset __P((SCR *, recno_t, char *, size_t)); + */ +int +db_rset( + SCR *sp, + recno_t lno, + char *p, + size_t len) +{ + DBT data, key; + EXF *ep; + + /* Check for no underlying file. */ + if ((ep = sp->ep) == NULL) + return (1); + + /* Update file. */ + key.data = &lno; + key.size = sizeof(lno); + data.data = p; + data.size = len; + if (ep->db->put(ep->db, &key, &data, 0) == -1) + /* We do not report error, and do not ensure the size! */ + return (1); + return (0); } @@ -539,9 +652,9 @@ db_last(sp, lnop) * PUBLIC: void db_err __P((SCR *, recno_t)); */ void -db_err(sp, lno) - SCR *sp; - recno_t lno; +db_err( + SCR *sp, + recno_t lno) { msgq(sp, M_ERR, "008|Error: unable to retrieve line %lu", (u_long)lno); @@ -553,11 +666,11 @@ db_err(sp, lno) * just changed. */ static int -scr_update(sp, lno, op, current) - SCR *sp; - recno_t lno; - lnop_t op; - int current; +scr_update( + SCR *sp, + recno_t lno, + lnop_t op, + int current) { EXF *ep; SCR *tsp; @@ -567,8 +680,7 @@ scr_update(sp, lno, op, current) ep = sp->ep; if (ep->refcnt != 1) - for (tsp = sp->gp->dq.cqh_first; - tsp != (void *)&sp->gp->dq; tsp = tsp->q.cqe_next) + TAILQ_FOREACH(tsp, sp->gp->dq, q) if (sp != tsp && tsp->ep == ep) if (vs_change(tsp, lno, op)) return (1); diff --git a/contrib/nvi/common/log.c b/contrib/nvi/common/log.c index 9a9fe79..eb8d85b 100644 --- a/contrib/nvi/common/log.c +++ b/contrib/nvi/common/log.c @@ -10,7 +10,7 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)log.c 10.8 (Berkeley) 3/6/96"; +static const char sccsid[] = "$Id: log.c,v 10.27 2011/07/13 06:25:50 zy Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -21,6 +21,7 @@ static const char sccsid[] = "@(#)log.c 10.8 (Berkeley) 3/6/96"; #include <errno.h> #include <fcntl.h> #include <limits.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -67,6 +68,8 @@ static void log_err __P((SCR *, char *, int)); #if defined(DEBUG) && 0 static void log_trace __P((SCR *, char *, recno_t, u_char *)); #endif +static int apply_with __P((int (*)(SCR *, recno_t, CHAR_T *, size_t), + SCR *, recno_t, u_char *, size_t)); /* Try and restart the log on failure, i.e. if we run out of memory. */ #define LOG_ERR { \ @@ -74,6 +77,15 @@ static void log_trace __P((SCR *, char *, recno_t, u_char *)); return (1); \ } +/* offset of CHAR_T string in log needs to be aligned on some systems + * because it is passed to db_set as a string + */ +typedef struct { + char data[sizeof(u_char) /* type */ + sizeof(recno_t)]; + CHAR_T str[1]; +} log_t; +#define CHAR_T_OFFSET ((char *)(((log_t*)0)->str) - (char *)0) + /* * log_init -- * Initialize the logging subsystem. @@ -81,9 +93,9 @@ static void log_trace __P((SCR *, char *, recno_t, u_char *)); * PUBLIC: int log_init __P((SCR *, EXF *)); */ int -log_init(sp, ep) - SCR *sp; - EXF *ep; +log_init( + SCR *sp, + EXF *ep) { /* * !!! @@ -117,9 +129,9 @@ log_init(sp, ep) * PUBLIC: int log_end __P((SCR *, EXF *)); */ int -log_end(sp, ep) - SCR *sp; - EXF *ep; +log_end( + SCR *sp, + EXF *ep) { /* * !!! @@ -147,8 +159,7 @@ log_end(sp, ep) * PUBLIC: int log_cursor __P((SCR *)); */ int -log_cursor(sp) - SCR *sp; +log_cursor(SCR *sp) { EXF *ep; @@ -175,15 +186,16 @@ log_cursor(sp) * Actually push a cursor record out. */ static int -log_cursor1(sp, type) - SCR *sp; - int type; +log_cursor1( + SCR *sp, + int type) { DBT data, key; EXF *ep; ep = sp->ep; - BINC_RET(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK)); + + BINC_RETC(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK)); ep->l_lp[0] = type; memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK)); @@ -212,15 +224,16 @@ log_cursor1(sp, type) * PUBLIC: int log_line __P((SCR *, recno_t, u_int)); */ int -log_line(sp, lno, action) - SCR *sp; - recno_t lno; - u_int action; +log_line( + SCR *sp, + recno_t lno, + u_int action) { DBT data, key; EXF *ep; size_t len; - char *lp; + CHAR_T *lp; + recno_t lcur; ep = sp->ep; if (F_ISSET(ep, F_NOLOG)) @@ -254,28 +267,30 @@ log_line(sp, lno, action) return (1); } len = 0; - lp = ""; + lp = L(""); } } else if (db_get(sp, lno, DBG_FATAL, &lp, &len)) return (1); - BINC_RET(sp, - ep->l_lp, ep->l_len, len + sizeof(u_char) + sizeof(recno_t)); + BINC_RETC(sp, + ep->l_lp, ep->l_len, + len * sizeof(CHAR_T) + CHAR_T_OFFSET); ep->l_lp[0] = action; memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t)); - memmove(ep->l_lp + sizeof(u_char) + sizeof(recno_t), lp, len); + memmove(ep->l_lp + CHAR_T_OFFSET, lp, len * sizeof(CHAR_T)); - key.data = &ep->l_cur; + lcur = ep->l_cur; + key.data = &lcur; key.size = sizeof(recno_t); data.data = ep->l_lp; - data.size = len + sizeof(u_char) + sizeof(recno_t); + data.size = len * sizeof(CHAR_T) + CHAR_T_OFFSET; if (ep->log->put(ep->log, &key, &data, 0) == -1) LOG_ERR; #if defined(DEBUG) && 0 switch (action) { case LOG_LINE_APPEND: - TRACE(sp, "%u: log_line: append: %lu {%u}\n", + TRACE(sp, "%lu: log_line: append: %lu {%u}\n", ep->l_cur, lno, len); break; case LOG_LINE_DELETE: @@ -312,9 +327,9 @@ log_line(sp, lno, action) * PUBLIC: int log_mark __P((SCR *, LMARK *)); */ int -log_mark(sp, lmp) - SCR *sp; - LMARK *lmp; +log_mark( + SCR *sp, + LMARK *lmp) { DBT data, key; EXF *ep; @@ -330,7 +345,7 @@ log_mark(sp, lmp) ep->l_cursor.lno = OOBLNO; } - BINC_RET(sp, ep->l_lp, + BINC_RETC(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(LMARK)); ep->l_lp[0] = LOG_MARK; memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK)); @@ -358,9 +373,9 @@ log_mark(sp, lmp) * PUBLIC: int log_backward __P((SCR *, MARK *)); */ int -log_backward(sp, rp) - SCR *sp; - MARK *rp; +log_backward( + SCR *sp, + MARK *rp) { DBT key, data; EXF *ep; @@ -414,9 +429,8 @@ log_backward(sp, rp) case LOG_LINE_DELETE: didop = 1; memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); - if (db_insert(sp, lno, p + sizeof(u_char) + - sizeof(recno_t), data.size - sizeof(u_char) - - sizeof(recno_t))) + if (apply_with(db_insert, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) goto err; ++sp->rptlines[L_ADDED]; break; @@ -425,9 +439,8 @@ log_backward(sp, rp) case LOG_LINE_RESET_B: didop = 1; memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); - if (db_set(sp, lno, p + sizeof(u_char) + - sizeof(recno_t), data.size - sizeof(u_char) - - sizeof(recno_t))) + if (apply_with(db_set, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) goto err; if (sp->rptlchange != lno) { sp->rptlchange = lno; @@ -464,8 +477,7 @@ err: F_CLR(ep, F_NOLOG); * PUBLIC: int log_setline __P((SCR *)); */ int -log_setline(sp) - SCR *sp; +log_setline(SCR *sp) { DBT key, data; EXF *ep; @@ -488,7 +500,6 @@ log_setline(sp) key.data = &ep->l_cur; /* Initialize db request. */ key.size = sizeof(recno_t); - for (;;) { --ep->l_cur; if (ep->log->get(ep->log, &key, &data, 0)) @@ -520,9 +531,8 @@ log_setline(sp) case LOG_LINE_RESET_B: memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); if (lno == sp->lno && - db_set(sp, lno, p + sizeof(u_char) + - sizeof(recno_t), data.size - sizeof(u_char) - - sizeof(recno_t))) + apply_with(db_set, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) goto err; if (sp->rptlchange != lno) { sp->rptlchange = lno; @@ -551,9 +561,9 @@ err: F_CLR(ep, F_NOLOG); * PUBLIC: int log_forward __P((SCR *, MARK *)); */ int -log_forward(sp, rp) - SCR *sp; - MARK *rp; +log_forward( + SCR *sp, + MARK *rp) { DBT key, data; EXF *ep; @@ -601,9 +611,8 @@ log_forward(sp, rp) case LOG_LINE_INSERT: didop = 1; memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); - if (db_insert(sp, lno, p + sizeof(u_char) + - sizeof(recno_t), data.size - sizeof(u_char) - - sizeof(recno_t))) + if (apply_with(db_insert, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) goto err; ++sp->rptlines[L_ADDED]; break; @@ -619,9 +628,8 @@ log_forward(sp, rp) case LOG_LINE_RESET_F: didop = 1; memmove(&lno, p + sizeof(u_char), sizeof(recno_t)); - if (db_set(sp, lno, p + sizeof(u_char) + - sizeof(recno_t), data.size - sizeof(u_char) - - sizeof(recno_t))) + if (apply_with(db_set, sp, lno, + p + CHAR_T_OFFSET, data.size - CHAR_T_OFFSET)) goto err; if (sp->rptlchange != lno) { sp->rptlchange = lno; @@ -650,10 +658,10 @@ err: F_CLR(ep, F_NOLOG); * Try and restart the log on failure, i.e. if we run out of memory. */ static void -log_err(sp, file, line) - SCR *sp; - char *file; - int line; +log_err( + SCR *sp, + char *file, + int line) { EXF *ep; @@ -666,11 +674,11 @@ log_err(sp, file, line) #if defined(DEBUG) && 0 static void -log_trace(sp, msg, rno, p) - SCR *sp; - char *msg; - recno_t rno; - u_char *p; +log_trace( + SCR *sp, + char *msg, + recno_t rno, + u_char *p) { LMARK lm; MARK m; @@ -715,3 +723,45 @@ log_trace(sp, msg, rno, p) } } #endif + +/* + * apply_with -- + * Apply a realigned line from the log db to the file db. + */ +static int +apply_with( + int (*db_func)(SCR *, recno_t, CHAR_T *, size_t), + SCR *sp, + recno_t lno, + u_char *p, + size_t len) +{ +#ifdef USE_WIDECHAR + typedef unsigned long nword; + + static size_t blen; + static nword *bp; + nword *lp = (nword *)((uintptr_t)p / sizeof(nword) * sizeof(nword)); + + if (lp != (nword *)p) { + int offl = ((uintptr_t)p - (uintptr_t)lp) << 3; + int offr = (sizeof(nword) << 3) - offl; + size_t i, cnt = (len + sizeof(nword) / 2) / sizeof(nword); + + if (len > blen) { + blen = p2roundup(MAX(len, 512)); + REALLOC(sp, bp, nword *, blen); + if (bp == NULL) + return (1); + } + for (i = 0; i < cnt; ++i) +#if BYTE_ORDER == BIG_ENDIAN + bp[i] = (lp[i] << offl) ^ (lp[i+1] >> offr); +#else + bp[i] = (lp[i] >> offl) ^ (lp[i+1] << offr); +#endif + p = (u_char *)bp; + } +#endif + return db_func(sp, lno, (CHAR_T *)p, len / sizeof(CHAR_T)); +} diff --git a/contrib/nvi/common/main.c b/contrib/nvi/common/main.c index 7e95803..16b3fb1 100644 --- a/contrib/nvi/common/main.c +++ b/contrib/nvi/common/main.c @@ -11,20 +11,19 @@ #ifndef lint static const char copyright[] = -"@(#) Copyright (c) 1992, 1993, 1994\n\ +"%Z% Copyright (c) 1992, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n\ -@(#) Copyright (c) 1992, 1993, 1994, 1995, 1996\n\ +%Z% Copyright (c) 1992, 1993, 1994, 1995, 1996\n\ Keith Bostic. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static const char sccsid[] = "@(#)main.c 10.48 (Berkeley) 10/11/96"; +static const char sccsid[] = "$Id: main.c,v 11.0 2012/10/17 06:34:37 zy Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> -#include <sys/time.h> #include <bitstring.h> #include <errno.h> @@ -50,10 +49,10 @@ static int v_obsolete __P((char *, char *[])); * PUBLIC: int editor __P((GS *, int, char *[])); */ int -editor(gp, argc, argv) - GS *gp; - int argc; - char *argv[]; +editor( + GS *gp, + int argc, + char *argv[]) { extern int optind; extern char *optarg; @@ -64,10 +63,9 @@ editor(gp, argc, argv) size_t len; u_int flags; int ch, flagchk, lflag, secure, startup, readonly, rval, silent; -#ifdef GTAGS - int gtags = 0; -#endif char *tag_f, *wsizearg, path[256]; + CHAR_T *w; + size_t wlen; /* Initialize the busy routine, if not defined by the screen. */ if (gp->scr_busy == NULL) @@ -75,19 +73,20 @@ editor(gp, argc, argv) /* Initialize the message routine, if not defined by the screen. */ if (gp->scr_msg == NULL) gp->scr_msg = vs_msg; + gp->catd = (nl_catd)-1; /* Common global structure initialization. */ - CIRCLEQ_INIT(&gp->dq); - CIRCLEQ_INIT(&gp->hq); - LIST_INIT(&gp->ecq); - LIST_INSERT_HEAD(&gp->ecq, &gp->excmd, q); + TAILQ_INIT(gp->dq); + TAILQ_INIT(gp->hq); + SLIST_INIT(gp->ecq); + SLIST_INSERT_HEAD(gp->ecq, &gp->excmd, q); gp->noprint = DEFAULT_NOPRINT; /* Structures shared by screens so stored in the GS structure. */ - CIRCLEQ_INIT(&gp->frefq); - CIRCLEQ_INIT(&gp->dcb_store.textq); - LIST_INIT(&gp->cutq); - LIST_INIT(&gp->seqq); + TAILQ_INIT(gp->frefq); + TAILQ_INIT(gp->dcb_store.textq); + SLIST_INIT(gp->cutq); + SLIST_INIT(gp->seqq); /* Set initial screen type and mode based on the program name. */ readonly = 0; @@ -116,19 +115,11 @@ editor(gp, argc, argv) /* Set the file snapshot flag. */ F_SET(gp, G_SNAPSHOT); -#ifdef GTAGS -#ifdef DEBUG - while ((ch = getopt(argc, argv, "c:D:eFGlRrSsT:t:vw:")) != EOF) -#else - while ((ch = getopt(argc, argv, "c:eFGlRrSst:vw:")) != EOF) -#endif -#else #ifdef DEBUG while ((ch = getopt(argc, argv, "c:D:eFlRrSsT:t:vw:")) != EOF) #else while ((ch = getopt(argc, argv, "c:eFlRrSst:vw:")) != EOF) #endif -#endif switch (ch) { case 'c': /* Run the command. */ /* @@ -165,11 +156,6 @@ editor(gp, argc, argv) case 'F': /* No snapshot. */ F_CLR(gp, G_SNAPSHOT); break; -#ifdef GTAGS - case 'G': /* gtags mode. */ - gtags = 1; - break; -#endif case 'l': /* Set lisp, showmatch options. */ lflag = 1; break; @@ -252,11 +238,11 @@ editor(gp, argc, argv) */ if (screen_init(gp, NULL, &sp)) { if (sp != NULL) - CIRCLEQ_INSERT_HEAD(&gp->dq, sp, q); + TAILQ_INSERT_HEAD(gp->dq, sp, q); goto err; } F_SET(sp, SC_EX); - CIRCLEQ_INSERT_HEAD(&gp->dq, sp, q); + TAILQ_INSERT_HEAD(gp->dq, sp, q); if (v_key_init(sp)) /* Special key initialization. */ goto err; @@ -268,10 +254,6 @@ editor(gp, argc, argv) } if (readonly) *oargp++ = O_READONLY; -#ifdef GTAGS - if (gtags) - *oargp++ = O_GTAGSMODE; -#endif if (secure) *oargp++ = O_SECURE; *oargp = -1; /* Options initialization. */ @@ -351,8 +333,11 @@ editor(gp, argc, argv) } /* Open a tag file if specified. */ - if (tag_f != NULL && ex_tag_first(sp, tag_f)) - goto err; + if (tag_f != NULL) { + CHAR2INT(sp, tag_f, strlen(tag_f) + 1, w, wlen); + if (ex_tag_first(sp, w)) + goto err; + } /* * Append any remaining arguments as file names. Files are recovery @@ -362,13 +347,11 @@ editor(gp, argc, argv) if (*argv != NULL) { if (sp->frp != NULL) { /* Cheat -- we know we have an extra argv slot. */ - MALLOC_NOMSG(sp, - *--argv, char *, strlen(sp->frp->name) + 1); + *--argv = strdup(sp->frp->name); if (*argv == NULL) { v_estr(gp->progname, errno, NULL); goto err; } - (void)strcpy(*argv, sp->frp->name); } sp->argv = sp->cargv = argv; F_SET(sp, SC_ARGNOFREE); @@ -386,7 +369,7 @@ editor(gp, argc, argv) if ((frp = file_add(sp, NULL)) == NULL) goto err; } else { - if ((frp = file_add(sp, (CHAR_T *)sp->argv[0])) == NULL) + if ((frp = file_add(sp, sp->argv[0])) == NULL) goto err; if (F_ISSET(sp, SC_ARGRECOVER)) F_SET(frp, FR_RECOVER); @@ -420,8 +403,8 @@ editor(gp, argc, argv) if (v_event_get(sp, &ev, 0, 0)) goto err; if (ev.e_event == E_INTERRUPT || - ev.e_event == E_CHARACTER && - (ev.e_value == K_CR || ev.e_value == K_NL)) + (ev.e_event == E_CHARACTER && + (ev.e_value == K_CR || ev.e_value == K_NL))) break; (void)gp->scr_bell(sp); } @@ -467,20 +450,16 @@ v_end(gp) (void)file_end(gp->ccl_sp, NULL, 1); (void)screen_end(gp->ccl_sp); } - while ((sp = gp->dq.cqh_first) != (void *)&gp->dq) + while ((sp = TAILQ_FIRST(gp->dq)) != NULL) (void)screen_end(sp); - while ((sp = gp->hq.cqh_first) != (void *)&gp->hq) + while ((sp = TAILQ_FIRST(gp->hq)) != NULL) (void)screen_end(sp); -#ifdef HAVE_PERL_INTERP - perl_end(gp); -#endif - #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY) { FREF *frp; /* Free FREF's. */ - while ((frp = gp->frefq.cqh_first) != (FREF *)&gp->frefq) { - CIRCLEQ_REMOVE(&gp->frefq, frp, q); + while ((frp = TAILQ_FIRST(gp->frefq)) != NULL) { + TAILQ_REMOVE(gp->frefq, frp, q); if (frp->name != NULL) free(frp->name); if (frp->tname != NULL) @@ -500,7 +479,7 @@ v_end(gp) seq_close(gp); /* Free default buffer storage. */ - (void)text_lfree(&gp->dcb_store.textq); + (void)text_lfree(gp->dcb_store.textq); /* Close message catalogs. */ msg_close(gp); @@ -516,10 +495,10 @@ v_end(gp) * it's possible that the user is sourcing a file that exits from the * editor). */ - while ((mp = gp->msgq.lh_first) != NULL) { + while ((mp = SLIST_FIRST(gp->msgq)) != NULL) { (void)fprintf(stderr, "%s%.*s", mp->mtype == M_ERR ? "ex/vi: " : "", (int)mp->len, mp->buf); - LIST_REMOVE(mp, q); + SLIST_REMOVE_HEAD(gp->msgq, q); #if defined(DEBUG) || defined(PURIFY) || defined(LIBRARY) free(mp->buf); free(mp); @@ -544,8 +523,9 @@ v_end(gp) * Convert historic arguments into something getopt(3) will like. */ static int -v_obsolete(name, argv) - char *name, *argv[]; +v_obsolete( + char *name, + char *argv[]) { size_t len; char *p; @@ -566,28 +546,26 @@ v_obsolete(name, argv) while (*++argv && strcmp(argv[0], "--")) if (argv[0][0] == '+') { if (argv[0][1] == '\0') { - MALLOC_NOMSG(NULL, argv[0], char *, 4); + argv[0] = strdup("-c$"); if (argv[0] == NULL) goto nomem; - (void)strcpy(argv[0], "-c$"); } else { p = argv[0]; len = strlen(argv[0]); - MALLOC_NOMSG(NULL, argv[0], char *, len + 2); + argv[0] = malloc(len + 2); if (argv[0] == NULL) goto nomem; argv[0][0] = '-'; argv[0][1] = 'c'; - (void)strcpy(argv[0] + 2, p + 1); + (void)strlcpy(argv[0] + 2, p + 1, len); } } else if (argv[0][0] == '-') if (argv[0][1] == '\0') { - MALLOC_NOMSG(NULL, argv[0], char *, 3); + argv[0] = strdup("-s"); if (argv[0] == NULL) { nomem: v_estr(name, errno, NULL); return (1); } - (void)strcpy(argv[0], "-s"); } else if ((argv[0][1] == 'c' || argv[0][1] == 'T' || argv[0][1] == 't' || argv[0][1] == 'w') && @@ -598,8 +576,7 @@ nomem: v_estr(name, errno, NULL); #ifdef DEBUG static void -attach(gp) - GS *gp; +attach(GS *gp) { int fd; char ch; @@ -624,9 +601,10 @@ attach(gp) #endif static void -v_estr(name, eno, msg) - char *name, *msg; - int eno; +v_estr( + char *name, + int eno, + char *msg) { (void)fprintf(stderr, "%s", name); if (msg != NULL) diff --git a/contrib/nvi/common/mark.c b/contrib/nvi/common/mark.c index 0ac1fc2..7a95439 100644 --- a/contrib/nvi/common/mark.c +++ b/contrib/nvi/common/mark.c @@ -10,11 +10,12 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)mark.c 10.13 (Berkeley) 7/19/96"; +static const char sccsid[] = "$Id: mark.c,v 10.14 2011/07/04 14:42:58 zy Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> +#include <sys/time.h> #include <bitstring.h> #include <errno.h> @@ -28,7 +29,7 @@ static const char sccsid[] = "@(#)mark.c 10.13 (Berkeley) 7/19/96"; static LMARK *mark_find __P((SCR *, ARG_CHAR_T)); /* - * Marks are maintained in a key sorted doubly linked list. We can't + * Marks are maintained in a key sorted singly linked list. We can't * use arrays because we have no idea how big an index key could be. * The underlying assumption is that users don't have more than, say, * 10 marks at any one time, so this will be is fast enough. @@ -65,9 +66,9 @@ static LMARK *mark_find __P((SCR *, ARG_CHAR_T)); * PUBLIC: int mark_init __P((SCR *, EXF *)); */ int -mark_init(sp, ep) - SCR *sp; - EXF *ep; +mark_init( + SCR *sp, + EXF *ep) { /* * !!! @@ -75,7 +76,7 @@ mark_init(sp, ep) * * Set up the marks. */ - LIST_INIT(&ep->marks); + SLIST_INIT(ep->marks); return (0); } @@ -86,9 +87,9 @@ mark_init(sp, ep) * PUBLIC: int mark_end __P((SCR *, EXF *)); */ int -mark_end(sp, ep) - SCR *sp; - EXF *ep; +mark_end( + SCR *sp, + EXF *ep) { LMARK *lmp; @@ -96,8 +97,8 @@ mark_end(sp, ep) * !!! * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. */ - while ((lmp = ep->marks.lh_first) != NULL) { - LIST_REMOVE(lmp, q); + while ((lmp = SLIST_FIRST(ep->marks)) != NULL) { + SLIST_REMOVE_HEAD(ep->marks, q); free(lmp); } return (0); @@ -110,11 +111,11 @@ mark_end(sp, ep) * PUBLIC: int mark_get __P((SCR *, ARG_CHAR_T, MARK *, mtype_t)); */ int -mark_get(sp, key, mp, mtype) - SCR *sp; - ARG_CHAR_T key; - MARK *mp; - mtype_t mtype; +mark_get( + SCR *sp, + ARG_CHAR_T key, + MARK *mp, + mtype_t mtype) { LMARK *lmp; @@ -155,11 +156,11 @@ mark_get(sp, key, mp, mtype) * PUBLIC: int mark_set __P((SCR *, ARG_CHAR_T, MARK *, int)); */ int -mark_set(sp, key, value, userset) - SCR *sp; - ARG_CHAR_T key; - MARK *value; - int userset; +mark_set( + SCR *sp, + ARG_CHAR_T key, + MARK *value, + int userset) { LMARK *lmp, *lmt; @@ -176,9 +177,9 @@ mark_set(sp, key, value, userset) if (lmp == NULL || lmp->name != key) { MALLOC_RET(sp, lmt, LMARK *, sizeof(LMARK)); if (lmp == NULL) { - LIST_INSERT_HEAD(&sp->ep->marks, lmt, q); + SLIST_INSERT_HEAD(sp->ep->marks, lmt, q); } else - LIST_INSERT_AFTER(lmp, lmt, q); + SLIST_INSERT_AFTER(lmp, lmt, q); lmp = lmt; } else if (!userset && !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET)) @@ -197,20 +198,21 @@ mark_set(sp, key, value, userset) * where it would go. */ static LMARK * -mark_find(sp, key) - SCR *sp; - ARG_CHAR_T key; +mark_find( + SCR *sp, + ARG_CHAR_T key) { - LMARK *lmp, *lastlmp; + LMARK *lmp, *lastlmp = NULL; /* * Return the requested mark or the slot immediately before * where it should go. */ - for (lastlmp = NULL, lmp = sp->ep->marks.lh_first; - lmp != NULL; lastlmp = lmp, lmp = lmp->q.le_next) + SLIST_FOREACH(lmp, sp->ep->marks, q) { if (lmp->name >= key) return (lmp->name == key ? lmp : lastlmp); + lastlmp = lmp; + } return (lastlmp); } @@ -221,10 +223,10 @@ mark_find(sp, key) * PUBLIC: int mark_insdel __P((SCR *, lnop_t, recno_t)); */ int -mark_insdel(sp, op, lno) - SCR *sp; - lnop_t op; - recno_t lno; +mark_insdel( + SCR *sp, + lnop_t op, + recno_t lno) { LMARK *lmp; recno_t lline; @@ -234,8 +236,7 @@ mark_insdel(sp, op, lno) /* All insert/append operations are done as inserts. */ abort(); case LINE_DELETE: - for (lmp = sp->ep->marks.lh_first; - lmp != NULL; lmp = lmp->q.le_next) + SLIST_FOREACH(lmp, sp->ep->marks, q) if (lmp->lno >= lno) if (lmp->lno == lno) { F_SET(lmp, MARK_DELETED); @@ -265,8 +266,7 @@ mark_insdel(sp, op, lno) return (0); } - for (lmp = sp->ep->marks.lh_first; - lmp != NULL; lmp = lmp->q.le_next) + SLIST_FOREACH(lmp, sp->ep->marks, q) if (lmp->lno >= lno) ++lmp->lno; break; diff --git a/contrib/nvi/common/mark.h b/contrib/nvi/common/mark.h index 9c63e18..44b8a19 100644 --- a/contrib/nvi/common/mark.h +++ b/contrib/nvi/common/mark.h @@ -6,7 +6,7 @@ * * See the LICENSE file for redistribution information. * - * @(#)mark.h 10.3 (Berkeley) 3/6/96 + * $Id: mark.h,v 10.6 2011/07/04 14:41:51 zy Exp $ */ /* @@ -28,9 +28,10 @@ struct _mark { }; struct _lmark { - LIST_ENTRY(_lmark) q; /* Linked list of marks. */ + SLIST_ENTRY(_lmark) q; /* Linked list of marks. */ recno_t lno; /* Line number. */ size_t cno; /* Column number. */ + /* XXXX Needed ? Can non ascii-chars be mark names ? */ CHAR_T name; /* Mark name. */ #define MARK_DELETED 0x01 /* Mark was deleted. */ diff --git a/contrib/nvi/common/mem.h b/contrib/nvi/common/mem.h index af42e6b..b2b44b6 100644 --- a/contrib/nvi/common/mem.h +++ b/contrib/nvi/common/mem.h @@ -6,13 +6,21 @@ * * See the LICENSE file for redistribution information. * - * @(#)mem.h 10.7 (Berkeley) 3/30/96 + * $Id: mem.h,v 10.17 2012/10/07 00:40:29 zy Exp $ */ +#ifdef DEBUG +#define CHECK_TYPE(type, var) \ + type L__lp __attribute__((unused)) = var; +#else +#define CHECK_TYPE(type, var) +#endif + /* Increase the size of a malloc'd buffer. Two versions, one that * returns, one that jumps to an error label. */ -#define BINC_GOTO(sp, lp, llen, nlen) { \ +#define BINC_GOTO(sp, type, lp, llen, nlen) { \ + CHECK_TYPE(type *, lp) \ void *L__bincp; \ if ((nlen) > llen) { \ if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \ @@ -24,7 +32,12 @@ lp = L__bincp; \ } \ } -#define BINC_RET(sp, lp, llen, nlen) { \ +#define BINC_GOTOC(sp, lp, llen, nlen) \ + BINC_GOTO(sp, char, lp, llen, nlen) +#define BINC_GOTOW(sp, lp, llen, nlen) \ + BINC_GOTO(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T)) +#define BINC_RET(sp, type, lp, llen, nlen) { \ + CHECK_TYPE(type *, lp) \ void *L__bincp; \ if ((nlen) > llen) { \ if ((L__bincp = binc(sp, lp, &(llen), nlen)) == NULL) \ @@ -36,65 +49,89 @@ lp = L__bincp; \ } \ } +#define BINC_RETC(sp, lp, llen, nlen) \ + BINC_RET(sp, char, lp, llen, nlen) +#define BINC_RETW(sp, lp, llen, nlen) \ + BINC_RET(sp, CHAR_T, lp, llen, (nlen) * sizeof(CHAR_T)) /* * Get some temporary space, preferably from the global temporary buffer, * from a malloc'd buffer otherwise. Two versions, one that returns, one * that jumps to an error label. */ -#define GET_SPACE_GOTO(sp, bp, blen, nlen) { \ +#define GET_SPACE_GOTO(sp, type, bp, blen, nlen) { \ + CHECK_TYPE(type *, bp) \ GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) { \ bp = NULL; \ blen = 0; \ - BINC_GOTO(sp, bp, blen, nlen); \ + BINC_GOTO(sp, type, bp, blen, nlen); \ } else { \ - BINC_GOTO(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ - bp = L__gp->tmp_bp; \ + BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ blen = L__gp->tmp_blen; \ F_SET(L__gp, G_TMP_INUSE); \ } \ } -#define GET_SPACE_RET(sp, bp, blen, nlen) { \ +#define GET_SPACE_GOTOC(sp, bp, blen, nlen) \ + GET_SPACE_GOTO(sp, char, bp, blen, nlen) +#define GET_SPACE_GOTOW(sp, bp, blen, nlen) \ + GET_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) +#define GET_SPACE_RET(sp, type, bp, blen, nlen) { \ + CHECK_TYPE(type *, bp) \ GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ if (L__gp == NULL || F_ISSET(L__gp, G_TMP_INUSE)) { \ bp = NULL; \ blen = 0; \ - BINC_RET(sp, bp, blen, nlen); \ + BINC_RET(sp, type, bp, blen, nlen); \ } else { \ - BINC_RET(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ - bp = L__gp->tmp_bp; \ + BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ blen = L__gp->tmp_blen; \ F_SET(L__gp, G_TMP_INUSE); \ } \ } +#define GET_SPACE_RETC(sp, bp, blen, nlen) \ + GET_SPACE_RET(sp, char, bp, blen, nlen) +#define GET_SPACE_RETW(sp, bp, blen, nlen) \ + GET_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) /* * Add space to a GET_SPACE returned buffer. Two versions, one that * returns, one that jumps to an error label. */ -#define ADD_SPACE_GOTO(sp, bp, blen, nlen) { \ +#define ADD_SPACE_GOTO(sp, type, bp, blen, nlen) { \ + CHECK_TYPE(type *, bp) \ GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ - if (L__gp == NULL || bp == L__gp->tmp_bp) { \ + if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) { \ F_CLR(L__gp, G_TMP_INUSE); \ - BINC_GOTO(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ - bp = L__gp->tmp_bp; \ + BINC_GOTOC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ blen = L__gp->tmp_blen; \ F_SET(L__gp, G_TMP_INUSE); \ } else \ - BINC_GOTO(sp, bp, blen, nlen); \ -} -#define ADD_SPACE_RET(sp, bp, blen, nlen) { \ + BINC_GOTO(sp, type, bp, blen, nlen); \ +} +#define ADD_SPACE_GOTOC(sp, bp, blen, nlen) \ + ADD_SPACE_GOTO(sp, char, bp, blen, nlen) +#define ADD_SPACE_GOTOW(sp, bp, blen, nlen) \ + ADD_SPACE_GOTO(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) +#define ADD_SPACE_RET(sp, type, bp, blen, nlen) { \ + CHECK_TYPE(type *, bp) \ GS *L__gp = (sp) == NULL ? NULL : (sp)->gp; \ - if (L__gp == NULL || bp == L__gp->tmp_bp) { \ + if (L__gp == NULL || bp == (type *)L__gp->tmp_bp) { \ F_CLR(L__gp, G_TMP_INUSE); \ - BINC_RET(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ - bp = L__gp->tmp_bp; \ + BINC_RETC(sp, L__gp->tmp_bp, L__gp->tmp_blen, nlen); \ + bp = (type *) L__gp->tmp_bp; \ blen = L__gp->tmp_blen; \ F_SET(L__gp, G_TMP_INUSE); \ } else \ - BINC_RET(sp, bp, blen, nlen); \ + BINC_RET(sp, type, bp, blen, nlen); \ } +#define ADD_SPACE_RETC(sp, bp, blen, nlen) \ + ADD_SPACE_RET(sp, char, bp, blen, nlen) +#define ADD_SPACE_RETW(sp, bp, blen, nlen) \ + ADD_SPACE_RET(sp, CHAR_T, bp, blen, (nlen) * sizeof(CHAR_T)) /* Free a GET_SPACE returned buffer. */ #define FREE_SPACE(sp, bp, blen) { \ @@ -104,6 +141,10 @@ else \ free(bp); \ } +#define FREE_SPACEW(sp, bp, blen) { \ + CHECK_TYPE(CHAR_T *, bp) \ + FREE_SPACE(sp, (char *)bp, blen); \ +} /* * Malloc a buffer, casting the return pointer. Various versions. @@ -150,19 +191,50 @@ return (1); \ } \ } + /* - * XXX - * Don't depend on realloc(NULL, size) working. + * Resize a buffer, free any already held memory if we can't get more. + * FreeBSD's reallocf(3) does the same thing, but it's not portable yet. */ #define REALLOC(sp, p, cast, size) { \ - if ((p = (cast)(p == NULL ? \ - malloc(size) : realloc(p, size))) == NULL) \ + cast newp; \ + if ((newp = (cast)realloc(p, size)) == NULL) { \ + if (p != NULL) \ + free(p); \ msgq(sp, M_SYSERR, NULL); \ + } \ + p = newp; \ } /* - * Versions of memmove(3) and memset(3) that use the size of the + * Versions of bcopy(3) and bzero(3) that use the size of the * initial pointer to figure out how much memory to manipulate. */ -#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(*(p))) -#define MEMSET(p, value, len) memset(p, value, (len) * sizeof(*(p))) +#define BCOPY(p, t, len) bcopy(p, t, (len) * sizeof(*(p))) +#define BZERO(p, len) bzero(p, (len) * sizeof(*(p))) + +/* + * p2roundup -- + * Get next power of 2; convenient for realloc. + * + * Reference: FreeBSD /usr/src/lib/libc/stdio/getdelim.c + */ +static __inline size_t +p2roundup(size_t n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; +#if SIZE_T_MAX > 0xffffffffU + n |= n >> 32; +#endif + n++; + return (n); +} + +/* Additional TAILQ helper. */ +#define TAILQ_ENTRY_ISVALID(elm, field) \ + ((elm)->field.tqe_prev != NULL) diff --git a/contrib/nvi/common/msg.c b/contrib/nvi/common/msg.c index 9fbd738..c0930b8 100644 --- a/contrib/nvi/common/msg.c +++ b/contrib/nvi/common/msg.c @@ -10,31 +10,25 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)msg.c 10.48 (Berkeley) 9/15/96"; +static const char sccsid[] = "$Id: msg.c,v 11.0 2012/10/17 06:34:37 zy Exp $"; #endif /* not lint */ -#include <sys/param.h> -#include <sys/types.h> /* XXX: param.h may not have included types.h */ +#include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> -#include <sys/time.h> #include <bitstring.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <limits.h> +#include <locale.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#ifdef __STDC__ -#include <stdarg.h> -#else -#include <varargs.h> -#endif - #include "common.h" #include "../vi/vi.h" @@ -45,15 +39,11 @@ static const char sccsid[] = "@(#)msg.c 10.48 (Berkeley) 9/15/96"; * PUBLIC: void msgq __P((SCR *, mtype_t, const char *, ...)); */ void -#ifdef __STDC__ -msgq(SCR *sp, mtype_t mt, const char *fmt, ...) -#else -msgq(sp, mt, fmt, va_alist) - SCR *sp; - mtype_t mt; - const char *fmt; - va_dcl -#endif +msgq( + SCR *sp, + mtype_t mt, + const char *fmt, + ...) { #ifndef NL_ARGMAX #define __NL_ARGMAX 20 /* Set to 9 by System V. */ @@ -66,12 +56,17 @@ msgq(sp, mt, fmt, va_alist) } str[__NL_ARGMAX]; #endif static int reenter; /* STATIC: Re-entrancy check. */ - CHAR_T ch; GS *gp; - size_t blen, cnt1, cnt2, len, mlen, nlen, soff; - const char *p, *t, *u; - char *bp, *mp, *rbp, *s_rbp; + size_t blen, len, mlen, nlen; + const char *p; + char *bp, *mp; va_list ap; +#ifndef NL_ARGMAX + int ch; + char *rbp, *s_rbp; + const char *t, *u; + size_t cnt1, cnt2, soff; +#endif /* * !!! @@ -130,7 +125,7 @@ retry: FREE_SPACE(sp, bp, blen); } bp = NULL; blen = 0; - GET_SPACE_GOTO(sp, bp, blen, nlen); + GET_SPACE_GOTOC(sp, bp, blen, nlen); /* * Error prefix. @@ -157,8 +152,12 @@ retry: FREE_SPACE(sp, bp, blen); */ if ((mt == M_ERR || mt == M_SYSERR) && sp != NULL && gp != NULL && gp->if_name != NULL) { - for (p = gp->if_name; *p != '\0'; ++p) { - len = snprintf(mp, REM, "%s", KEY_NAME(sp, *p)); + CHAR_T *wp; + size_t wlen; + + CHAR2INT(sp, gp->if_name, strlen(gp->if_name) + 1, wp, wlen); + for (; *wp != '\0'; ++wp) { + len = snprintf(mp, REM, "%s", KEY_NAME(sp, *wp)); mp += len; if ((mlen += len) > blen) goto retry; @@ -272,12 +271,10 @@ retry: FREE_SPACE(sp, bp, blen); fmt = rbp; #endif +#ifndef NL_ARGMAX format: /* Format the arguments into the string. */ -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); #endif + va_start(ap, fmt); len = vsnprintf(mp, REM, fmt, ap); va_end(ap); if (len >= nlen) @@ -347,28 +344,56 @@ nofmt: mp += len; (void)fprintf(stderr, "%.*s", (int)mlen, bp); /* Cleanup. */ -ret: FREE_SPACE(sp, bp, blen); +#ifndef NL_ARGMAX +ret: +#endif + FREE_SPACE(sp, bp, blen); alloc_err: reenter = 0; } /* + * msgq_wstr -- + * Display a message with an embedded string. + * + * PUBLIC: void msgq_wstr __P((SCR *, mtype_t, const CHAR_T *, const char *)); + */ +void +msgq_wstr( + SCR *sp, + mtype_t mtype, + const CHAR_T *str, + const char *fmt) +{ + size_t nlen; + CONST char *nstr; + + if (str == NULL) { + msgq(sp, mtype, "%s", fmt); + return; + } + INT2CHAR(sp, str, STRLEN(str) + 1, nstr, nlen); + msgq_str(sp, mtype, nstr, fmt); +} + +/* * msgq_str -- * Display a message with an embedded string. * - * PUBLIC: void msgq_str __P((SCR *, mtype_t, char *, char *)); + * PUBLIC: void msgq_str __P((SCR *, mtype_t, const char *, const char *)); */ void -msgq_str(sp, mtype, str, fmt) - SCR *sp; - mtype_t mtype; - char *str, *fmt; +msgq_str( + SCR *sp, + mtype_t mtype, + const char *str, + const char *fmt) { int nf, sv_errno; char *p; if (str == NULL) { - msgq(sp, mtype, fmt); + msgq(sp, mtype, "%s", fmt); return; } @@ -401,8 +426,7 @@ msgq_str(sp, mtype, str, fmt) * PUBLIC: void mod_rpt __P((SCR *)); */ void -mod_rpt(sp) - SCR *sp; +mod_rpt(SCR *sp) { static char * const action[] = { "293|added", @@ -461,7 +485,7 @@ mod_rpt(sp) } /* Build and display the message. */ - GET_SPACE_GOTO(sp, bp, blen, sizeof(action) * MAXNUM + 1); + GET_SPACE_GOTOC(sp, bp, blen, sizeof(action) * MAXNUM + 1); for (p = bp, first = 1, tlen = 0, ap = action, cnt = 0; cnt < ARSIZE(action); ++ap, ++cnt) if (sp->rptlines[cnt] != 0) { @@ -512,27 +536,32 @@ alloc_err: * PUBLIC: void msgq_status __P((SCR *, recno_t, u_int)); */ void -msgq_status(sp, lno, flags) - SCR *sp; - recno_t lno; - u_int flags; +msgq_status( + SCR *sp, + recno_t lno, + u_int flags) { - static int poisoned; recno_t last; size_t blen, len; int cnt, needsep; const char *t; - char **ap, *bp, *np, *p, *s; + char **ap, *bp, *np, *p, *s, *ep; + CHAR_T *wp; + size_t wlen; /* Get sufficient memory. */ len = strlen(sp->frp->name); - GET_SPACE_GOTO(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128); + GET_SPACE_GOTOC(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128); p = bp; + ep = bp + blen; + + /* Convert the filename. */ + CHAR2INT(sp, sp->frp->name, len + 1, wp, wlen); /* Copy in the filename. */ - for (p = bp, t = sp->frp->name; *t != '\0'; ++t) { - len = KEY_LEN(sp, *t); - memcpy(p, KEY_NAME(sp, *t), len); + for (; *wp != '\0'; ++wp) { + len = KEY_LEN(sp, *wp); + memcpy(p, KEY_NAME(sp, *wp), len); p += len; } np = p; @@ -543,7 +572,7 @@ msgq_status(sp, lno, flags) if (F_ISSET(sp, SC_STATUS_CNT) && sp->argv != NULL) { for (cnt = 0, ap = sp->argv; *ap != NULL; ++ap, ++cnt); if (cnt > 1) { - (void)sprintf(p, + (void)snprintf(p, ep - p, msg_cat(sp, "317|%d files to edit", NULL), cnt); p += strlen(p); *p++ = ':'; @@ -617,18 +646,18 @@ msgq_status(sp, lno, flags) memcpy(p, t, len); p += len; } else { - t = msg_cat(sp, "027|line %lu of %lu [%lu%%]", &len); - (void)sprintf(p, t, (u_long)lno, (u_long)last, - (u_long)(lno * 100) / last); + t = msg_cat(sp, "027|line %lu of %lu [%ld%%]", &len); + (void)snprintf(p, ep - p, t, lno, last, + ((u_long)lno * 100) / last); p += strlen(p); } } else { t = msg_cat(sp, "029|line %lu", &len); - (void)sprintf(p, t, (u_long)lno); + (void)snprintf(p, ep - p, t, (u_long)lno); p += strlen(p); } #ifdef DEBUG - (void)sprintf(p, " (pid %lu)", (u_long)getpid()); + (void)snprintf(p, ep - p, " (pid %lu)", (u_long)getpid()); p += strlen(p); #endif *p++ = '\n'; @@ -679,9 +708,9 @@ alloc_err: * PUBLIC: int msg_open __P((SCR *, char *)); */ int -msg_open(sp, file) - SCR *sp; - char *file; +msg_open( + SCR *sp, + char *file) { /* * !!! @@ -693,54 +722,50 @@ msg_open(sp, file) * message will be repeated every time nvi is started up. */ static int first = 1; - DB *db; - DBT data, key; - recno_t msgno; - char *p, *t, buf[MAXPATHLEN]; - - if ((p = strrchr(file, '/')) != NULL && p[1] == '\0' && - ((t = getenv("LC_MESSAGES")) != NULL && t[0] != '\0' || - (t = getenv("LANG")) != NULL && t[0] != '\0')) { - (void)snprintf(buf, sizeof(buf), "%s%s", file, t); - p = buf; - } else - p = file; - if ((db = dbopen(p, - O_NONBLOCK | O_RDONLY, 0, DB_RECNO, NULL)) == NULL) { - if (first) { - first = 0; + nl_catd catd; + char *p; + int rval = 0; + + if ((p = strrchr(file, '/')) != NULL && p[1] == '\0') { + /* Confirms to XPG4. */ + if ((p = join(file, setlocale(LC_MESSAGES, NULL))) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + } else { + /* Make sure it's recognized as a path by catopen(3). */ + if ((p = join(".", file)) == NULL) { + msgq(sp, M_SYSERR, NULL); return (1); } - msgq_str(sp, M_SYSERR, p, "%s"); - return (1); } - - /* - * Test record 1 for the magic string. The msgq call is here so - * the message catalog build finds it. - */ -#define VMC "VI_MESSAGE_CATALOG" - key.data = &msgno; - key.size = sizeof(recno_t); - msgno = 1; - if (db->get(db, &key, &data, 0) != 0 || - data.size != sizeof(VMC) - 1 || - memcmp(data.data, VMC, sizeof(VMC) - 1)) { - (void)db->close(db); + errno = 0; + if ((catd = catopen(p, NL_CAT_LOCALE)) == (nl_catd)-1) { if (first) { first = 0; - return (1); + rval = 1; + goto ret; } - msgq_str(sp, M_ERR, p, - "030|The file %s is not a message catalog"); - return (1); + + /* + * POSIX.1-2008 gives no instruction on how to report a + * corrupt catalog file. Errno == 0 is not rare; add + * EFTYPE, which is seen on FreeBSD, for a good measure. + */ + if (errno == 0 || errno == EFTYPE) + msgq_str(sp, M_ERR, p, + "030|The file %s is not a message catalog"); + else + msgq_str(sp, M_SYSERR, p, "%s"); + rval = 1; + goto ret; } first = 0; - if (sp->gp->msg != NULL) - (void)sp->gp->msg->close(sp->gp->msg); - sp->gp->msg = db; - return (0); + msg_close(sp->gp); + sp->gp->catd = catd; +ret: free(p); + return (rval); } /* @@ -750,11 +775,10 @@ msg_open(sp, file) * PUBLIC: void msg_close __P((GS *)); */ void -msg_close(gp) - GS *gp; +msg_close(GS *gp) { - if (gp->msg != NULL) - (void)gp->msg->close(gp->msg); + if (gp->catd != (nl_catd)-1) + (void)catclose(gp->catd); } /* @@ -764,10 +788,10 @@ msg_close(gp) * PUBLIC: const char *msg_cmsg __P((SCR *, cmsg_t, size_t *)); */ const char * -msg_cmsg(sp, which, lenp) - SCR *sp; - cmsg_t which; - size_t *lenp; +msg_cmsg( + SCR *sp, + cmsg_t which, + size_t *lenp) { switch (which) { case CMSG_CONF: @@ -802,14 +826,14 @@ msg_cmsg(sp, which, lenp) * PUBLIC: const char *msg_cat __P((SCR *, const char *, size_t *)); */ const char * -msg_cat(sp, str, lenp) - SCR *sp; - const char *str; - size_t *lenp; +msg_cat( + SCR *sp, + const char *str, + size_t *lenp) { GS *gp; - DBT data, key; - recno_t msgno; + char *p; + int msgno; /* * If it's not a catalog message, i.e. has doesn't have a leading @@ -817,28 +841,16 @@ msg_cat(sp, str, lenp) */ if (isdigit(str[0]) && isdigit(str[1]) && isdigit(str[2]) && str[3] == '|') { - key.data = &msgno; - key.size = sizeof(recno_t); msgno = atoi(str); + str = &str[4]; - /* - * XXX - * Really sleazy hack -- we put an extra character on the - * end of the format string, and then we change it to be - * the nul termination of the string. There ought to be - * a better way. Once we can allocate multiple temporary - * memory buffers, maybe we can use one of them instead. - */ gp = sp == NULL ? NULL : sp->gp; - if (gp != NULL && gp->msg != NULL && - gp->msg->get(gp->msg, &key, &data, 0) == 0 && - data.size != 0) { + if (gp != NULL && gp->catd != (nl_catd)-1 && + (p = catgets(gp->catd, 1, msgno, str)) != NULL) { if (lenp != NULL) - *lenp = data.size - 1; - ((char *)data.data)[data.size - 1] = '\0'; - return (data.data); + *lenp = strlen(p); + return (p); } - str = &str[4]; } if (lenp != NULL) *lenp = strlen(str); @@ -852,19 +864,22 @@ msg_cat(sp, str, lenp) * PUBLIC: char *msg_print __P((SCR *, const char *, int *)); */ char * -msg_print(sp, s, needfree) - SCR *sp; - const char *s; - int *needfree; +msg_print( + SCR *sp, + const char *s, + int *needfree) { size_t blen, nlen; - const char *cp; char *bp, *ep, *p, *t; + CHAR_T *wp, *cp; + size_t wlen; *needfree = 0; - for (cp = s; *cp != '\0'; ++cp) - if (!isprint(*cp)) + /* XXX Not good for debugging ex_read & ex_filter.*/ + CHAR2INT5(sp, EXP(sp)->ibcw, (char *)s, strlen(s) + 1, wp, wlen); + for (cp = wp; *cp != '\0'; ++cp) + if (!ISPRINT(*cp)) break; if (*cp == '\0') return ((char *)s); /* SAFE: needfree set to 0. */ @@ -875,21 +890,21 @@ retry: if (sp == NULL) free(bp); else FREE_SPACE(sp, bp, blen); - needfree = 0; + *needfree = 0; } nlen += 256; if (sp == NULL) { if ((bp = malloc(nlen)) == NULL) goto alloc_err; } else - GET_SPACE_GOTO(sp, bp, blen, nlen); + GET_SPACE_GOTOC(sp, bp, blen, nlen); if (0) { alloc_err: return (""); } *needfree = 1; - for (p = bp, ep = (bp + blen) - 1, cp = s; *cp != '\0' && p < ep; ++cp) - for (t = KEY_NAME(sp, *cp); *t != '\0' && p < ep; *p++ = *t++); + for (p = bp, ep = (bp + blen) - 1; *wp != '\0' && p < ep; ++wp) + for (t = KEY_NAME(sp, *wp); *t != '\0' && p < ep; *p++ = *t++); if (p == ep) goto retry; *p = '\0'; diff --git a/contrib/nvi/common/msg.h b/contrib/nvi/common/msg.h index b10f4cc..d65bb1a 100644 --- a/contrib/nvi/common/msg.h +++ b/contrib/nvi/common/msg.h @@ -52,9 +52,9 @@ typedef enum { * messages. */ typedef struct _msgh MSGH; /* MSGS list head structure. */ -LIST_HEAD(_msgh, _msg); +SLIST_HEAD(_msgh, _msg); struct _msg { - LIST_ENTRY(_msg) q; /* Linked list of messages. */ + SLIST_ENTRY(_msg) q; /* Linked list of messages. */ mtype_t mtype; /* Message type: M_NONE, M_ERR, M_INFO. */ char *buf; /* Message buffer. */ size_t len; /* Message length. */ diff --git a/contrib/nvi/common/multibyte.h b/contrib/nvi/common/multibyte.h new file mode 100644 index 0000000..40e3521 --- /dev/null +++ b/contrib/nvi/common/multibyte.h @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + * + * $Id: multibyte.h,v 1.32 2012/10/07 01:35:58 zy Exp $ + */ + +#ifndef MULTIBYTE_H +#define MULTIBYTE_H + +/* + * Fundamental character types. + * + * CHAR_T An integral type that can hold any character. + * ARG_CHAR_T The type of a CHAR_T when passed as an argument using + * traditional promotion rules. It should also be able + * to be compared against any CHAR_T for equality without + * problems. + * UCHAR_T The shortest unified character type (8-bit clean). + * RCHAR_T The character type used by the internal regex engine. + * + * If no integral type can hold a character, don't even try the port. + */ +typedef int ARG_CHAR_T; + +#ifdef USE_WIDECHAR +#include <wchar.h> +#include <wctype.h> + +typedef wchar_t CHAR_T; +typedef wint_t UCHAR_T; +typedef wchar_t RCHAR_T; +#define REOF WEOF + +#define STRLEN wcslen +#define STRTOL wcstol +#define STRTOUL wcstoul +#define SPRINTF swprintf +#define STRCMP wcscmp +#define STRPBRK wcspbrk +#define ISBLANK iswblank +#define ISCNTRL iswcntrl +#define ISDIGIT iswdigit +#define ISXDIGIT iswxdigit +#define ISGRAPH iswgraph +#define ISLOWER iswlower +#define ISPRINT iswprint +#define ISPUNCT iswpunct +#define ISSPACE iswspace +#define ISUPPER iswupper +#define TOLOWER towlower +#define TOUPPER towupper +#define STRSET wmemset +#define STRCHR wcschr +#define STRRCHR wcsrchr +#define GETC getwc + +#define L(ch) L ## ch +#define WS "%ls" +#define WVS "%*ls" +#define WC "%lc" + +#else +typedef u_char CHAR_T; +typedef u_char UCHAR_T; +typedef char RCHAR_T; +#define REOF EOF + +#define STRLEN strlen +#define STRTOL(a,b,c) (strtol(a,(char**)b,c)) +#define STRTOUL(a,b,c) (strtoul(a,(char**)b,c)) +#define SPRINTF snprintf +#define STRCMP strcmp +#define STRPBRK strpbrk +#define ISBLANK isblank +#define ISCNTRL iscntrl +#define ISDIGIT isdigit +#define ISXDIGIT isxdigit +#define ISGRAPH isgraph +#define ISLOWER islower +#define ISPRINT isprint +#define ISPUNCT ispunct +#define ISSPACE isspace +#define ISUPPER isupper +#define TOLOWER tolower +#define TOUPPER toupper +#define STRSET memset +#define STRCHR strchr +#define STRRCHR strrchr +#define GETC getc + +#define L(ch) ch +#define WS "%s" +#define WVS "%*s" +#define WC "%c" + +#endif + +#if defined(USE_WIDECHAR) && defined(DEBUG) +#define MEMCPY wmemcpy +#define MEMMOVE wmemmove +#define MEMCMP wmemcmp +#else +#define MEMCPY(p, t, len) memcpy(p, t, (len) * sizeof(CHAR_T)) +#define MEMMOVE(p, t, len) memmove(p, t, (len) * sizeof(CHAR_T)) +#define MEMCMP(p, t, len) memcmp(p, t, (len) * sizeof(CHAR_T)) +#endif + +#define SIZE(w) (sizeof(w) / sizeof(*w)) + +#endif diff --git a/contrib/nvi/common/options.c b/contrib/nvi/common/options.c index dea4eba..71a5e43 100644 --- a/contrib/nvi/common/options.c +++ b/contrib/nvi/common/options.c @@ -10,13 +10,12 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)options.c 10.51 (Berkeley) 10/14/96"; +static const char sccsid[] = "$Id: options.c,v 10.73 2012/10/09 06:14:07 zy Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> -#include <sys/time.h> #include <bitstring.h> #include <ctype.h> @@ -35,6 +34,12 @@ static int opts_abbcmp __P((const void *, const void *)); static int opts_cmp __P((const void *, const void *)); static int opts_print __P((SCR *, OPTLIST const *)); +#ifdef USE_WIDECHAR +#define OPT_WC 0 +#else +#define OPT_WC (OPT_NOSAVE | OPT_NDISP) +#endif + /* * O'Reilly noted options and abbreviations are from "Learning the VI Editor", * Fifth Edition, May 1992. There's no way of knowing what systems they are @@ -45,77 +50,81 @@ static int opts_print __P((SCR *, OPTLIST const *)); */ OPTLIST const optlist[] = { /* O_ALTWERASE 4.4BSD */ - {"altwerase", f_altwerase, OPT_0BOOL, 0}, + {L("altwerase"), f_altwerase, OPT_0BOOL, 0}, /* O_AUTOINDENT 4BSD */ - {"autoindent", NULL, OPT_0BOOL, 0}, + {L("autoindent"), NULL, OPT_0BOOL, 0}, /* O_AUTOPRINT 4BSD */ - {"autoprint", NULL, OPT_1BOOL, 0}, + {L("autoprint"), NULL, OPT_1BOOL, 0}, /* O_AUTOWRITE 4BSD */ - {"autowrite", NULL, OPT_0BOOL, 0}, + {L("autowrite"), NULL, OPT_0BOOL, 0}, /* O_BACKUP 4.4BSD */ - {"backup", NULL, OPT_STR, 0}, + {L("backup"), NULL, OPT_STR, 0}, /* O_BEAUTIFY 4BSD */ - {"beautify", NULL, OPT_0BOOL, 0}, + {L("beautify"), NULL, OPT_0BOOL, 0}, /* O_CDPATH 4.4BSD */ - {"cdpath", NULL, OPT_STR, 0}, + {L("cdpath"), NULL, OPT_STR, 0}, /* O_CEDIT 4.4BSD */ - {"cedit", NULL, OPT_STR, 0}, + {L("cedit"), NULL, OPT_STR, 0}, /* O_COLUMNS 4.4BSD */ - {"columns", f_columns, OPT_NUM, OPT_NOSAVE}, + {L("columns"), f_columns, OPT_NUM, OPT_NOSAVE}, +/* O_COMBINED */ + {L("combined"), NULL, OPT_0BOOL, OPT_NOSET|OPT_WC}, /* O_COMMENT 4.4BSD */ - {"comment", NULL, OPT_0BOOL, 0}, -/* O_TMP_DIRECTORY 4BSD */ - {"directory", NULL, OPT_STR, 0}, + {L("comment"), NULL, OPT_0BOOL, 0}, +/* O_TMPDIR 4BSD */ + {L("directory"), NULL, OPT_STR, 0}, /* O_EDCOMPATIBLE 4BSD */ - {"edcompatible",NULL, OPT_0BOOL, 0}, -/* O_ESCAPETIME 4.4BSD */ - {"escapetime", NULL, OPT_NUM, 0}, + {L("edcompatible"),NULL, OPT_0BOOL, 0}, /* O_ERRORBELLS 4BSD */ - {"errorbells", NULL, OPT_0BOOL, 0}, + {L("errorbells"), NULL, OPT_0BOOL, 0}, +/* O_ESCAPETIME 4.4BSD */ + {L("escapetime"), NULL, OPT_NUM, 0}, /* O_EXRC System V (undocumented) */ - {"exrc", NULL, OPT_0BOOL, 0}, + {L("exrc"), NULL, OPT_0BOOL, 0}, /* O_EXTENDED 4.4BSD */ - {"extended", f_recompile, OPT_0BOOL, 0}, + {L("extended"), f_recompile, OPT_0BOOL, 0}, /* O_FILEC 4.4BSD */ - {"filec", NULL, OPT_STR, 0}, + {L("filec"), NULL, OPT_STR, 0}, +/* O_FILEENCODING */ + {L("fileencoding"),f_encoding, OPT_STR, OPT_WC}, /* O_FLASH HPUX */ - {"flash", NULL, OPT_1BOOL, 0}, -#ifdef GTAGS -/* O_GTAGSMODE FreeBSD2.2 */ - {"gtagsmode", NULL, OPT_0BOOL, 0}, -#endif + {L("flash"), NULL, OPT_1BOOL, 0}, /* O_HARDTABS 4BSD */ - {"hardtabs", NULL, OPT_NUM, 0}, + {L("hardtabs"), NULL, OPT_NUM, 0}, /* O_ICLOWER 4.4BSD */ - {"iclower", f_recompile, OPT_0BOOL, 0}, + {L("iclower"), f_recompile, OPT_0BOOL, 0}, /* O_IGNORECASE 4BSD */ - {"ignorecase", f_recompile, OPT_0BOOL, 0}, + {L("ignorecase"), f_recompile, OPT_0BOOL, 0}, +/* O_INPUTENCODING */ + {L("inputencoding"),f_encoding, OPT_STR, OPT_WC}, /* O_KEYTIME 4.4BSD */ - {"keytime", NULL, OPT_NUM, 0}, + {L("keytime"), NULL, OPT_NUM, 0}, /* O_LEFTRIGHT 4.4BSD */ - {"leftright", f_reformat, OPT_0BOOL, 0}, + {L("leftright"), f_reformat, OPT_0BOOL, 0}, /* O_LINES 4.4BSD */ - {"lines", f_lines, OPT_NUM, OPT_NOSAVE}, + {L("lines"), f_lines, OPT_NUM, OPT_NOSAVE}, /* O_LISP 4BSD * XXX * When the lisp option is implemented, delete the OPT_NOSAVE flag, * so that :mkexrc dumps it. */ - {"lisp", f_lisp, OPT_0BOOL, OPT_NOSAVE}, + {L("lisp"), f_lisp, OPT_0BOOL, OPT_NOSAVE}, /* O_LIST 4BSD */ - {"list", f_reformat, OPT_0BOOL, 0}, + {L("list"), f_reformat, OPT_0BOOL, 0}, /* O_LOCKFILES 4.4BSD * XXX * Locking isn't reliable enough over NFS to require it, in addition, * it's a serious startup performance problem over some remote links. */ - {"lock", NULL, OPT_1BOOL, 0}, + {L("lock"), NULL, OPT_1BOOL, 0}, /* O_MAGIC 4BSD */ - {"magic", NULL, OPT_1BOOL, 0}, + {L("magic"), NULL, OPT_1BOOL, 0}, +/* O_MATCHCHARS NetBSD 2.0 */ + {L("matchchars"), NULL, OPT_STR, OPT_PAIRS}, /* O_MATCHTIME 4.4BSD */ - {"matchtime", NULL, OPT_NUM, 0}, + {L("matchtime"), NULL, OPT_NUM, 0}, /* O_MESG 4BSD */ - {"mesg", NULL, OPT_1BOOL, 0}, + {L("mesg"), NULL, OPT_1BOOL, 0}, /* O_MODELINE 4BSD * !!! * This has been documented in historical systems as both "modeline" @@ -124,61 +133,61 @@ OPTLIST const optlist[] = { * example of what your intro CS professor referred to as the perils of * mixing code and data. Don't add it, or I will kill you. */ - {"modeline", NULL, OPT_0BOOL, OPT_NOSET}, + {L("modeline"), NULL, OPT_0BOOL, OPT_NOSET}, /* O_MSGCAT 4.4BSD */ - {"msgcat", f_msgcat, OPT_STR, 0}, + {L("msgcat"), f_msgcat, OPT_STR, 0}, /* O_NOPRINT 4.4BSD */ - {"noprint", f_print, OPT_STR, 0}, + {L("noprint"), f_print, OPT_STR, 0}, /* O_NUMBER 4BSD */ - {"number", f_reformat, OPT_0BOOL, 0}, + {L("number"), f_reformat, OPT_0BOOL, 0}, /* O_OCTAL 4.4BSD */ - {"octal", f_print, OPT_0BOOL, 0}, + {L("octal"), f_print, OPT_0BOOL, 0}, /* O_OPEN 4BSD */ - {"open", NULL, OPT_1BOOL, 0}, + {L("open"), NULL, OPT_1BOOL, 0}, /* O_OPTIMIZE 4BSD */ - {"optimize", NULL, OPT_1BOOL, 0}, + {L("optimize"), NULL, OPT_1BOOL, 0}, /* O_PARAGRAPHS 4BSD */ - {"paragraphs", f_paragraph, OPT_STR, 0}, + {L("paragraphs"), NULL, OPT_STR, OPT_PAIRS}, /* O_PATH 4.4BSD */ - {"path", NULL, OPT_STR, 0}, + {L("path"), NULL, OPT_STR, 0}, /* O_PRINT 4.4BSD */ - {"print", f_print, OPT_STR, 0}, + {L("print"), f_print, OPT_STR, 0}, /* O_PROMPT 4BSD */ - {"prompt", NULL, OPT_1BOOL, 0}, + {L("prompt"), NULL, OPT_1BOOL, 0}, /* O_READONLY 4BSD (undocumented) */ - {"readonly", f_readonly, OPT_0BOOL, OPT_ALWAYS}, + {L("readonly"), f_readonly, OPT_0BOOL, OPT_ALWAYS}, /* O_RECDIR 4.4BSD */ - {"recdir", NULL, OPT_STR, 0}, + {L("recdir"), NULL, OPT_STR, 0}, /* O_REDRAW 4BSD */ - {"redraw", NULL, OPT_0BOOL, 0}, + {L("redraw"), NULL, OPT_0BOOL, 0}, /* O_REMAP 4BSD */ - {"remap", NULL, OPT_1BOOL, 0}, + {L("remap"), NULL, OPT_1BOOL, 0}, /* O_REPORT 4BSD */ - {"report", NULL, OPT_NUM, 0}, + {L("report"), NULL, OPT_NUM, 0}, /* O_RULER 4.4BSD */ - {"ruler", NULL, OPT_0BOOL, 0}, + {L("ruler"), NULL, OPT_0BOOL, 0}, /* O_SCROLL 4BSD */ - {"scroll", NULL, OPT_NUM, 0}, + {L("scroll"), NULL, OPT_NUM, 0}, /* O_SEARCHINCR 4.4BSD */ - {"searchincr", NULL, OPT_0BOOL, 0}, + {L("searchincr"), NULL, OPT_0BOOL, 0}, /* O_SECTIONS 4BSD */ - {"sections", f_section, OPT_STR, 0}, + {L("sections"), NULL, OPT_STR, OPT_PAIRS}, /* O_SECURE 4.4BSD */ - {"secure", NULL, OPT_0BOOL, OPT_NOUNSET}, + {L("secure"), NULL, OPT_0BOOL, OPT_NOUNSET}, /* O_SHELL 4BSD */ - {"shell", NULL, OPT_STR, 0}, + {L("shell"), NULL, OPT_STR, 0}, /* O_SHELLMETA 4.4BSD */ - {"shellmeta", NULL, OPT_STR, 0}, + {L("shellmeta"), NULL, OPT_STR, 0}, /* O_SHIFTWIDTH 4BSD */ - {"shiftwidth", NULL, OPT_NUM, OPT_NOZERO}, + {L("shiftwidth"), NULL, OPT_NUM, OPT_NOZERO}, /* O_SHOWMATCH 4BSD */ - {"showmatch", NULL, OPT_0BOOL, 0}, + {L("showmatch"), NULL, OPT_0BOOL, 0}, /* O_SHOWMODE 4.4BSD */ - {"showmode", NULL, OPT_0BOOL, 0}, + {L("showmode"), NULL, OPT_0BOOL, 0}, /* O_SIDESCROLL 4.4BSD */ - {"sidescroll", NULL, OPT_NUM, OPT_NOZERO}, + {L("sidescroll"), NULL, OPT_NUM, OPT_NOZERO}, /* O_SLOWOPEN 4BSD */ - {"slowopen", NULL, OPT_0BOOL, 0}, + {L("slowopen"), NULL, OPT_0BOOL, 0}, /* O_SOURCEANY 4BSD (undocumented) * !!! * Historic vi, on startup, source'd $HOME/.exrc and ./.exrc, if they @@ -187,98 +196,97 @@ OPTLIST const optlist[] = { * .exrc files the user didn't own. This is an obvious security problem, * and we ignore the option. */ - {"sourceany", NULL, OPT_0BOOL, OPT_NOSET}, + {L("sourceany"), NULL, OPT_0BOOL, OPT_NOSET}, /* O_TABSTOP 4BSD */ - {"tabstop", f_reformat, OPT_NUM, OPT_NOZERO}, + {L("tabstop"), f_reformat, OPT_NUM, OPT_NOZERO}, /* O_TAGLENGTH 4BSD */ - {"taglength", NULL, OPT_NUM, 0}, + {L("taglength"), NULL, OPT_NUM, 0}, /* O_TAGS 4BSD */ - {"tags", NULL, OPT_STR, 0}, + {L("tags"), NULL, OPT_STR, 0}, /* O_TERM 4BSD * !!! * By default, the historic vi always displayed information about two * options, redraw and term. Term seems sufficient. */ - {"term", NULL, OPT_STR, OPT_ADISP|OPT_NOSAVE}, + {L("term"), NULL, OPT_STR, OPT_ADISP|OPT_NOSAVE}, /* O_TERSE 4BSD */ - {"terse", NULL, OPT_0BOOL, 0}, + {L("terse"), NULL, OPT_0BOOL, 0}, /* O_TILDEOP 4.4BSD */ - {"tildeop", NULL, OPT_0BOOL, 0}, + {L("tildeop"), NULL, OPT_0BOOL, 0}, /* O_TIMEOUT 4BSD (undocumented) */ - {"timeout", NULL, OPT_1BOOL, 0}, + {L("timeout"), NULL, OPT_1BOOL, 0}, /* O_TTYWERASE 4.4BSD */ - {"ttywerase", f_ttywerase, OPT_0BOOL, 0}, + {L("ttywerase"), f_ttywerase, OPT_0BOOL, 0}, /* O_VERBOSE 4.4BSD */ - {"verbose", NULL, OPT_0BOOL, 0}, + {L("verbose"), NULL, OPT_0BOOL, 0}, /* O_W1200 4BSD */ - {"w1200", f_w1200, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, + {L("w1200"), f_w1200, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, /* O_W300 4BSD */ - {"w300", f_w300, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, + {L("w300"), f_w300, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, /* O_W9600 4BSD */ - {"w9600", f_w9600, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, + {L("w9600"), f_w9600, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, /* O_WARN 4BSD */ - {"warn", NULL, OPT_1BOOL, 0}, + {L("warn"), NULL, OPT_1BOOL, 0}, /* O_WINDOW 4BSD */ - {"window", f_window, OPT_NUM, 0}, + {L("window"), f_window, OPT_NUM, 0}, /* O_WINDOWNAME 4BSD */ - {"windowname", NULL, OPT_0BOOL, 0}, + {L("windowname"), NULL, OPT_0BOOL, 0}, /* O_WRAPLEN 4.4BSD */ - {"wraplen", NULL, OPT_NUM, 0}, + {L("wraplen"), NULL, OPT_NUM, 0}, /* O_WRAPMARGIN 4BSD */ - {"wrapmargin", NULL, OPT_NUM, 0}, + {L("wrapmargin"), NULL, OPT_NUM, 0}, /* O_WRAPSCAN 4BSD */ - {"wrapscan", NULL, OPT_1BOOL, 0}, + {L("wrapscan"), NULL, OPT_1BOOL, 0}, /* O_WRITEANY 4BSD */ - {"writeany", NULL, OPT_0BOOL, 0}, + {L("writeany"), NULL, OPT_0BOOL, 0}, {NULL}, }; typedef struct abbrev { - char *name; + CHAR_T *name; int offset; } OABBREV; static OABBREV const abbrev[] = { - {"ai", O_AUTOINDENT}, /* 4BSD */ - {"ap", O_AUTOPRINT}, /* 4BSD */ - {"aw", O_AUTOWRITE}, /* 4BSD */ - {"bf", O_BEAUTIFY}, /* 4BSD */ - {"co", O_COLUMNS}, /* 4.4BSD */ - {"dir", O_TMP_DIRECTORY}, /* 4BSD */ - {"eb", O_ERRORBELLS}, /* 4BSD */ - {"ed", O_EDCOMPATIBLE}, /* 4BSD */ - {"ex", O_EXRC}, /* System V (undocumented) */ -#ifdef GTAGS - {"gt", O_GTAGSMODE}, /* FreeBSD2.2 */ -#endif - {"ht", O_HARDTABS}, /* 4BSD */ - {"ic", O_IGNORECASE}, /* 4BSD */ - {"li", O_LINES}, /* 4.4BSD */ - {"modelines", O_MODELINE}, /* HPUX */ - {"nu", O_NUMBER}, /* 4BSD */ - {"opt", O_OPTIMIZE}, /* 4BSD */ - {"para", O_PARAGRAPHS}, /* 4BSD */ - {"re", O_REDRAW}, /* O'Reilly */ - {"ro", O_READONLY}, /* 4BSD (undocumented) */ - {"scr", O_SCROLL}, /* 4BSD (undocumented) */ - {"sect", O_SECTIONS}, /* O'Reilly */ - {"sh", O_SHELL}, /* 4BSD */ - {"slow", O_SLOWOPEN}, /* 4BSD */ - {"sm", O_SHOWMATCH}, /* 4BSD */ - {"smd", O_SHOWMODE}, /* 4BSD */ - {"sw", O_SHIFTWIDTH}, /* 4BSD */ - {"tag", O_TAGS}, /* 4BSD (undocumented) */ - {"tl", O_TAGLENGTH}, /* 4BSD */ - {"to", O_TIMEOUT}, /* 4BSD (undocumented) */ - {"ts", O_TABSTOP}, /* 4BSD */ - {"tty", O_TERM}, /* 4BSD (undocumented) */ - {"ttytype", O_TERM}, /* 4BSD (undocumented) */ - {"w", O_WINDOW}, /* O'Reilly */ - {"wa", O_WRITEANY}, /* 4BSD */ - {"wi", O_WINDOW}, /* 4BSD (undocumented) */ - {"wl", O_WRAPLEN}, /* 4.4BSD */ - {"wm", O_WRAPMARGIN}, /* 4BSD */ - {"ws", O_WRAPSCAN}, /* 4BSD */ + {L("ai"), O_AUTOINDENT}, /* 4BSD */ + {L("ap"), O_AUTOPRINT}, /* 4BSD */ + {L("aw"), O_AUTOWRITE}, /* 4BSD */ + {L("bf"), O_BEAUTIFY}, /* 4BSD */ + {L("co"), O_COLUMNS}, /* 4.4BSD */ + {L("dir"), O_TMPDIR}, /* 4BSD */ + {L("eb"), O_ERRORBELLS}, /* 4BSD */ + {L("ed"), O_EDCOMPATIBLE}, /* 4BSD */ + {L("ex"), O_EXRC}, /* System V (undocumented) */ + {L("fe"), O_FILEENCODING}, + {L("ht"), O_HARDTABS}, /* 4BSD */ + {L("ic"), O_IGNORECASE}, /* 4BSD */ + {L("ie"), O_INPUTENCODING}, + {L("li"), O_LINES}, /* 4.4BSD */ + {L("modelines"), O_MODELINE}, /* HPUX */ + {L("nu"), O_NUMBER}, /* 4BSD */ + {L("opt"), O_OPTIMIZE}, /* 4BSD */ + {L("para"), O_PARAGRAPHS}, /* 4BSD */ + {L("re"), O_REDRAW}, /* O'Reilly */ + {L("ro"), O_READONLY}, /* 4BSD (undocumented) */ + {L("scr"), O_SCROLL}, /* 4BSD (undocumented) */ + {L("sect"), O_SECTIONS}, /* O'Reilly */ + {L("sh"), O_SHELL}, /* 4BSD */ + {L("slow"), O_SLOWOPEN}, /* 4BSD */ + {L("sm"), O_SHOWMATCH}, /* 4BSD */ + {L("smd"), O_SHOWMODE}, /* 4BSD */ + {L("sw"), O_SHIFTWIDTH}, /* 4BSD */ + {L("tag"), O_TAGS}, /* 4BSD (undocumented) */ + {L("tl"), O_TAGLENGTH}, /* 4BSD */ + {L("to"), O_TIMEOUT}, /* 4BSD (undocumented) */ + {L("ts"), O_TABSTOP}, /* 4BSD */ + {L("tty"), O_TERM}, /* 4BSD (undocumented) */ + {L("ttytype"), O_TERM}, /* 4BSD (undocumented) */ + {L("w"), O_WINDOW}, /* O'Reilly */ + {L("wa"), O_WRITEANY}, /* 4BSD */ + {L("wi"), O_WINDOW}, /* 4BSD (undocumented) */ + {L("wl"), O_WRAPLEN}, /* 4.4BSD */ + {L("wm"), O_WRAPMARGIN}, /* 4BSD */ + {L("ws"), O_WRAPSCAN}, /* 4BSD */ {NULL}, }; @@ -289,17 +297,18 @@ static OABBREV const abbrev[] = { * PUBLIC: int opts_init __P((SCR *, int *)); */ int -opts_init(sp, oargs) - SCR *sp; - int *oargs; +opts_init( + SCR *sp, + int *oargs) { ARGS *argv[2], a, b; OPTLIST const *op; u_long v; - int cnt, optindx; - char *s, b1[1024]; + int cnt, optindx = 0; + char *s; + CHAR_T b2[1024]; - a.bp = b1; + a.bp = b2; b.bp = NULL; a.len = b.len = 0; argv[0] = &a; @@ -307,9 +316,9 @@ opts_init(sp, oargs) /* Set numeric and string default values. */ #define OI(indx, str) { \ - if (str != b1) /* GCC puts strings in text-space. */ \ - (void)strcpy(b1, str); \ - a.len = strlen(b1); \ + a.len = STRLEN(str); \ + if ((CHAR_T*)str != b2) /* GCC puts strings in text-space. */ \ + (void)MEMCPY(b2, str, a.len+1); \ if (opts_set(sp, argv, NULL)) { \ optindx = indx; \ goto err; \ @@ -334,9 +343,10 @@ opts_init(sp, oargs) F_SET(&sp->opts[O_SECURE], OPT_GLOBAL); /* Initialize string values. */ - (void)snprintf(b1, sizeof(b1), - "cdpath=%s", (s = getenv("CDPATH")) == NULL ? ":" : s); - OI(O_CDPATH, b1); + (void)SPRINTF(b2, SIZE(b2), + L("cdpath=%s"), (s = getenv("CDPATH")) == NULL ? ":" : s); + OI(O_CDPATH, b2); + OI(O_CEDIT, L("cedit=\033")); /* * !!! @@ -345,30 +355,32 @@ opts_init(sp, oargs) * are two ways to change this -- the user can set either the directory * option or the TMPDIR environmental variable. */ - (void)snprintf(b1, sizeof(b1), - "directory=%s", (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s); - OI(O_TMP_DIRECTORY, b1); - OI(O_ESCAPETIME, "escapetime=6"); - OI(O_KEYTIME, "keytime=6"); - OI(O_MATCHTIME, "matchtime=7"); - (void)snprintf(b1, sizeof(b1), "msgcat=%s", _PATH_MSGCAT); - OI(O_MSGCAT, b1); - OI(O_REPORT, "report=5"); - OI(O_PARAGRAPHS, "paragraphs=IPLPPPQPP LIpplpipbp"); - (void)snprintf(b1, sizeof(b1), "path=%s", ""); - OI(O_PATH, b1); - (void)snprintf(b1, sizeof(b1), "recdir=%s", _PATH_PRESERVE); - OI(O_RECDIR, b1); - OI(O_SECTIONS, "sections=NHSHH HUnhsh"); - (void)snprintf(b1, sizeof(b1), - "shell=%s", (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s); - OI(O_SHELL, b1); - OI(O_SHELLMETA, "shellmeta=~{[*?$`'\"\\"); - OI(O_SHIFTWIDTH, "shiftwidth=8"); - OI(O_SIDESCROLL, "sidescroll=16"); - OI(O_TABSTOP, "tabstop=8"); - (void)snprintf(b1, sizeof(b1), "tags=%s", _PATH_TAGS); - OI(O_TAGS, b1); + (void)SPRINTF(b2, SIZE(b2), + L("directory=%s"), (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s); + OI(O_TMPDIR, b2); + OI(O_ESCAPETIME, L("escapetime=6")); + OI(O_FILEC, L("filec=\t")); + OI(O_KEYTIME, L("keytime=6")); + OI(O_MATCHCHARS, L("matchchars=()[]{}")); + OI(O_MATCHTIME, L("matchtime=7")); + (void)SPRINTF(b2, SIZE(b2), L("msgcat=%s"), _PATH_MSGCAT); + OI(O_MSGCAT, b2); + OI(O_REPORT, L("report=5")); + OI(O_PARAGRAPHS, L("paragraphs=IPLPPPQPP LIpplpipbp")); + (void)SPRINTF(b2, SIZE(b2), L("path=%s"), ""); + OI(O_PATH, b2); + (void)SPRINTF(b2, SIZE(b2), L("recdir=%s"), _PATH_PRESERVE); + OI(O_RECDIR, b2); + OI(O_SECTIONS, L("sections=NHSHH HUnhsh")); + (void)SPRINTF(b2, SIZE(b2), + L("shell=%s"), (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s); + OI(O_SHELL, b2); + OI(O_SHELLMETA, L("shellmeta=~{[*?$`'\"\\")); + OI(O_SHIFTWIDTH, L("shiftwidth=8")); + OI(O_SIDESCROLL, L("sidescroll=16")); + OI(O_TABSTOP, L("tabstop=8")); + (void)SPRINTF(b2, SIZE(b2), L("tags=%s"), _PATH_TAGS); + OI(O_TAGS, b2); /* * XXX @@ -377,8 +389,8 @@ opts_init(sp, oargs) */ if ((v = (O_VAL(sp, O_LINES) - 1) / 2) == 0) v = 1; - (void)snprintf(b1, sizeof(b1), "scroll=%ld", v); - OI(O_SCROLL, b1); + (void)SPRINTF(b2, SIZE(b2), L("scroll=%ld"), v); + OI(O_SCROLL, b2); /* * The default window option values are: @@ -395,16 +407,19 @@ opts_init(sp, oargs) v = 8; else if (v <= 1200) v = 16; - else - v = O_VAL(sp, O_LINES) - 1; - (void)snprintf(b1, sizeof(b1), "window=%lu", v); - OI(O_WINDOW, b1); + else if ((v = O_VAL(sp, O_LINES) - 1) == 0) + v = 1; + + (void)SPRINTF(b2, SIZE(b2), L("window=%lu"), v); + OI(O_WINDOW, b2); /* * Set boolean default values, and copy all settings into the default * information. OS_NOFREE is set, we're copying, not replacing. */ - for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt) + for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt) { + if (F_ISSET(op, OPT_GLOBAL)) + continue; switch (op->type) { case OPT_0BOOL: break; @@ -423,6 +438,7 @@ opts_init(sp, oargs) default: abort(); } + } /* * !!! @@ -432,11 +448,11 @@ opts_init(sp, oargs) */ for (; *oargs != -1; ++oargs) OI(*oargs, optlist[*oargs].name); - return (0); #undef OI + return (0); -err: msgq(sp, M_ERR, - "031|Unable to set default %s option", optlist[optindx].name); +err: msgq_wstr(sp, M_ERR, optlist[optindx].name, + "031|Unable to set default %s option"); return (1); } @@ -447,18 +463,21 @@ err: msgq(sp, M_ERR, * PUBLIC: int opts_set __P((SCR *, ARGS *[], char *)); */ int -opts_set(sp, argv, usage) - SCR *sp; - ARGS *argv[]; - char *usage; +opts_set( + SCR *sp, + ARGS *argv[], + char *usage) { enum optdisp disp; enum nresult nret; OPTLIST const *op; OPTION *spo; - u_long value, turnoff; + u_long isset, turnoff, value; int ch, equals, nf, nf2, offset, qmark, rval; - char *endp, *name, *p, *sep, *t; + CHAR_T *endp, *name, *p, *sep; + char *p2, *t2; + char *np; + size_t nlen; disp = NO_DISPLAY; for (rval = 0; argv[0]->len != 0; ++argv) { @@ -466,7 +485,7 @@ opts_set(sp, argv, usage) * The historic vi dumped the options for each occurrence of * "all" in the set list. Puhleeze. */ - if (!strcmp(argv[0]->bp, "all")) { + if (!STRCMP(argv[0]->bp, L("all"))) { disp = ALL_DISPLAY; continue; } @@ -528,7 +547,7 @@ opts_set(sp, argv, usage) case OPT_1BOOL: /* Some options may not be reset. */ if (F_ISSET(op, OPT_NOUNSET) && turnoff) { - msgq_str(sp, M_ERR, name, + msgq_wstr(sp, M_ERR, name, "291|set: the %s option may not be turned off"); rval = 1; break; @@ -536,14 +555,14 @@ opts_set(sp, argv, usage) /* Some options may not be set. */ if (F_ISSET(op, OPT_NOSET) && !turnoff) { - msgq_str(sp, M_ERR, name, + msgq_wstr(sp, M_ERR, name, "313|set: the %s option may never be turned on"); rval = 1; break; } if (equals) { - msgq_str(sp, M_ERR, name, + msgq_wstr(sp, M_ERR, name, "034|set: [no]%s option doesn't take a value"); rval = 1; break; @@ -559,34 +578,34 @@ opts_set(sp, argv, usage) * Do nothing if the value is unchanged, the underlying * functions can be expensive. */ + isset = !turnoff; if (!F_ISSET(op, OPT_ALWAYS)) - if (turnoff) { - if (!O_ISSET(sp, offset)) - break; - } else { + if (isset) { if (O_ISSET(sp, offset)) break; - } + } else + if (!O_ISSET(sp, offset)) + break; /* Report to subsystems. */ - if (op->func != NULL && - op->func(sp, spo, NULL, &turnoff) || - ex_optchange(sp, offset, NULL, &turnoff) || - v_optchange(sp, offset, NULL, &turnoff) || - sp->gp->scr_optchange(sp, offset, NULL, &turnoff)) { + if ((op->func != NULL && + op->func(sp, spo, NULL, &isset)) || + ex_optchange(sp, offset, NULL, &isset) || + v_optchange(sp, offset, NULL, &isset) || + sp->gp->scr_optchange(sp, offset, NULL, &isset)) { rval = 1; break; } /* Set the value. */ - if (turnoff) - O_CLR(sp, offset); - else + if (isset) O_SET(sp, offset); + else + O_CLR(sp, offset); break; case OPT_NUM: if (turnoff) { - msgq_str(sp, M_ERR, name, + msgq_wstr(sp, M_ERR, name, "035|set: %s option isn't a boolean"); rval = 1; break; @@ -598,48 +617,56 @@ opts_set(sp, argv, usage) break; } - if (!isdigit(sep[0])) + if (!ISDIGIT(sep[0])) goto badnum; if ((nret = nget_uslong(&value, sep, &endp, 10)) != NUM_OK) { - p = msg_print(sp, name, &nf); - t = msg_print(sp, sep, &nf2); + INT2CHAR(sp, name, STRLEN(name) + 1, + np, nlen); + p2 = msg_print(sp, np, &nf); + INT2CHAR(sp, sep, STRLEN(sep) + 1, + np, nlen); + t2 = msg_print(sp, np, &nf2); switch (nret) { case NUM_ERR: msgq(sp, M_SYSERR, - "036|set: %s option: %s", p, t); + "036|set: %s option: %s", p2, t2); break; case NUM_OVER: msgq(sp, M_ERR, - "037|set: %s option: %s: value overflow", p, t); + "037|set: %s option: %s: value overflow", p2, t2); break; case NUM_OK: case NUM_UNDER: abort(); } if (nf) - FREE_SPACE(sp, p, 0); + FREE_SPACE(sp, p2, 0); if (nf2) - FREE_SPACE(sp, t, 0); + FREE_SPACE(sp, t2, 0); rval = 1; break; } - if (*endp && !isblank(*endp)) { -badnum: p = msg_print(sp, name, &nf); - t = msg_print(sp, sep, &nf2); + if (*endp && !cmdskip(*endp)) { +badnum: INT2CHAR(sp, name, STRLEN(name) + 1, + np, nlen); + p2 = msg_print(sp, np, &nf); + INT2CHAR(sp, sep, STRLEN(sep) + 1, + np, nlen); + t2 = msg_print(sp, np, &nf2); msgq(sp, M_ERR, - "038|set: %s option: %s is an illegal number", p, t); + "038|set: %s option: %s is an illegal number", p2, t2); if (nf) - FREE_SPACE(sp, p, 0); + FREE_SPACE(sp, p2, 0); if (nf2) - FREE_SPACE(sp, t, 0); + FREE_SPACE(sp, t2, 0); rval = 1; break; } /* Some options may never be set to zero. */ if (F_ISSET(op, OPT_NOZERO) && value == 0) { - msgq_str(sp, M_ERR, name, + msgq_wstr(sp, M_ERR, name, "314|set: the %s option may never be set to 0"); rval = 1; break; @@ -654,11 +681,12 @@ badnum: p = msg_print(sp, name, &nf); break; /* Report to subsystems. */ - if (op->func != NULL && - op->func(sp, spo, sep, &value) || - ex_optchange(sp, offset, sep, &value) || - v_optchange(sp, offset, sep, &value) || - sp->gp->scr_optchange(sp, offset, sep, &value)) { + INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen); + if ((op->func != NULL && + op->func(sp, spo, np, &value)) || + ex_optchange(sp, offset, np, &value) || + v_optchange(sp, offset, np, &value) || + sp->gp->scr_optchange(sp, offset, np, &value)) { rval = 1; break; } @@ -669,7 +697,7 @@ badnum: p = msg_print(sp, name, &nf); break; case OPT_STR: if (turnoff) { - msgq_str(sp, M_ERR, name, + msgq_wstr(sp, M_ERR, name, "039|set: %s option isn't a boolean"); rval = 1; break; @@ -681,27 +709,36 @@ badnum: p = msg_print(sp, name, &nf); break; } + /* Check for strings that must have even length. */ + if (F_ISSET(op, OPT_PAIRS) && STRLEN(sep) & 1) { + msgq_wstr(sp, M_ERR, name, + "047|The %s option must be in two character groups"); + rval = 1; + break; + } + /* * Do nothing if the value is unchanged, the underlying * functions can be expensive. */ + INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen); if (!F_ISSET(op, OPT_ALWAYS) && O_STR(sp, offset) != NULL && - !strcmp(O_STR(sp, offset), sep)) + !strcmp(O_STR(sp, offset), np)) break; /* Report to subsystems. */ - if (op->func != NULL && - op->func(sp, spo, sep, NULL) || - ex_optchange(sp, offset, sep, NULL) || - v_optchange(sp, offset, sep, NULL) || - sp->gp->scr_optchange(sp, offset, sep, NULL)) { + if ((op->func != NULL && + op->func(sp, spo, np, NULL)) || + ex_optchange(sp, offset, np, NULL) || + v_optchange(sp, offset, np, NULL) || + sp->gp->scr_optchange(sp, offset, np, NULL)) { rval = 1; break; } /* Set the value. */ - if (o_set(sp, offset, OS_STRDUP, sep, 0)) + if (o_set(sp, offset, OS_STRDUP, np, 0)) rval = 1; break; default: @@ -720,12 +757,12 @@ badnum: p = msg_print(sp, name, &nf); * PUBLIC: int o_set __P((SCR *, int, u_int, char *, u_long)); */ int -o_set(sp, opt, flags, str, val) - SCR *sp; - int opt; - u_int flags; - char *str; - u_long val; +o_set( + SCR *sp, + int opt, + u_int flags, + char *str, + u_long val) { OPTION *op; @@ -764,15 +801,16 @@ o_set(sp, opt, flags, str, val) * PUBLIC: int opts_empty __P((SCR *, int, int)); */ int -opts_empty(sp, off, silent) - SCR *sp; - int off, silent; +opts_empty( + SCR *sp, + int off, + int silent) { char *p; if ((p = O_STR(sp, off)) == NULL || p[0] == '\0') { if (!silent) - msgq_str(sp, M_ERR, optlist[off].name, + msgq_wstr(sp, M_ERR, optlist[off].name, "305|No %s edit option specified"); return (1); } @@ -786,9 +824,9 @@ opts_empty(sp, off, silent) * PUBLIC: void opts_dump __P((SCR *, enum optdisp)); */ void -opts_dump(sp, type) - SCR *sp; - enum optdisp type; +opts_dump( + SCR *sp, + enum optdisp type) { OPTLIST const *op; int base, b_num, cnt, col, colwidth, curlen, s_num; @@ -843,8 +881,8 @@ opts_dump(sp, type) break; case OPT_STR: if (O_STR(sp, cnt) == O_D_STR(sp, cnt) || - O_D_STR(sp, cnt) != NULL && - !strcmp(O_STR(sp, cnt), O_D_STR(sp, cnt))) + (O_D_STR(sp, cnt) != NULL && + !strcmp(O_STR(sp, cnt), O_D_STR(sp, cnt)))) continue; break; } @@ -859,7 +897,7 @@ opts_dump(sp, type) } F_CLR(&sp->opts[cnt], OPT_SELECTED); - curlen = strlen(op->name); + curlen = STRLEN(op->name); switch (op->type) { case OPT_0BOOL: case OPT_1BOOL: @@ -920,9 +958,9 @@ opts_dump(sp, type) * Print out an option. */ static int -opts_print(sp, op) - SCR *sp; - OPTLIST const *op; +opts_print( + SCR *sp, + OPTLIST const *op) { int curlen, offset; @@ -932,13 +970,13 @@ opts_print(sp, op) case OPT_0BOOL: case OPT_1BOOL: curlen += ex_printf(sp, - "%s%s", O_ISSET(sp, offset) ? "" : "no", op->name); + "%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name); break; case OPT_NUM: - curlen += ex_printf(sp, "%s=%ld", op->name, O_VAL(sp, offset)); + curlen += ex_printf(sp, WS"=%ld", op->name, O_VAL(sp, offset)); break; case OPT_STR: - curlen += ex_printf(sp, "%s=\"%s\"", op->name, + curlen += ex_printf(sp, WS"=\"%s\"", op->name, O_STR(sp, offset) == NULL ? "" : O_STR(sp, offset)); break; } @@ -952,13 +990,14 @@ opts_print(sp, op) * PUBLIC: int opts_save __P((SCR *, FILE *)); */ int -opts_save(sp, fp) - SCR *sp; - FILE *fp; +opts_save( + SCR *sp, + FILE *fp) { OPTLIST const *op; - int ch, cnt; - char *p; + CHAR_T ch, *p; + char nch, *np; + int cnt; for (op = optlist; op->name != NULL; ++op) { if (F_ISSET(op, OPT_NOSAVE)) @@ -968,28 +1007,28 @@ opts_save(sp, fp) case OPT_0BOOL: case OPT_1BOOL: if (O_ISSET(sp, cnt)) - (void)fprintf(fp, "set %s\n", op->name); + (void)fprintf(fp, "set "WS"\n", op->name); else - (void)fprintf(fp, "set no%s\n", op->name); + (void)fprintf(fp, "set no"WS"\n", op->name); break; case OPT_NUM: (void)fprintf(fp, - "set %s=%-3ld\n", op->name, O_VAL(sp, cnt)); + "set "WS"=%-3ld\n", op->name, O_VAL(sp, cnt)); break; case OPT_STR: if (O_STR(sp, cnt) == NULL) break; (void)fprintf(fp, "set "); for (p = op->name; (ch = *p) != '\0'; ++p) { - if (isblank(ch) || ch == '\\') + if (cmdskip(ch) || ch == '\\') (void)putc('\\', fp); - (void)putc(ch, fp); + fprintf(fp, WC, ch); } (void)putc('=', fp); - for (p = O_STR(sp, cnt); (ch = *p) != '\0'; ++p) { - if (isblank(ch) || ch == '\\') + for (np = O_STR(sp, cnt); (nch = *np) != '\0'; ++np) { + if (cmdskip(nch) || nch == '\\') (void)putc('\\', fp); - (void)putc(ch, fp); + (void)putc(nch, fp); } (void)putc('\n', fp); break; @@ -1006,11 +1045,10 @@ opts_save(sp, fp) * opts_search -- * Search for an option. * - * PUBLIC: OPTLIST const *opts_search __P((char *)); + * PUBLIC: OPTLIST const *opts_search __P((CHAR_T *)); */ OPTLIST const * -opts_search(name) - char *name; +opts_search(CHAR_T *name) { OPTLIST const *op, *found; OABBREV atmp, *ap; @@ -1033,13 +1071,13 @@ opts_search(name) * Check to see if the name is the prefix of one (and only one) * option. If so, return the option. */ - len = strlen(name); + len = STRLEN(name); for (found = NULL, op = optlist; op->name != NULL; ++op) { if (op->name[0] < name[0]) continue; if (op->name[0] > name[0]) break; - if (!memcmp(op->name, name, len)) { + if (!MEMCMP(op->name, name, len)) { if (found != NULL) return (NULL); found = op; @@ -1052,29 +1090,31 @@ opts_search(name) * opts_nomatch -- * Standard nomatch error message for options. * - * PUBLIC: void opts_nomatch __P((SCR *, char *)); + * PUBLIC: void opts_nomatch __P((SCR *, CHAR_T *)); */ void -opts_nomatch(sp, name) - SCR *sp; - char *name; +opts_nomatch( + SCR *sp, + CHAR_T *name) { - msgq_str(sp, M_ERR, name, + msgq_wstr(sp, M_ERR, name, "033|set: no %s option: 'set all' gives all option values"); } static int -opts_abbcmp(a, b) - const void *a, *b; +opts_abbcmp( + const void *a, + const void *b) { - return(strcmp(((OABBREV *)a)->name, ((OABBREV *)b)->name)); + return(STRCMP(((OABBREV *)a)->name, ((OABBREV *)b)->name)); } static int -opts_cmp(a, b) - const void *a, *b; +opts_cmp( + const void *a, + const void *b) { - return(strcmp(((OPTLIST *)a)->name, ((OPTLIST *)b)->name)); + return(STRCMP(((OPTLIST *)a)->name, ((OPTLIST *)b)->name)); } /* @@ -1084,8 +1124,9 @@ opts_cmp(a, b) * PUBLIC: int opts_copy __P((SCR *, SCR *)); */ int -opts_copy(orig, sp) - SCR *orig, *sp; +opts_copy( + SCR *orig, + SCR *sp) { int cnt, rval; @@ -1095,7 +1136,7 @@ opts_copy(orig, sp) /* Copy the string edit options. */ for (cnt = rval = 0; cnt < O_OPTIONCOUNT; ++cnt) { if (optlist[cnt].type != OPT_STR || - F_ISSET(&optlist[cnt], OPT_GLOBAL)) + F_ISSET(&sp->opts[cnt], OPT_GLOBAL)) continue; /* * If never set, or already failed, NULL out the entries -- @@ -1131,14 +1172,13 @@ nomem: msgq(orig, M_SYSERR, NULL); * PUBLIC: void opts_free __P((SCR *)); */ void -opts_free(sp) - SCR *sp; +opts_free(SCR *sp) { int cnt; for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt) { if (optlist[cnt].type != OPT_STR || - F_ISSET(&optlist[cnt], OPT_GLOBAL)) + F_ISSET(&sp->opts[cnt], OPT_GLOBAL)) continue; if (O_STR(sp, cnt) != NULL) free(O_STR(sp, cnt)); diff --git a/contrib/nvi/common/options.h b/contrib/nvi/common/options.h index 2646dc3..fe1f80f 100644 --- a/contrib/nvi/common/options.h +++ b/contrib/nvi/common/options.h @@ -6,7 +6,7 @@ * * See the LICENSE file for redistribution information. * - * @(#)options.h 10.19 (Berkeley) 10/10/96 + * $Id: options.h,v 10.21 2012/02/10 20:24:58 zy Exp $ */ /* @@ -76,7 +76,7 @@ struct _option { /* List of option names, associated update functions and information. */ struct _optlist { - char *name; /* Name. */ + CHAR_T *name; /* Name. */ /* Change function. */ int (*func) __P((SCR *, OPTION *, char *, u_long *)); /* Type of object. */ @@ -89,6 +89,7 @@ struct _optlist { #define OPT_NOSET 0x010 /* Option may not be set. */ #define OPT_NOUNSET 0x020 /* Option may not be unset. */ #define OPT_NOZERO 0x040 /* Option may not be set to 0. */ +#define OPT_PAIRS 0x080 /* String with even length. */ u_int8_t flags; }; diff --git a/contrib/nvi/common/options_def.h b/contrib/nvi/common/options_def.h new file mode 100644 index 0000000..8e23278 --- /dev/null +++ b/contrib/nvi/common/options_def.h @@ -0,0 +1,83 @@ +#define O_ALTWERASE 0 +#define O_AUTOINDENT 1 +#define O_AUTOPRINT 2 +#define O_AUTOWRITE 3 +#define O_BACKUP 4 +#define O_BEAUTIFY 5 +#define O_CDPATH 6 +#define O_CEDIT 7 +#define O_COLUMNS 8 +#define O_COMBINED 9 +#define O_COMMENT 10 +#define O_TMPDIR 11 +#define O_EDCOMPATIBLE 12 +#define O_ERRORBELLS 13 +#define O_ESCAPETIME 14 +#define O_EXRC 15 +#define O_EXTENDED 16 +#define O_FILEC 17 +#define O_FILEENCODING 18 +#define O_FLASH 19 +#define O_HARDTABS 20 +#define O_ICLOWER 21 +#define O_IGNORECASE 22 +#define O_INPUTENCODING 23 +#define O_KEYTIME 24 +#define O_LEFTRIGHT 25 +#define O_LINES 26 +#define O_LISP 27 +#define O_LIST 28 +#define O_LOCKFILES 29 +#define O_MAGIC 30 +#define O_MATCHCHARS 31 +#define O_MATCHTIME 32 +#define O_MESG 33 +#define O_MODELINE 34 +#define O_MSGCAT 35 +#define O_NOPRINT 36 +#define O_NUMBER 37 +#define O_OCTAL 38 +#define O_OPEN 39 +#define O_OPTIMIZE 40 +#define O_PARAGRAPHS 41 +#define O_PATH 42 +#define O_PRINT 43 +#define O_PROMPT 44 +#define O_READONLY 45 +#define O_RECDIR 46 +#define O_REDRAW 47 +#define O_REMAP 48 +#define O_REPORT 49 +#define O_RULER 50 +#define O_SCROLL 51 +#define O_SEARCHINCR 52 +#define O_SECTIONS 53 +#define O_SECURE 54 +#define O_SHELL 55 +#define O_SHELLMETA 56 +#define O_SHIFTWIDTH 57 +#define O_SHOWMATCH 58 +#define O_SHOWMODE 59 +#define O_SIDESCROLL 60 +#define O_SLOWOPEN 61 +#define O_SOURCEANY 62 +#define O_TABSTOP 63 +#define O_TAGLENGTH 64 +#define O_TAGS 65 +#define O_TERM 66 +#define O_TERSE 67 +#define O_TILDEOP 68 +#define O_TIMEOUT 69 +#define O_TTYWERASE 70 +#define O_VERBOSE 71 +#define O_W1200 72 +#define O_W300 73 +#define O_W9600 74 +#define O_WARN 75 +#define O_WINDOW 76 +#define O_WINDOWNAME 77 +#define O_WRAPLEN 78 +#define O_WRAPMARGIN 79 +#define O_WRAPSCAN 80 +#define O_WRITEANY 81 +#define O_OPTIONCOUNT 82 diff --git a/contrib/nvi/common/options_f.c b/contrib/nvi/common/options_f.c index ea3c611..482a37e 100644 --- a/contrib/nvi/common/options_f.c +++ b/contrib/nvi/common/options_f.c @@ -10,7 +10,7 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)options_f.c 10.25 (Berkeley) 7/12/96"; +static const char sccsid[] = "$Id: options_f.c,v 10.34 04/07/11 16:06:29 zy Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -32,13 +32,13 @@ static const char sccsid[] = "@(#)options_f.c 10.25 (Berkeley) 7/12/96"; * PUBLIC: int f_altwerase __P((SCR *, OPTION *, char *, u_long *)); */ int -f_altwerase(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_altwerase( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { - if (!*valp) + if (*valp) O_CLR(sp, O_TTYWERASE); return (0); } @@ -47,11 +47,11 @@ f_altwerase(sp, op, str, valp) * PUBLIC: int f_columns __P((SCR *, OPTION *, char *, u_long *)); */ int -f_columns(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_columns( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { /* Validate the number. */ if (*valp < MINIMUM_SCREEN_COLS) { @@ -81,11 +81,11 @@ f_columns(sp, op, str, valp) * PUBLIC: int f_lines __P((SCR *, OPTION *, char *, u_long *)); */ int -f_lines(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_lines( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { /* Validate the number. */ if (*valp < MINIMUM_SCREEN_ROWS) { @@ -138,11 +138,11 @@ f_lines(sp, op, str, valp) * PUBLIC: int f_lisp __P((SCR *, OPTION *, char *, u_long *)); */ int -f_lisp(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_lisp( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { msgq(sp, M_ERR, "044|The lisp option is not implemented"); return (0); @@ -152,44 +152,37 @@ f_lisp(sp, op, str, valp) * PUBLIC: int f_msgcat __P((SCR *, OPTION *, char *, u_long *)); */ int -f_msgcat(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_msgcat( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { (void)msg_open(sp, str); return (0); } /* - * PUBLIC: int f_paragraph __P((SCR *, OPTION *, char *, u_long *)); - */ -int -f_paragraph(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; -{ - if (strlen(str) & 1) { - msgq(sp, M_ERR, - "048|The paragraph option must be in two character groups"); - return (1); - } - return (0); -} - -/* * PUBLIC: int f_print __P((SCR *, OPTION *, char *, u_long *)); */ int -f_print(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_print( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { + int offset = op - sp->opts; + + /* Preset the value, needed for reinitialization of lookup table. */ + if (offset == O_OCTAL) { + if (*valp) + O_SET(sp, offset); + else + O_CLR(sp, offset); + } else if (o_set(sp, offset, OS_STRDUP, str, 0)) + return(1); + /* Reinitialize the key fast lookup table. */ v_key_ilookup(sp); @@ -202,20 +195,20 @@ f_print(sp, op, str, valp) * PUBLIC: int f_readonly __P((SCR *, OPTION *, char *, u_long *)); */ int -f_readonly(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_readonly( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { /* * !!! * See the comment in exf.c. */ if (*valp) - F_CLR(sp, SC_READONLY); - else F_SET(sp, SC_READONLY); + else + F_CLR(sp, SC_READONLY); return (0); } @@ -223,11 +216,11 @@ f_readonly(sp, op, str, valp) * PUBLIC: int f_recompile __P((SCR *, OPTION *, char *, u_long *)); */ int -f_recompile(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_recompile( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { if (F_ISSET(sp, SC_RE_SEARCH)) { regfree(&sp->re_c); @@ -244,45 +237,27 @@ f_recompile(sp, op, str, valp) * PUBLIC: int f_reformat __P((SCR *, OPTION *, char *, u_long *)); */ int -f_reformat(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_reformat( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { F_SET(sp, SC_SCR_REFORMAT); return (0); } /* - * PUBLIC: int f_section __P((SCR *, OPTION *, char *, u_long *)); - */ -int -f_section(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; -{ - if (strlen(str) & 1) { - msgq(sp, M_ERR, - "049|The section option must be in two character groups"); - return (1); - } - return (0); -} - -/* * PUBLIC: int f_ttywerase __P((SCR *, OPTION *, char *, u_long *)); */ int -f_ttywerase(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_ttywerase( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { - if (!*valp) + if (*valp) O_CLR(sp, O_ALTWERASE); return (0); } @@ -291,11 +266,11 @@ f_ttywerase(sp, op, str, valp) * PUBLIC: int f_w300 __P((SCR *, OPTION *, char *, u_long *)); */ int -f_w300(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_w300( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { u_long v; @@ -312,11 +287,11 @@ f_w300(sp, op, str, valp) * PUBLIC: int f_w1200 __P((SCR *, OPTION *, char *, u_long *)); */ int -f_w1200(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_w1200( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { u_long v; @@ -333,11 +308,11 @@ f_w1200(sp, op, str, valp) * PUBLIC: int f_w9600 __P((SCR *, OPTION *, char *, u_long *)); */ int -f_w9600(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_w9600( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { u_long v; @@ -354,14 +329,29 @@ f_w9600(sp, op, str, valp) * PUBLIC: int f_window __P((SCR *, OPTION *, char *, u_long *)); */ int -f_window(sp, op, str, valp) - SCR *sp; - OPTION *op; - char *str; - u_long *valp; +f_window( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) { if (*valp >= O_VAL(sp, O_LINES) - 1 && (*valp = O_VAL(sp, O_LINES) - 1) == 0) *valp = 1; return (0); } + +/* + * PUBLIC: int f_encoding __P((SCR *, OPTION *, char *, u_long *)); + */ +int +f_encoding( + SCR *sp, + OPTION *op, + char *str, + u_long *valp) +{ + int offset = op - sp->opts; + + return conv_enc(sp, offset, str); +} diff --git a/contrib/nvi/common/put.c b/contrib/nvi/common/put.c index 8c0ca4b..6e9dc09 100644 --- a/contrib/nvi/common/put.c +++ b/contrib/nvi/common/put.c @@ -10,11 +10,12 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)put.c 10.11 (Berkeley) 9/23/96"; +static const char sccsid[] = "$Id: put.c,v 10.19 04/07/11 17:00:24 zy Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> +#include <sys/time.h> #include <bitstring.h> #include <ctype.h> @@ -32,19 +33,21 @@ static const char sccsid[] = "@(#)put.c 10.11 (Berkeley) 9/23/96"; * PUBLIC: int put __P((SCR *, CB *, CHAR_T *, MARK *, MARK *, int)); */ int -put(sp, cbp, namep, cp, rp, append) - SCR *sp; - CB *cbp; - CHAR_T *namep; - MARK *cp, *rp; - int append; +put( + SCR *sp, + CB *cbp, + CHAR_T *namep, + MARK *cp, + MARK *rp, + int append) { CHAR_T name; TEXT *ltp, *tp; recno_t lno; size_t blen, clen, len; int rval; - char *bp, *p, *t; + CHAR_T *bp, *t; + CHAR_T *p; if (cbp == NULL) if (namep == NULL) { @@ -63,7 +66,7 @@ put(sp, cbp, namep, cp, rp, append) return (1); } } - tp = cbp->textq.cqh_first; + tp = TAILQ_FIRST(cbp->textq); /* * It's possible to do a put into an empty file, meaning that the cut @@ -84,8 +87,8 @@ put(sp, cbp, namep, cp, rp, append) if (db_last(sp, &lno)) return (1); if (lno == 0) { - for (; tp != (void *)&cbp->textq; - ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next) + for (; tp != NULL; + ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) if (db_append(sp, 1, lno, tp->lb, tp->len)) return (1); rp->lno = 1; @@ -98,8 +101,8 @@ put(sp, cbp, namep, cp, rp, append) if (F_ISSET(cbp, CB_LMODE)) { lno = append ? cp->lno : cp->lno - 1; rp->lno = lno + 1; - for (; tp != (void *)&cbp->textq; - ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next) + for (; tp != NULL; + ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) if (db_append(sp, 1, lno, tp->lb, tp->len)) return (1); rp->cno = 0; @@ -120,19 +123,19 @@ put(sp, cbp, namep, cp, rp, append) if (db_get(sp, lno, DBG_FATAL, &p, &len)) return (1); - GET_SPACE_RET(sp, bp, blen, tp->len + len + 1); + GET_SPACE_RETW(sp, bp, blen, tp->len + len + 1); t = bp; /* Original line, left of the split. */ if (len > 0 && (clen = cp->cno + (append ? 1 : 0)) > 0) { - memcpy(bp, p, clen); + MEMCPY(bp, p, clen); p += clen; t += clen; } /* First line from the CB. */ if (tp->len != 0) { - memcpy(t, tp->lb, tp->len); + MEMCPY(t, tp->lb, tp->len); t += tp->len; } @@ -161,9 +164,9 @@ put(sp, cbp, namep, cp, rp, append) * the intermediate lines, because the line changes will lose * the cached line. */ - if (tp->q.cqe_next == (void *)&cbp->textq) { + if (TAILQ_NEXT(tp, q) == NULL) { if (clen > 0) { - memcpy(t, p, clen); + MEMCPY(t, p, clen); t += clen; } if (db_set(sp, lno, bp, t - bp)) @@ -183,15 +186,15 @@ put(sp, cbp, namep, cp, rp, append) * Last part of original line; check for space, reset * the pointer into the buffer. */ - ltp = cbp->textq.cqh_last; + ltp = TAILQ_LAST(cbp->textq, _texth); len = t - bp; - ADD_SPACE_RET(sp, bp, blen, ltp->len + clen); + ADD_SPACE_RETW(sp, bp, blen, ltp->len + clen); t = bp + len; /* Add in last part of the CB. */ - memcpy(t, ltp->lb, ltp->len); + MEMCPY(t, ltp->lb, ltp->len); if (clen) - memcpy(t + ltp->len, p, clen); + MEMCPY(t + ltp->len, p, clen); clen += ltp->len; /* @@ -211,9 +214,8 @@ put(sp, cbp, namep, cp, rp, append) } /* Output any intermediate lines in the CB. */ - for (tp = tp->q.cqe_next; - tp->q.cqe_next != (void *)&cbp->textq; - ++lno, ++sp->rptlines[L_ADDED], tp = tp->q.cqe_next) + for (tp = TAILQ_NEXT(tp, q); TAILQ_NEXT(tp, q) != NULL; + ++lno, ++sp->rptlines[L_ADDED], tp = TAILQ_NEXT(tp, q)) if (db_append(sp, 1, lno, tp->lb, tp->len)) goto err; @@ -226,6 +228,6 @@ put(sp, cbp, namep, cp, rp, append) if (0) err: rval = 1; - FREE_SPACE(sp, bp, blen); + FREE_SPACEW(sp, bp, blen); return (rval); } diff --git a/contrib/nvi/common/recover.c b/contrib/nvi/common/recover.c index f3abaab..b20471f 100644 --- a/contrib/nvi/common/recover.c +++ b/contrib/nvi/common/recover.c @@ -10,11 +10,10 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)recover.c 10.21 (Berkeley) 9/15/96"; +static const char sccsid[] = "$Id: recover.c,v 11.2 2012/10/09 08:06:58 zy Exp $"; #endif /* not lint */ -#include <sys/param.h> -#include <sys/types.h> /* XXX: param.h may not have included types.h */ +#include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> @@ -31,12 +30,15 @@ static const char sccsid[] = "@(#)recover.c 10.21 (Berkeley) 9/15/96"; #include <fcntl.h> #include <limits.h> #include <pwd.h> +#include <netinet/in.h> /* Required by resolv.h. */ +#include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> +#include "../ex/version.h" #include "common.h" #include "pathnames.h" @@ -57,12 +59,7 @@ static const char sccsid[] = "@(#)recover.c 10.21 (Berkeley) 9/15/96"; * file exists, and is exclusively locked. * * In the EXF structure we maintain a file descriptor that is the locked - * file descriptor for the mail recovery file. NOTE: we sometimes have to - * do locking with fcntl(2). This is a problem because if you close(2) any - * file descriptor associated with the file, ALL of the locks go away. Be - * sure to remember that if you have to modify the recovery code. (It has - * been rhetorically asked of what the designers could have been thinking - * when they did that interface. The answer is simple: they weren't.) + * file descriptor for the mail recovery file. * * To find out if a recovery file/backing file pair are in use, try to get * a lock on the recovery file. @@ -93,27 +90,24 @@ static const char sccsid[] = "@(#)recover.c 10.21 (Berkeley) 9/15/96"; * means that the data structures (SCR, EXF, the underlying tree structures) * must be consistent when the signal arrives. * - * The recovery mail file contains normal mail headers, with two additions, - * which occur in THIS order, as the FIRST TWO headers: + * The recovery mail file contains normal mail headers, with two additional * - * X-vi-recover-file: file_name - * X-vi-recover-path: recover_path + * X-vi-data: <file|path>;<base64 encoded path> * - * Since newlines delimit the headers, this means that file names cannot have - * newlines in them, but that's probably okay. As these files aren't intended - * to be long-lived, changing their format won't be too painful. + * MIME headers; the folding character is limited to ' '. * - * Btree files are named "vi.XXXX" and recovery files are named "recover.XXXX". + * Btree files are named "vi.XXXXXX" and recovery files are named + * "recover.XXXXXX". */ -#define VI_FHEADER "X-vi-recover-file: " -#define VI_PHEADER "X-vi-recover-path: " +#define VI_DHEADER "X-vi-data:" static int rcv_copy __P((SCR *, int, char *)); static void rcv_email __P((SCR *, char *)); -static char *rcv_gets __P((char *, size_t, int)); static int rcv_mailfile __P((SCR *, int, char *)); -static int rcv_mktemp __P((SCR *, char *, char *, int)); +static int rcv_mktemp __P((SCR *, char *, char *)); +static int rcv_dlnwrite __P((SCR *, const char *, const char *, FILE *)); +static int rcv_dlnread __P((SCR *, char **, char **, FILE *)); /* * rcv_tmp -- @@ -122,14 +116,14 @@ static int rcv_mktemp __P((SCR *, char *, char *, int)); * PUBLIC: int rcv_tmp __P((SCR *, EXF *, char *)); */ int -rcv_tmp(sp, ep, name) - SCR *sp; - EXF *ep; - char *name; +rcv_tmp( + SCR *sp, + EXF *ep, + char *name) { struct stat sb; int fd; - char *dp, *p, path[MAXPATHLEN]; + char *dp, *path; /* * !!! @@ -153,22 +147,17 @@ rcv_tmp(sp, ep, name) (void)chmod(dp, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX); } - /* Newlines delimit the mail messages. */ - for (p = name; *p; ++p) - if (*p == '\n') { - msgq(sp, M_ERR, - "055|Files with newlines in the name are unrecoverable"); - goto err; - } - - (void)snprintf(path, sizeof(path), "%s/vi.XXXXXX", dp); - if ((fd = rcv_mktemp(sp, path, dp, S_IRWXU)) == -1) + if ((path = join(dp, "vi.XXXXXX")) == NULL) goto err; + if ((fd = rcv_mktemp(sp, path, dp)) == -1) { + free(path); + goto err; + } + (void)fchmod(fd, S_IRWXU); (void)close(fd); - if ((ep->rcv_path = strdup(path)) == NULL) { - msgq(sp, M_SYSERR, NULL); - (void)unlink(path); + ep->rcv_path = path; + if (0) { err: msgq(sp, M_ERR, "056|Modifications not recoverable if the session fails"); return (1); @@ -186,8 +175,7 @@ err: msgq(sp, M_ERR, * PUBLIC: int rcv_init __P((SCR *)); */ int -rcv_init(sp) - SCR *sp; +rcv_init(SCR *sp) { EXF *ep; recno_t lno; @@ -249,13 +237,13 @@ err: msgq(sp, M_ERR, * PUBLIC: int rcv_sync __P((SCR *, u_int)); */ int -rcv_sync(sp, flags) - SCR *sp; - u_int flags; +rcv_sync( + SCR *sp, + u_int flags) { EXF *ep; int fd, rval; - char *dp, buf[1024]; + char *dp, *buf; /* Make sure that there's something to recover/sync. */ ep = sp->ep; @@ -298,9 +286,14 @@ rcv_sync(sp, flags) if (opts_empty(sp, O_RECDIR, 0)) goto err; dp = O_STR(sp, O_RECDIR); - (void)snprintf(buf, sizeof(buf), "%s/vi.XXXXXX", dp); - if ((fd = rcv_mktemp(sp, buf, dp, S_IRUSR | S_IWUSR)) == -1) + if ((buf = join(dp, "vi.XXXXXX")) == NULL) { + msgq(sp, M_SYSERR, NULL); + goto err; + } + if ((fd = rcv_mktemp(sp, buf, dp)) == -1) { + free(buf); goto err; + } sp->gp->scr_busy(sp, "061|Copying file for recovery...", BUSY_ON); if (rcv_copy(sp, fd, ep->rcv_path) || @@ -309,6 +302,7 @@ rcv_sync(sp, flags) (void)close(fd); rval = 1; } + free(buf); sp->gp->scr_busy(sp, NULL, BUSY_OFF); } if (0) { @@ -327,30 +321,32 @@ err: rval = 1; * Build the file to mail to the user. */ static int -rcv_mailfile(sp, issync, cp_path) - SCR *sp; - int issync; - char *cp_path; +rcv_mailfile( + SCR *sp, + int issync, + char *cp_path) { EXF *ep; GS *gp; struct passwd *pw; - size_t len; + int len; time_t now; uid_t uid; int fd; - char *dp, *p, *t, buf[4096], mpath[MAXPATHLEN]; + FILE *fp; + char *dp, *p, *t, *qt, *buf, *mpath; char *t1, *t2, *t3; + int st; /* * XXX - * MAXHOSTNAMELEN is in various places on various systems, including - * <netdb.h> and <sys/socket.h>. If not found, use a large default. + * MAXHOSTNAMELEN/HOST_NAME_MAX are deprecated. We try sysconf(3) + * first, then fallback to _POSIX_HOST_NAME_MAX. */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 1024 -#endif - char host[MAXHOSTNAMELEN]; + char *host; + long hostmax = sysconf(_SC_HOST_NAME_MAX); + if (hostmax < 0) + hostmax = _POSIX_HOST_NAME_MAX; gp = sp->gp; if ((pw = getpwuid(uid = getuid())) == NULL) { @@ -362,9 +358,19 @@ rcv_mailfile(sp, issync, cp_path) if (opts_empty(sp, O_RECDIR, 0)) return (1); dp = O_STR(sp, O_RECDIR); - (void)snprintf(mpath, sizeof(mpath), "%s/recover.XXXXXX", dp); - if ((fd = rcv_mktemp(sp, mpath, dp, S_IRUSR | S_IWUSR)) == -1) + if ((mpath = join(dp, "recover.XXXXXX")) == NULL) { + msgq(sp, M_SYSERR, NULL); + return (1); + } + if ((fd = rcv_mktemp(sp, mpath, dp)) == -1) { + free(mpath); return (1); + } + if ((fp = fdopen(fd, "w")) == NULL) { + free(mpath); + close(fd); + return (1); + } /* * XXX @@ -374,56 +380,64 @@ rcv_mailfile(sp, issync, cp_path) * and the lock, but it's pretty small. */ ep = sp->ep; - if (file_lock(sp, NULL, NULL, fd, 1) != LOCK_SUCCESS) + if (file_lock(sp, NULL, fd, 1) != LOCK_SUCCESS) msgq(sp, M_SYSERR, "063|Unable to lock recovery file"); if (!issync) { /* Save the recover file descriptor, and mail path. */ - ep->rcv_fd = fd; - if ((ep->rcv_mpath = strdup(mpath)) == NULL) { - msgq(sp, M_SYSERR, NULL); - goto err; - } + ep->rcv_fd = dup(fd); + ep->rcv_mpath = mpath; cp_path = ep->rcv_path; } - /* - * XXX - * We can't use stdio(3) here. The problem is that we may be using - * fcntl(2), so if ANY file descriptor into the file is closed, the - * lock is lost. So, we could never close the FILE *, even if we - * dup'd the fd first. - */ t = sp->frp->name; if ((p = strrchr(t, '/')) == NULL) p = t; else ++p; (void)time(&now); - (void)gethostname(host, sizeof(host)); - len = snprintf(buf, sizeof(buf), - "%s%s\n%s%s\n%s\n%s\n%s%s\n%s%s\n%s\n\n", - VI_FHEADER, t, /* Non-standard. */ - VI_PHEADER, cp_path, /* Non-standard. */ - "Reply-To: root", - "From: root (Nvi recovery program)", - "To: ", pw->pw_name, + + if ((st = rcv_dlnwrite(sp, "file", t, fp))) { + if (st == 1) + goto werr; + goto err; + } + if ((st = rcv_dlnwrite(sp, "path", cp_path, fp))) { + if (st == 1) + goto werr; + goto err; + } + + MALLOC(sp, host, char *, hostmax + 1); + if (host == NULL) + goto err; + (void)gethostname(host, hostmax + 1); + + len = fprintf(fp, "%s%s%s\n%s%s%s%s\n%s%.40s\n%s\n\n", + "From: root@", host, " (Nvi recovery program)", + "To: ", pw->pw_name, "@", host, "Subject: Nvi saved the file ", p, "Precedence: bulk"); /* For vacation(1). */ - if (len > sizeof(buf) - 1) - goto lerr; - if (write(fd, buf, len) != len) + if (len < 0) { + free(host); goto werr; + } - len = snprintf(buf, sizeof(buf), - "%s%.24s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n\n", + if ((qt = quote(t)) == NULL) { + free(host); + msgq(sp, M_SYSERR, NULL); + goto err; + } + len = asprintf(&buf, "%s%.24s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n\n", "On ", ctime(&now), ", the user ", pw->pw_name, " was editing a file named ", t, " on the machine ", host, ", when it was saved for recovery. ", "You can recover most, if not all, of the changes ", "to this file using the -r option to ", gp->progname, ":\n\n\t", - gp->progname, " -r ", t); - if (len > sizeof(buf) - 1) { -lerr: msgq(sp, M_ERR, "064|Recovery file buffer overrun"); + gp->progname, " -r ", qt); + free(qt); + free(host); + if (buf == NULL) { + msgq(sp, M_SYSERR, NULL); goto err; } @@ -457,23 +471,29 @@ lerr: msgq(sp, M_ERR, "064|Recovery file buffer overrun"); wout: *t2++ = '\n'; /* t2 points one after the last character to display. */ - if (write(fd, t1, t2 - t1) != t2 - t1) + if (fwrite(t1, 1, t2 - t1, fp) != t2 - t1) { + free(buf); goto werr; + } } if (issync) { + fflush(fp); rcv_email(sp, mpath); - if (close(fd)) { -werr: msgq(sp, M_SYSERR, "065|Recovery file"); - goto err; - } + free(mpath); + } + if (fclose(fp)) { + free(buf); +werr: msgq(sp, M_SYSERR, "065|Recovery file"); + goto err; } + free(buf); return (0); err: if (!issync) ep->rcv_fd = -1; - if (fd != -1) - (void)close(fd); + if (fp != NULL) + (void)fclose(fp); return (1); } @@ -488,15 +508,16 @@ err: if (!issync) * PUBLIC: int rcv_list __P((SCR *)); */ int -rcv_list(sp) - SCR *sp; +rcv_list(SCR *sp) { struct dirent *dp; struct stat sb; DIR *dirp; FILE *fp; int found; - char *p, *t, file[MAXPATHLEN], path[MAXPATHLEN]; + char *p, *file, *path; + char *dtype, *data; + int st; /* Open the recovery directory for reading. */ if (opts_empty(sp, O_RECDIR, 0)) @@ -512,18 +533,11 @@ rcv_list(sp) if (strncmp(dp->d_name, "recover.", 8)) continue; - /* - * If it's readable, it's recoverable. - * - * XXX - * Should be "r", we don't want to write the file. However, - * if we're using fcntl(2), there's no way to lock a file - * descriptor that's not open for writing. - */ - if ((fp = fopen(dp->d_name, "r+")) == NULL) + /* If it's readable, it's recoverable. */ + if ((fp = fopen(dp->d_name, "r")) == NULL) continue; - switch (file_lock(sp, NULL, NULL, fileno(fp), 1)) { + switch (file_lock(sp, NULL, fileno(fp), 1)) { case LOCK_FAILED: /* * XXX @@ -542,17 +556,23 @@ rcv_list(sp) } /* Check the headers. */ - if (fgets(file, sizeof(file), fp) == NULL || - strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) || - (p = strchr(file, '\n')) == NULL || - fgets(path, sizeof(path), fp) == NULL || - strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) || - (t = strchr(path, '\n')) == NULL) { - msgq_str(sp, M_ERR, dp->d_name, - "066|%s: malformed recovery file"); - goto next; + for (file = NULL, path = NULL; + file == NULL || path == NULL;) { + if ((st = rcv_dlnread(sp, &dtype, &data, fp))) { + if (st == 1) + msgq_str(sp, M_ERR, dp->d_name, + "066|%s: malformed recovery file"); + goto next; + } + if (dtype == NULL) + continue; + if (!strcmp(dtype, "file")) + file = data; + else if (!strcmp(dtype, "path")) + path = data; + else + free(data); } - *p = *t = '\0'; /* * If the file doesn't exist, it's an orphaned recovery file, @@ -563,7 +583,7 @@ rcv_list(sp) * before deleting the email file. */ errno = 0; - if (stat(path + sizeof(VI_PHEADER) - 1, &sb) && + if (stat(path, &sb) && errno == ENOENT) { (void)unlink(dp->d_name); goto next; @@ -572,14 +592,18 @@ rcv_list(sp) /* Get the last modification time and display. */ (void)fstat(fileno(fp), &sb); (void)printf("%.24s: %s\n", - ctime(&sb.st_mtime), file + sizeof(VI_FHEADER) - 1); + ctime(&sb.st_mtime), file); found = 1; /* Close, discarding lock. */ next: (void)fclose(fp); + if (file != NULL) + free(file); + if (path != NULL) + free(path); } if (found == 0) - (void)printf("vi: no files to recover.\n"); + (void)printf("%s: No files to recover\n", sp->gp->progname); (void)closedir(dirp); return (0); } @@ -591,18 +615,21 @@ next: (void)fclose(fp); * PUBLIC: int rcv_read __P((SCR *, FREF *)); */ int -rcv_read(sp, frp) - SCR *sp; - FREF *frp; +rcv_read( + SCR *sp, + FREF *frp) { struct dirent *dp; struct stat sb; DIR *dirp; + FILE *fp; EXF *ep; - time_t rec_mtime; - int fd, found, locked, requested, sv_fd; + struct timespec rec_mtim = { 0, 0 }; + int found, locked = 0, requested, sv_fd; char *name, *p, *t, *rp, *recp, *pathp; - char file[MAXPATHLEN], path[MAXPATHLEN], recpath[MAXPATHLEN]; + char *file, *path, *recpath; + char *dtype, *data; + int st; if (opts_empty(sp, O_RECDIR, 0)) return (1); @@ -614,30 +641,22 @@ rcv_read(sp, frp) name = frp->name; sv_fd = -1; - rec_mtime = 0; recp = pathp = NULL; for (found = requested = 0; (dp = readdir(dirp)) != NULL;) { if (strncmp(dp->d_name, "recover.", 8)) continue; - (void)snprintf(recpath, - sizeof(recpath), "%s/%s", rp, dp->d_name); + if ((recpath = join(rp, dp->d_name)) == NULL) { + msgq(sp, M_SYSERR, NULL); + continue; + } - /* - * If it's readable, it's recoverable. It would be very - * nice to use stdio(3), but, we can't because that would - * require closing and then reopening the file so that we - * could have a lock and still close the FP. Another tip - * of the hat to fcntl(2). - * - * XXX - * Should be O_RDONLY, we don't want to write it. However, - * if we're using fcntl(2), there's no way to lock a file - * descriptor that's not open for writing. - */ - if ((fd = open(recpath, O_RDWR, 0)) == -1) + /* If it's readable, it's recoverable. */ + if ((fp = fopen(recpath, "r")) == NULL) { + free(recpath); continue; + } - switch (file_lock(sp, NULL, NULL, fd, 1)) { + switch (file_lock(sp, NULL, fileno(fp), 1)) { case LOCK_FAILED: /* * XXX @@ -653,22 +672,28 @@ rcv_read(sp, frp) break; case LOCK_UNAVAIL: /* If it's locked, it's live. */ - (void)close(fd); + (void)fclose(fp); continue; } /* Check the headers. */ - if (rcv_gets(file, sizeof(file), fd) == NULL || - strncmp(file, VI_FHEADER, sizeof(VI_FHEADER) - 1) || - (p = strchr(file, '\n')) == NULL || - rcv_gets(path, sizeof(path), fd) == NULL || - strncmp(path, VI_PHEADER, sizeof(VI_PHEADER) - 1) || - (t = strchr(path, '\n')) == NULL) { - msgq_str(sp, M_ERR, recpath, - "067|%s: malformed recovery file"); - goto next; + for (file = NULL, path = NULL; + file == NULL || path == NULL;) { + if ((st = rcv_dlnread(sp, &dtype, &data, fp))) { + if (st == 1) + msgq_str(sp, M_ERR, dp->d_name, + "067|%s: malformed recovery file"); + goto next; + } + if (dtype == NULL) + continue; + if (!strcmp(dtype, "file")) + file = data; + else if (!strcmp(dtype, "path")) + path = data; + else + free(data); } - *p = *t = '\0'; ++found; /* @@ -680,52 +705,42 @@ rcv_read(sp, frp) * before deleting the email file. */ errno = 0; - if (stat(path + sizeof(VI_PHEADER) - 1, &sb) && + if (stat(path, &sb) && errno == ENOENT) { (void)unlink(dp->d_name); goto next; } /* Check the file name. */ - if (strcmp(file + sizeof(VI_FHEADER) - 1, name)) + if (strcmp(file, name)) goto next; ++requested; - /* - * If we've found more than one, take the most recent. - * - * XXX - * Since we're using st_mtime, for portability reasons, - * we only get a single second granularity, instead of - * getting it right. - */ - (void)fstat(fd, &sb); - if (recp == NULL || rec_mtime < sb.st_mtime) { + /* If we've found more than one, take the most recent. */ + (void)fstat(fileno(fp), &sb); + if (recp == NULL || + timespeccmp(&rec_mtim, &sb.st_mtimespec, <)) { p = recp; t = pathp; - if ((recp = strdup(recpath)) == NULL) { - msgq(sp, M_SYSERR, NULL); - recp = p; - goto next; - } - if ((pathp = strdup(path)) == NULL) { - msgq(sp, M_SYSERR, NULL); - free(recp); - recp = p; - pathp = t; - goto next; - } + recp = recpath; + pathp = path; if (p != NULL) { free(p); free(t); } - rec_mtime = sb.st_mtime; + rec_mtim = sb.st_mtimespec; if (sv_fd != -1) (void)close(sv_fd); - sv_fd = fd; - } else -next: (void)close(fd); + sv_fd = dup(fileno(fp)); + } else { +next: free(recpath); + if (path != NULL) + free(path); + } + (void)fclose(fp); + if (file != NULL) + free(file); } (void)closedir(dirp); @@ -749,12 +764,13 @@ next: (void)close(fd); * XXX * file_init() is going to set ep->rcv_path. */ - if (file_init(sp, frp, pathp + sizeof(VI_PHEADER) - 1, 0)) { + if (file_init(sp, frp, pathp, 0)) { free(recp); free(pathp); (void)close(sv_fd); return (1); } + free(pathp); /* * We keep an open lock on the file so that the recover option can @@ -777,10 +793,10 @@ next: (void)close(fd); * Copy a recovery file. */ static int -rcv_copy(sp, wfd, fname) - SCR *sp; - int wfd; - char *fname; +rcv_copy( + SCR *sp, + int wfd, + char *fname) { int nr, nw, off, rfd; char buf[8 * 1024]; @@ -799,52 +815,19 @@ err: msgq_str(sp, M_SYSERR, fname, "%s"); } /* - * rcv_gets -- - * Fgets(3) for a file descriptor. - */ -static char * -rcv_gets(buf, len, fd) - char *buf; - size_t len; - int fd; -{ - int nr; - char *p; - - if ((nr = read(fd, buf, len - 1)) == -1) - return (NULL); - if ((p = strchr(buf, '\n')) == NULL) - return (NULL); - (void)lseek(fd, (off_t)((p - buf) + 1), SEEK_SET); - return (buf); -} - -/* * rcv_mktemp -- * Paranoid make temporary file routine. */ static int -rcv_mktemp(sp, path, dname, perms) - SCR *sp; - char *path, *dname; - int perms; +rcv_mktemp( + SCR *sp, + char *path, + char *dname) { int fd; - /* - * !!! - * We expect mkstemp(3) to set the permissions correctly. On - * historic System V systems, mkstemp didn't. Do it here, on - * GP's. - * - * XXX - * The variable perms should really be a mode_t, and it would - * be nice to use fchmod(2) instead of chmod(2), here. - */ if ((fd = mkstemp(path)) == -1) msgq_str(sp, M_SYSERR, dname, "%s"); - else - (void)chmod(path, perms); return (fd); } @@ -853,26 +836,141 @@ rcv_mktemp(sp, path, dname, perms) * Send email. */ static void -rcv_email(sp, fname) - SCR *sp; - char *fname; +rcv_email( + SCR *sp, + char *fname) { - struct stat sb; - char buf[MAXPATHLEN * 2 + 20]; + char *buf; - if (_PATH_SENDMAIL[0] != '/' || stat(_PATH_SENDMAIL, &sb)) - msgq_str(sp, M_SYSERR, - _PATH_SENDMAIL, "071|not sending email: %s"); - else { - /* - * !!! - * If you need to port this to a system that doesn't have - * sendmail, the -t flag causes sendmail to read the message - * for the recipients instead of specifying them some other - * way. - */ - (void)snprintf(buf, sizeof(buf), - "%s -t < %s", _PATH_SENDMAIL, fname); - (void)system(buf); + (void)asprintf(&buf, _PATH_SENDMAIL " -odb -t < %s", fname); + if (buf == NULL) { + msgq_str(sp, M_ERR, strerror(errno), + "071|not sending email: %s"); + return; + } + (void)system(buf); + free(buf); +} + +/* + * rcv_dlnwrite -- + * Encode a string into an X-vi-data line and write it. + */ +static int +rcv_dlnwrite( + SCR *sp, + const char *dtype, + const char *src, + FILE *fp) +{ + char *bp = NULL, *p; + size_t blen = 0; + size_t dlen, len; + int plen, xlen; + + len = strlen(src); + dlen = strlen(dtype); + GET_SPACE_GOTOC(sp, bp, blen, (len + 2) / 3 * 4 + dlen + 2); + (void)memcpy(bp, dtype, dlen); + bp[dlen] = ';'; + if ((xlen = b64_ntop((u_char *)src, + len, bp + dlen + 1, blen)) == -1) + goto err; + xlen += dlen + 1; + + /* Output as an MIME folding header. */ + if ((plen = fprintf(fp, VI_DHEADER " %.*s\n", + FMTCOLS - (int)sizeof(VI_DHEADER), bp)) < 0) + goto err; + plen -= (int)sizeof(VI_DHEADER) + 1; + for (p = bp, xlen -= plen; xlen > 0; xlen -= plen) { + p += plen; + if ((plen = fprintf(fp, " %.*s\n", FMTCOLS - 1, p)) < 0) + goto err; + plen -= 2; + } + FREE_SPACE(sp, bp, blen); + return (0); + +err: FREE_SPACE(sp, bp, blen); + return (1); +alloc_err: + msgq(sp, M_SYSERR, NULL); + return (-1); +} + +/* + * rcv_dlnread -- + * Read an X-vi-data line and decode it. + */ +static int +rcv_dlnread( + SCR *sp, + char **dtypep, + char **datap, /* free *datap if != NULL after use. */ + FILE *fp) +{ + int ch; + char buf[1024]; + char *bp = NULL, *p, *src; + size_t blen = 0; + size_t len, off, dlen; + char *dtype, *data; + int xlen; + + if (fgets(buf, sizeof(buf), fp) == NULL) + return (1); + if (strncmp(buf, VI_DHEADER, sizeof(VI_DHEADER) - 1)) { + *dtypep = NULL; + *datap = NULL; + return (0); + } + + /* Fetch an MIME folding header. */ + len = strlen(buf) - sizeof(VI_DHEADER) + 1; + GET_SPACE_GOTOC(sp, bp, blen, len); + (void)memcpy(bp, buf + sizeof(VI_DHEADER) - 1, len); + p = bp + len; + while ((ch = fgetc(fp)) == ' ') { + if (fgets(buf, sizeof(buf), fp) == NULL) + goto err; + off = strlen(buf); + len += off; + ADD_SPACE_GOTOC(sp, bp, blen, len); + p = bp + len - off; + (void)memcpy(p, buf, off); + } + bp[len] = '\0'; + (void)ungetc(ch, fp); + + for (p = bp; *p == ' ' || *p == '\n'; p++); + if ((src = strchr(p, ';')) == NULL) + goto err; + dlen = src - p; + src += 1; + len -= src - bp; + + /* Memory looks like: "<data>\0<dtype>\0". */ + MALLOC(sp, data, char *, dlen + len / 4 * 3 + 2); + if (data == NULL) + goto err; + if ((xlen = (b64_pton(p + dlen + 1, + (u_char *)data, len / 4 * 3 + 1))) == -1) { + free(data); + goto err; } + data[xlen] = '\0'; + dtype = data + xlen + 1; + (void)memcpy(dtype, p, dlen); + dtype[dlen] = '\0'; + FREE_SPACE(sp, bp, blen); + *dtypep = dtype; + *datap = data; + return (0); + +err: FREE_SPACE(sp, bp, blen); + return (1); +alloc_err: + msgq(sp, M_SYSERR, NULL); + return (-1); } diff --git a/contrib/nvi/common/screen.c b/contrib/nvi/common/screen.c index ba9e287..9ff6845 100644 --- a/contrib/nvi/common/screen.c +++ b/contrib/nvi/common/screen.c @@ -10,7 +10,7 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)screen.c 10.15 (Berkeley) 9/15/96"; +static const char sccsid[] = "$Id: screen.c,v 10.25 2011/12/04 04:06:45 zy Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -35,9 +35,10 @@ static const char sccsid[] = "@(#)screen.c 10.15 (Berkeley) 9/15/96"; * PUBLIC: int screen_init __P((GS *, SCR *, SCR **)); */ int -screen_init(gp, orig, spp) - GS *gp; - SCR *orig, **spp; +screen_init( + GS *gp, + SCR *orig, + SCR **spp) { SCR *sp; size_t len; @@ -50,9 +51,9 @@ screen_init(gp, orig, spp) sp->id = ++gp->id; sp->refcnt = 1; - sp->gp = gp; /* All ref the GS structure. */ + sp->gp = gp; /* All ref the GS structure. */ - sp->ccnt = 2; /* Anything > 1 */ + sp->ccnt = 2; /* Anything > 1 */ /* * XXX @@ -60,7 +61,7 @@ screen_init(gp, orig, spp) * we don't have the option information yet. */ - CIRCLEQ_INIT(&sp->tiq); + TAILQ_INIT(sp->tiq); /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ if (orig == NULL) { @@ -80,15 +81,15 @@ screen_init(gp, orig, spp) /* Retain searching/substitution information. */ sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD; if (orig->re != NULL && (sp->re = - v_strdup(sp, orig->re, orig->re_len)) == NULL) + v_wstrdup(sp, orig->re, orig->re_len)) == NULL) goto mem; sp->re_len = orig->re_len; if (orig->subre != NULL && (sp->subre = - v_strdup(sp, orig->subre, orig->subre_len)) == NULL) + v_wstrdup(sp, orig->subre, orig->subre_len)) == NULL) goto mem; sp->subre_len = orig->subre_len; if (orig->repl != NULL && (sp->repl = - v_strdup(sp, orig->repl, orig->repl_len)) == NULL) + v_wstrdup(sp, orig->repl, orig->repl_len)) == NULL) goto mem; sp->repl_len = orig->repl_len; if (orig->newl_len) { @@ -113,6 +114,8 @@ mem: msgq(orig, M_SYSERR, NULL); goto err; if (v_screen_copy(orig, sp)) /* Vi. */ goto err; + sp->cl_private = 0; /* XXX */ + conv_init(orig, sp); /* XXX */ *spp = sp; return (0); @@ -129,8 +132,7 @@ err: screen_end(sp); * PUBLIC: int screen_end __P((SCR *)); */ int -screen_end(sp) - SCR *sp; +screen_end(SCR *sp) { int rval; @@ -144,17 +146,13 @@ screen_end(sp) * If a created screen failed during initialization, it may not * be linked into the chain. */ - if (sp->q.cqe_next != NULL) - CIRCLEQ_REMOVE(&sp->gp->dq, sp, q); + if (TAILQ_ENTRY_ISVALID(sp, q)) + TAILQ_REMOVE(sp->gp->dq, sp, q); /* The screen is no longer real. */ F_CLR(sp, SC_SCR_EX | SC_SCR_VI); rval = 0; -#ifdef HAVE_PERL_INTERP - if (perl_screen_end(sp)) /* End perl. */ - rval = 1; -#endif if (v_screen_end(sp)) /* End vi. */ rval = 1; if (ex_screen_end(sp)) /* End ex. */ @@ -170,8 +168,8 @@ screen_end(sp) } /* Free any text input. */ - if (sp->tiq.cqh_first != NULL) - text_lfree(&sp->tiq); + if (!TAILQ_EMPTY(sp->tiq)) + text_lfree(sp->tiq); /* Free alternate file name. */ if (sp->alt_name != NULL) @@ -191,6 +189,9 @@ screen_end(sp) if (sp->newl != NULL) free(sp->newl); + /* Free the iconv environment */ + conv_end(sp); + /* Free all the options */ opts_free(sp); @@ -207,26 +208,24 @@ screen_end(sp) * PUBLIC: SCR *screen_next __P((SCR *)); */ SCR * -screen_next(sp) - SCR *sp; +screen_next(SCR *sp) { GS *gp; SCR *next; /* Try the display queue, without returning the current screen. */ gp = sp->gp; - for (next = gp->dq.cqh_first; - next != (void *)&gp->dq; next = next->q.cqe_next) + TAILQ_FOREACH(next, gp->dq, q) if (next != sp) break; - if (next != (void *)&gp->dq) + if (next != NULL) return (next); /* Try the hidden queue; if found, move screen to the display queue. */ - if (gp->hq.cqh_first != (void *)&gp->hq) { - next = gp->hq.cqh_first; - CIRCLEQ_REMOVE(&gp->hq, next, q); - CIRCLEQ_INSERT_HEAD(&gp->dq, next, q); + if (!TAILQ_EMPTY(gp->hq)) { + next = TAILQ_FIRST(gp->hq); + TAILQ_REMOVE(gp->hq, next, q); + TAILQ_INSERT_HEAD(gp->dq, next, q); return (next); } return (NULL); diff --git a/contrib/nvi/common/screen.h b/contrib/nvi/common/screen.h index bb7254f..a762706 100644 --- a/contrib/nvi/common/screen.h +++ b/contrib/nvi/common/screen.h @@ -6,7 +6,7 @@ * * See the LICENSE file for redistribution information. * - * @(#)screen.h 10.24 (Berkeley) 7/19/96 + * $Id: screen.h,v 10.26 2011/12/12 22:31:36 zy Exp $ */ /* @@ -32,7 +32,7 @@ */ struct _scr { /* INITIALIZED AT SCREEN CREATE. */ - CIRCLEQ_ENTRY(_scr) q; /* Screens. */ + TAILQ_ENTRY(_scr) q; /* Screens. */ int id; /* Screen id #. */ int refcnt; /* Reference count. */ @@ -55,7 +55,8 @@ struct _scr { size_t t_rows; /* 1-N: cur number of text rows. */ size_t t_maxrows; /* 1-N: max number of text rows. */ size_t t_minrows; /* 1-N: min number of text rows. */ - size_t woff; /* 0-N: screen offset in frame. */ + size_t coff; /* 0-N: screen col offset in display. */ + size_t roff; /* 0-N: screen row offset in display. */ /* Cursor's: */ recno_t lno; /* 1-N: file line. */ @@ -73,15 +74,16 @@ struct _scr { recno_t rptlchange; /* Ex/vi: last L_CHANGED lno. */ recno_t rptlines[L_YANKED + 1];/* Ex/vi: lines changed by last op. */ - TEXTH tiq; /* Ex/vi: text input queue. */ + TEXTH tiq[1]; /* Ex/vi: text input queue. */ SCRIPT *script; /* Vi: script mode information .*/ recno_t defscroll; /* Vi: ^D, ^U scroll information. */ /* Display character. */ - CHAR_T cname[MAX_CHARACTER_COLUMNS + 1]; + char cname[MAX_CHARACTER_COLUMNS + 1]; size_t clen; /* Length of display character. */ + ARG_CHAR_T lastc; /* The last display character. */ enum { /* Vi editor mode. */ SM_APPEND = 0, SM_CHANGE, SM_COMMAND, SM_INSERT, @@ -89,7 +91,10 @@ struct _scr { void *ex_private; /* Ex private area. */ void *vi_private; /* Vi private area. */ - void *perl_private; /* Perl private area. */ + void *cl_private; /* Curses private area. */ + + CONV conv; /* Conversion functions. */ + CONVWIN cw; /* Conversion buffer. */ /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ char *alt_name; /* Ex/vi: alternate file name. */ @@ -103,8 +108,10 @@ struct _scr { #define RE_C_SUBST 0x0008 /* Compile substitute replacement. */ #define RE_C_TAG 0x0010 /* Compile ctag pattern. */ -#define RE_WSTART "[[:<:]]" /* Ex/vi: not-in-word search pattern. */ -#define RE_WSTOP "[[:>:]]" +#define RE_WSTART L("[[:<:]]") /* Ex/vi: not-in-word search pattern. */ +#define RE_WSTOP L("[[:>:]]") +#define RE_WSTART_LEN (SIZE(RE_WSTART) - 1) +#define RE_WSTOP_LEN (SIZE(RE_WSTOP) - 1) /* Ex/vi: flags to search routines. */ #define SEARCH_CSCOPE 0x0001 /* Search for a cscope pattern. */ #define SEARCH_EOL 0x0002 /* Offset past EOL is okay. */ @@ -119,12 +126,12 @@ struct _scr { /* Ex/vi: RE information. */ dir_t searchdir; /* Last file search direction. */ regex_t re_c; /* Search RE: compiled form. */ - char *re; /* Search RE: uncompiled form. */ + CHAR_T *re; /* Search RE: uncompiled form. */ size_t re_len; /* Search RE: uncompiled length. */ regex_t subre_c; /* Substitute RE: compiled form. */ - char *subre; /* Substitute RE: uncompiled form. */ + CHAR_T *subre; /* Substitute RE: uncompiled form. */ size_t subre_len; /* Substitute RE: uncompiled length). */ - char *repl; /* Substitute replacement. */ + CHAR_T *repl; /* Substitute replacement. */ size_t repl_len; /* Substitute replacement length.*/ size_t *newl; /* Newline offset array. */ size_t newl_len; /* Newline array size. */ @@ -199,5 +206,6 @@ struct _scr { #define SC_STATUS_CNT 0x04000000 /* Welcome message plus file count. */ #define SC_TINPUT 0x08000000 /* Doing text input. */ #define SC_TINPUT_INFO 0x10000000 /* Doing text input on info line. */ +#define SC_CONV_ERROR 0x20000000 /* Met with a conversion error. */ u_int32_t flags; }; diff --git a/contrib/nvi/common/search.c b/contrib/nvi/common/search.c index 3fd2719..22f0203 100644 --- a/contrib/nvi/common/search.c +++ b/contrib/nvi/common/search.c @@ -10,11 +10,12 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)search.c 10.25 (Berkeley) 6/30/96"; +static const char sccsid[] = "$Id: search.c,v 10.26 2011/07/04 20:16:26 zy Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> +#include <sys/time.h> #include <bitstring.h> #include <ctype.h> @@ -30,23 +31,24 @@ static const char sccsid[] = "@(#)search.c 10.25 (Berkeley) 6/30/96"; typedef enum { S_EMPTY, S_EOF, S_NOPREV, S_NOTFOUND, S_SOF, S_WRAP } smsg_t; static void search_msg __P((SCR *, smsg_t)); -static int search_init __P((SCR *, dir_t, char *, size_t, char **, u_int)); +static int search_init __P((SCR *, dir_t, CHAR_T *, size_t, CHAR_T **, u_int)); /* * search_init -- * Set up a search. */ static int -search_init(sp, dir, ptrn, plen, epp, flags) - SCR *sp; - dir_t dir; - char *ptrn, **epp; - size_t plen; - u_int flags; +search_init( + SCR *sp, + dir_t dir, + CHAR_T *ptrn, + size_t plen, + CHAR_T **epp, + u_int flags) { recno_t lno; int delim; - char *p, *t; + CHAR_T *p, *t; /* If the file is empty, it's a fast search. */ if (sp->lno <= 1) { @@ -141,22 +143,24 @@ prev: if (sp->re == NULL) { * Do a forward search. * * PUBLIC: int f_search __P((SCR *, - * PUBLIC: MARK *, MARK *, char *, size_t, char **, u_int)); + * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int)); */ int -f_search(sp, fm, rm, ptrn, plen, eptrn, flags) - SCR *sp; - MARK *fm, *rm; - char *ptrn, **eptrn; - size_t plen; - u_int flags; +f_search( + SCR *sp, + MARK *fm, + MARK *rm, + CHAR_T *ptrn, + size_t plen, + CHAR_T **eptrn, + u_int flags) { busy_t btype; recno_t lno; regmatch_t match[1]; size_t coff, len; int cnt, eval, rval, wrapped; - char *l; + CHAR_T *l; if (search_init(sp, FORWARD, ptrn, plen, eptrn, flags)) return (1); @@ -210,7 +214,7 @@ f_search(sp, fm, rm, ptrn, plen, eptrn, flags) } cnt = INTERRUPT_CHECK; } - if (wrapped && lno > fm->lno || db_get(sp, lno, 0, &l, &len)) { + if ((wrapped && lno > fm->lno) || db_get(sp, lno, 0, &l, &len)) { if (wrapped) { if (LF_ISSET(SEARCH_MSG)) search_msg(sp, S_NOTFOUND); @@ -285,22 +289,24 @@ f_search(sp, fm, rm, ptrn, plen, eptrn, flags) * Do a backward search. * * PUBLIC: int b_search __P((SCR *, - * PUBLIC: MARK *, MARK *, char *, size_t, char **, u_int)); + * PUBLIC: MARK *, MARK *, CHAR_T *, size_t, CHAR_T **, u_int)); */ int -b_search(sp, fm, rm, ptrn, plen, eptrn, flags) - SCR *sp; - MARK *fm, *rm; - char *ptrn, **eptrn; - size_t plen; - u_int flags; +b_search( + SCR *sp, + MARK *fm, + MARK *rm, + CHAR_T *ptrn, + size_t plen, + CHAR_T **eptrn, + u_int flags) { busy_t btype; recno_t lno; regmatch_t match[1]; size_t coff, last, len; int cnt, eval, rval, wrapped; - char *l; + CHAR_T *l; if (search_init(sp, BACKWARD, ptrn, plen, eptrn, flags)) return (1); @@ -342,7 +348,7 @@ b_search(sp, fm, rm, ptrn, plen, eptrn, flags) } cnt = INTERRUPT_CHECK; } - if (wrapped && lno < fm->lno || lno == 0) { + if ((wrapped && lno < fm->lno) || lno == 0) { if (wrapped) { if (LF_ISSET(SEARCH_MSG)) search_msg(sp, S_NOTFOUND); @@ -447,9 +453,9 @@ err: if (LF_ISSET(SEARCH_MSG)) * Display one of the search messages. */ static void -search_msg(sp, msg) - SCR *sp; - smsg_t msg; +search_msg( + SCR *sp, + smsg_t msg) { switch (msg) { case S_EMPTY: @@ -484,9 +490,9 @@ search_msg(sp, msg) * PUBLIC: void search_busy __P((SCR *, busy_t)); */ void -search_busy(sp, btype) - SCR *sp; - busy_t btype; +search_busy( + SCR *sp, + busy_t btype) { sp->gp->scr_busy(sp, "078|Searching...", btype); } diff --git a/contrib/nvi/common/seq.c b/contrib/nvi/common/seq.c index e2be879..45c6c11 100644 --- a/contrib/nvi/common/seq.c +++ b/contrib/nvi/common/seq.c @@ -10,11 +10,12 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)seq.c 10.10 (Berkeley) 3/30/96"; +static const char sccsid[] = "$Id: seq.c,v 10.18 2011/12/11 23:13:00 zy Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> +#include <sys/time.h> #include <bitstring.h> #include <ctype.h> @@ -34,12 +35,16 @@ static const char sccsid[] = "@(#)seq.c 10.10 (Berkeley) 3/30/96"; * PUBLIC: size_t, CHAR_T *, size_t, CHAR_T *, size_t, seq_t, int)); */ int -seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags) - SCR *sp; - CHAR_T *name, *input, *output; - size_t nlen, ilen, olen; - seq_t stype; - int flags; +seq_set( + SCR *sp, + CHAR_T *name, + size_t nlen, + CHAR_T *input, + size_t ilen, + CHAR_T *output, + size_t olen, + seq_t stype, + int flags) { CHAR_T *p; SEQ *lastqp, *qp; @@ -59,7 +64,7 @@ seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags) if (output == NULL || olen == 0) { p = NULL; olen = 0; - } else if ((p = v_strdup(sp, output, olen)) == NULL) { + } else if ((p = v_wstrdup(sp, output, olen)) == NULL) { sv_errno = errno; goto mem1; } @@ -80,14 +85,14 @@ seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags) /* Name. */ if (name == NULL || nlen == 0) qp->name = NULL; - else if ((qp->name = v_strdup(sp, name, nlen)) == NULL) { + else if ((qp->name = v_wstrdup(sp, name, nlen)) == NULL) { sv_errno = errno; goto mem2; } qp->nlen = nlen; /* Input. */ - if ((qp->input = v_strdup(sp, input, ilen)) == NULL) { + if ((qp->input = v_wstrdup(sp, input, ilen)) == NULL) { sv_errno = errno; goto mem3; } @@ -97,7 +102,7 @@ seq_set(sp, name, nlen, input, ilen, output, olen, stype, flags) if (output == NULL) { qp->output = NULL; olen = 0; - } else if ((qp->output = v_strdup(sp, output, olen)) == NULL) { + } else if ((qp->output = v_wstrdup(sp, output, olen)) == NULL) { sv_errno = errno; free(qp->input); mem3: if (qp->name != NULL) @@ -115,13 +120,13 @@ mem1: errno = sv_errno; /* Link into the chain. */ if (lastqp == NULL) { - LIST_INSERT_HEAD(&sp->gp->seqq, qp, q); + SLIST_INSERT_HEAD(sp->gp->seqq, qp, q); } else { - LIST_INSERT_AFTER(lastqp, qp, q); + SLIST_INSERT_AFTER(lastqp, qp, q); } /* Set the fast lookup bit. */ - if (qp->input[0] < MAX_BIT_SEQ) + if ((qp->input[0] & ~MAX_BIT_SEQ) == 0) bit_set(sp->gp->seqb, qp->input[0]); return (0); @@ -134,33 +139,48 @@ mem1: errno = sv_errno; * PUBLIC: int seq_delete __P((SCR *, CHAR_T *, size_t, seq_t)); */ int -seq_delete(sp, input, ilen, stype) - SCR *sp; - CHAR_T *input; - size_t ilen; - seq_t stype; +seq_delete( + SCR *sp, + CHAR_T *input, + size_t ilen, + seq_t stype) { - SEQ *qp; + SEQ *qp, *pre_qp = NULL; + int diff; - if ((qp = seq_find(sp, NULL, NULL, input, ilen, stype, NULL)) == NULL) - return (1); - return (seq_mdel(qp)); + SLIST_FOREACH(qp, sp->gp->seqq, q) { + if (qp->stype == stype && qp->ilen == ilen) { + diff = MEMCMP(qp->input, input, ilen); + if (!diff) { + if (F_ISSET(qp, SEQ_FUNCMAP)) + break; + if (qp == SLIST_FIRST(sp->gp->seqq)) + SLIST_REMOVE_HEAD(sp->gp->seqq, q); + else + SLIST_REMOVE_AFTER(pre_qp, q); + return (seq_free(qp)); + } + if (diff > 0) + break; + } + pre_qp = qp; + } + return (1); } /* - * seq_mdel -- - * Delete a map entry, without lookup. + * seq_free -- + * Free a map entry. * - * PUBLIC: int seq_mdel __P((SEQ *)); + * PUBLIC: int seq_free __P((SEQ *)); */ int -seq_mdel(qp) - SEQ *qp; +seq_free(SEQ *qp) { - LIST_REMOVE(qp, q); if (qp->name != NULL) free(qp->name); - free(qp->input); + if (qp->input != NULL) + free(qp->input); if (qp->output != NULL) free(qp->output); free(qp); @@ -176,16 +196,16 @@ seq_mdel(qp) * PUBLIC: __P((SCR *, SEQ **, EVENT *, CHAR_T *, size_t, seq_t, int *)); */ SEQ * -seq_find(sp, lastqp, e_input, c_input, ilen, stype, ispartialp) - SCR *sp; - SEQ **lastqp; - EVENT *e_input; - CHAR_T *c_input; - size_t ilen; - seq_t stype; - int *ispartialp; +seq_find( + SCR *sp, + SEQ **lastqp, + EVENT *e_input, + CHAR_T *c_input, + size_t ilen, + seq_t stype, + int *ispartialp) { - SEQ *lqp, *qp; + SEQ *lqp = NULL, *qp; int diff; /* @@ -200,8 +220,8 @@ seq_find(sp, lastqp, e_input, c_input, ilen, stype, ispartialp) */ if (ispartialp != NULL) *ispartialp = 0; - for (lqp = NULL, qp = sp->gp->seqq.lh_first; - qp != NULL; lqp = qp, qp = qp->q.le_next) { + for (qp = SLIST_FIRST(sp->gp->seqq); qp != NULL; + lqp = qp, qp = SLIST_NEXT(qp, q)) { /* * Fast checks on the first character and type, and then * a real comparison. @@ -212,7 +232,7 @@ seq_find(sp, lastqp, e_input, c_input, ilen, stype, ispartialp) if (qp->input[0] < c_input[0] || qp->stype != stype || F_ISSET(qp, SEQ_FUNCMAP)) continue; - diff = memcmp(qp->input, c_input, MIN(qp->ilen, ilen)); + diff = MEMCMP(qp->input, c_input, MIN(qp->ilen, ilen)); } else { if (qp->input[0] > e_input->e_c) break; @@ -261,20 +281,13 @@ seq_find(sp, lastqp, e_input, c_input, ilen, stype, ispartialp) * PUBLIC: void seq_close __P((GS *)); */ void -seq_close(gp) - GS *gp; +seq_close(GS *gp) { SEQ *qp; - while ((qp = gp->seqq.lh_first) != NULL) { - if (qp->name != NULL) - free(qp->name); - if (qp->input != NULL) - free(qp->input); - if (qp->output != NULL) - free(qp->output); - LIST_REMOVE(qp, q); - free(qp); + while ((qp = SLIST_FIRST(gp->seqq)) != NULL) { + SLIST_REMOVE_HEAD(gp->seqq, q); + (void)seq_free(qp); } } @@ -285,10 +298,10 @@ seq_close(gp) * PUBLIC: int seq_dump __P((SCR *, seq_t, int)); */ int -seq_dump(sp, stype, isname) - SCR *sp; - seq_t stype; - int isname; +seq_dump( + SCR *sp, + seq_t stype, + int isname) { CHAR_T *p; GS *gp; @@ -297,7 +310,7 @@ seq_dump(sp, stype, isname) cnt = 0; gp = sp->gp; - for (qp = gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) { + SLIST_FOREACH(qp, sp->gp->seqq, q) { if (stype != qp->stype || F_ISSET(qp, SEQ_FUNCMAP)) continue; ++cnt; @@ -333,11 +346,11 @@ seq_dump(sp, stype, isname) * PUBLIC: int seq_save __P((SCR *, FILE *, char *, seq_t)); */ int -seq_save(sp, fp, prefix, stype) - SCR *sp; - FILE *fp; - char *prefix; - seq_t stype; +seq_save( + SCR *sp, + FILE *fp, + char *prefix, + seq_t stype) { CHAR_T *p; SEQ *qp; @@ -345,7 +358,7 @@ seq_save(sp, fp, prefix, stype) int ch; /* Write a sequence command for all keys the user defined. */ - for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) { + SLIST_FOREACH(qp, sp->gp->seqq, q) { if (stype != qp->stype || !F_ISSET(qp, SEQ_USERDEF)) continue; if (prefix) @@ -353,7 +366,7 @@ seq_save(sp, fp, prefix, stype) for (p = qp->input, olen = qp->ilen; olen > 0; --olen) { ch = *p++; if (ch == CH_LITERAL || ch == '|' || - isblank(ch) || KEY_VAL(sp, ch) == K_NL) + cmdskip(ch) || KEY_VAL(sp, ch) == K_NL) (void)putc(CH_LITERAL, fp); (void)putc(ch, fp); } @@ -379,10 +392,10 @@ seq_save(sp, fp, prefix, stype) * PUBLIC: int e_memcmp __P((CHAR_T *, EVENT *, size_t)); */ int -e_memcmp(p1, ep, n) - CHAR_T *p1; - EVENT *ep; - size_t n; +e_memcmp( + CHAR_T *p1, + EVENT *ep, + size_t n) { if (n != 0) { do { diff --git a/contrib/nvi/common/seq.h b/contrib/nvi/common/seq.h index 984bb6c..2c5ae57 100644 --- a/contrib/nvi/common/seq.h +++ b/contrib/nvi/common/seq.h @@ -6,13 +6,13 @@ * * See the LICENSE file for redistribution information. * - * @(#)seq.h 10.3 (Berkeley) 3/6/96 + * $Id: seq.h,v 10.4 2011/12/11 21:43:39 zy Exp $ */ /* * Map and abbreviation structures. * - * The map structure is doubly linked list, sorted by input string and by + * The map structure is singly linked list, sorted by input string and by * input length within the string. (The latter is necessary so that short * matches will happen before long matches when the list is searched.) * Additionally, there is a bitmap which has bits set if there are entries @@ -27,7 +27,7 @@ * things, though, so it's probably not a big deal. */ struct _seq { - LIST_ENTRY(_seq) q; /* Linked list of all sequences. */ + SLIST_ENTRY(_seq) q; /* Linked list of all sequences. */ seq_t stype; /* Sequence type. */ CHAR_T *name; /* Sequence name (if any). */ size_t nlen; /* Name length. */ diff --git a/contrib/nvi/common/util.c b/contrib/nvi/common/util.c index 5a4422a..43fa9d1 100644 --- a/contrib/nvi/common/util.c +++ b/contrib/nvi/common/util.c @@ -10,18 +10,27 @@ #include "config.h" #ifndef lint -static const char sccsid[] = "@(#)util.c 10.11 (Berkeley) 9/15/96"; +static const char sccsid[] = "$Id: util.c,v 10.30 2013/03/19 10:00:27 yamt Exp $"; #endif /* not lint */ #include <sys/types.h> #include <sys/queue.h> +#ifdef __APPLE__ +#include <mach/clock.h> +#include <mach/mach.h> +#include <mach/mach_time.h> +#endif + #include <bitstring.h> +#include <ctype.h> #include <errno.h> #include <limits.h> +#include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include "common.h" @@ -33,10 +42,11 @@ static const char sccsid[] = "@(#)util.c 10.11 (Berkeley) 9/15/96"; * PUBLIC: void *binc __P((SCR *, void *, size_t *, size_t)); */ void * -binc(sp, bp, bsizep, min) - SCR *sp; /* sp MAY BE NULL!!! */ - void *bp; - size_t *bsizep, min; +binc( + SCR *sp, /* sp MAY BE NULL!!! */ + void *bp, + size_t *bsizep, + size_t min) { size_t csize; @@ -44,14 +54,10 @@ binc(sp, bp, bsizep, min) if (min && *bsizep >= min) return (bp); - csize = *bsizep + MAX(min, 256); + csize = p2roundup(MAX(min, 256)); REALLOC(sp, bp, void *, csize); if (bp == NULL) { - /* - * Theoretically, realloc is supposed to leave any already - * held memory alone if it can't get more. Don't trust it. - */ *bsizep = 0; return (NULL); } @@ -73,12 +79,12 @@ binc(sp, bp, bsizep, min) * PUBLIC: int nonblank __P((SCR *, recno_t, size_t *)); */ int -nonblank(sp, lno, cnop) - SCR *sp; - recno_t lno; - size_t *cnop; +nonblank( + SCR *sp, + recno_t lno, + size_t *cnop) { - char *p; + CHAR_T *p; size_t cnt, len, off; int isempty; @@ -95,7 +101,7 @@ nonblank(sp, lno, cnop) return (0); for (cnt = off, p = &p[off], - len -= off; len && isblank(*p); ++cnt, ++p, --len); + len -= off; len && ISBLANK(*p); ++cnt, ++p, --len); /* Set the return. */ *cnop = len ? cnt : cnt - 1; @@ -109,8 +115,7 @@ nonblank(sp, lno, cnop) * PUBLIC: char *tail __P((char *)); */ char * -tail(path) - char *path; +tail(char *path) { char *p; @@ -120,23 +125,161 @@ tail(path) } /* + * join -- + * Join two paths; need free. + * + * PUBLIC: char *join __P((char *, char *)); + */ +char * +join( + char *path1, + char *path2) +{ + char *p; + + if (path1[0] == '\0' || path2[0] == '/') + return strdup(path2); + (void)asprintf(&p, path1[strlen(path1)-1] == '/' ? + "%s%s" : "%s/%s", path1, path2); + return p; +} + +/* + * expanduser -- + * Return a "~" or "~user" expanded path; need free. + * + * PUBLIC: char *expanduser __P((char *)); + */ +char * +expanduser(char *str) +{ + struct passwd *pwd; + char *p, *t, *u, *h; + + /* + * This function always expands the content between the + * leading '~' and the first '/' or '\0' from the input. + * Return NULL whenever we fail to do so. + */ + if (*str != '~') + return (NULL); + p = str + 1; + for (t = p; *t != '/' && *t != '\0'; ++t) + continue; + if (t == p) { + /* ~ */ + if (issetugid() != 0 || + (h = getenv("HOME")) == NULL) { + if (((h = getlogin()) != NULL && + (pwd = getpwnam(h)) != NULL) || + (pwd = getpwuid(getuid())) != NULL) + h = pwd->pw_dir; + else + return (NULL); + } + } else { + /* ~user */ + if ((u = strndup(p, t - p)) == NULL) + return (NULL); + if ((pwd = getpwnam(u)) == NULL) { + free(u); + return (NULL); + } else + h = pwd->pw_dir; + free(u); + } + + for (; *t == '/' && *t != '\0'; ++t) + continue; + return (join(h, t)); +} + +/* + * quote -- + * Return a escaped string for /bin/sh; need free. + * + * PUBLIC: char *quote __P((char *)); + */ +char * +quote(char *str) +{ + char *p, *t; + size_t i = 0, n = 0; + int unsafe = 0; + + for (p = str; *p != '\0'; p++, i++) { + if (*p == '\'') + n++; + if (unsafe) + continue; + if (isascii(*p)) { + if (isalnum(*p)) + continue; + switch (*p) { + case '%': case '+': case ',': case '-': case '.': + case '/': case ':': case '=': case '@': case '_': + continue; + } + } + unsafe = 1; + } + if (!unsafe) + t = strdup(str); +#define SQT "'\\''" + else if ((p = t = malloc(i + n * (sizeof(SQT) - 2) + 3)) != NULL) { + *p++ = '\''; + for (; *str != '\0'; str++) { + if (*str == '\'') { + (void)memcpy(p, SQT, sizeof(SQT) - 1); + p += sizeof(SQT) - 1; + } else + *p++ = *str; + } + *p++ = '\''; + *p = '\0'; + } + return t; +} + +/* * v_strdup -- + * Strdup for 8-bit character strings with an associated length. + * + * PUBLIC: char *v_strdup __P((SCR *, const char *, size_t)); + */ +char * +v_strdup( + SCR *sp, + const char *str, + size_t len) +{ + char *copy; + + MALLOC(sp, copy, char *, len + 1); + if (copy == NULL) + return (NULL); + memcpy(copy, str, len); + copy[len] = '\0'; + return (copy); +} + +/* + * v_wstrdup -- * Strdup for wide character strings with an associated length. * - * PUBLIC: CHAR_T *v_strdup __P((SCR *, const CHAR_T *, size_t)); + * PUBLIC: CHAR_T *v_wstrdup __P((SCR *, const CHAR_T *, size_t)); */ CHAR_T * -v_strdup(sp, str, len) - SCR *sp; - const CHAR_T *str; - size_t len; +v_wstrdup(SCR *sp, + const CHAR_T *str, + size_t len) { CHAR_T *copy; - MALLOC(sp, copy, CHAR_T *, len + 1); + MALLOC(sp, copy, CHAR_T *, (len + 1) * sizeof(CHAR_T)); if (copy == NULL) return (NULL); - memcpy(copy, str, len * sizeof(CHAR_T)); + MEMCPY(copy, str, len); copy[len] = '\0'; return (copy); } @@ -145,17 +288,17 @@ v_strdup(sp, str, len) * nget_uslong -- * Get an unsigned long, checking for overflow. * - * PUBLIC: enum nresult nget_uslong __P((u_long *, const char *, char **, int)); + * PUBLIC: enum nresult nget_uslong __P((u_long *, const CHAR_T *, CHAR_T **, int)); */ enum nresult -nget_uslong(valp, p, endp, base) - u_long *valp; - const char *p; - char **endp; - int base; +nget_uslong( + u_long *valp, + const CHAR_T *p, + CHAR_T **endp, + int base) { errno = 0; - *valp = strtoul(p, endp, base); + *valp = STRTOUL(p, endp, base); if (errno == 0) return (NUM_OK); if (errno == ERANGE && *valp == ULONG_MAX) @@ -167,17 +310,17 @@ nget_uslong(valp, p, endp, base) * nget_slong -- * Convert a signed long, checking for overflow and underflow. * - * PUBLIC: enum nresult nget_slong __P((long *, const char *, char **, int)); + * PUBLIC: enum nresult nget_slong __P((long *, const CHAR_T *, CHAR_T **, int)); */ enum nresult -nget_slong(valp, p, endp, base) - long *valp; - const char *p; - char **endp; - int base; +nget_slong( + long *valp, + const CHAR_T *p, + CHAR_T **endp, + int base) { errno = 0; - *valp = strtol(p, endp, base); + *valp = STRTOL(p, endp, base); if (errno == 0) return (NUM_OK); if (errno == ERANGE) { @@ -189,12 +332,70 @@ nget_slong(valp, p, endp, base) return (NUM_ERR); } -#ifdef DEBUG -#ifdef __STDC__ -#include <stdarg.h> +/* + * timepoint_steady -- + * Get a timestamp from a monotonic clock. + * + * PUBLIC: void timepoint_steady __P((struct timespec *)); + */ +void +timepoint_steady( + struct timespec *ts) +{ +#ifdef __APPLE__ + static mach_timebase_info_data_t base = { 0 }; + uint64_t val; + uint64_t ns; + + if (base.denom == 0) + (void)mach_timebase_info(&base); + + val = mach_absolute_time(); + ns = val * base.numer / base.denom; + ts->tv_sec = ns / 1000000000; + ts->tv_nsec = ns % 1000000000; +#else +#ifdef CLOCK_MONOTONIC_FAST + (void)clock_gettime(CLOCK_MONOTONIC_FAST, ts); #else -#include <varargs.h> + (void)clock_gettime(CLOCK_MONOTONIC, ts); +#endif #endif +} + +/* + * timepoint_system -- + * Get the current calendar time. + * + * PUBLIC: void timepoint_system __P((struct timespec *)); + */ +void +timepoint_system( + struct timespec *ts) +{ +#ifdef __APPLE__ + clock_serv_t clk; + mach_timespec_t mts; + kern_return_t kr; + + kr = host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clk); + if (kr != KERN_SUCCESS) + return; + (void)clock_get_time(clk, &mts); + (void)mach_port_deallocate(mach_task_self(), clk); + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; +#else +#ifdef CLOCK_REALTIME_FAST + (void)clock_gettime(CLOCK_REALTIME_FAST, ts); +#else + (void)clock_gettime(CLOCK_REALTIME, ts); +#endif +#endif +} + +#ifdef DEBUG +#include <stdarg.h> /* * TRACE -- @@ -203,25 +404,17 @@ nget_slong(valp, p, endp, base) * PUBLIC: void TRACE __P((SCR *, const char *, ...)); */ void -#ifdef __STDC__ -TRACE(SCR *sp, const char *fmt, ...) -#else -TRACE(sp, fmt, va_alist) - SCR *sp; - char *fmt; - va_dcl -#endif +TRACE( + SCR *sp, + const char *fmt, + ...) { FILE *tfp; va_list ap; if ((tfp = sp->gp->tracefp) == NULL) return; -#ifdef __STDC__ va_start(ap, fmt); -#else - va_start(ap); -#endif (void)vfprintf(tfp, fmt, ap); va_end(ap); diff --git a/contrib/nvi/common/util.h b/contrib/nvi/common/util.h index 46edb4a..e6b2bec 100644 --- a/contrib/nvi/common/util.h +++ b/contrib/nvi/common/util.h @@ -6,7 +6,7 @@ * * See the LICENSE file for redistribution information. * - * @(#)util.h 10.5 (Berkeley) 3/16/96 + * $Id: util.h,v 10.7 2013/02/24 21:00:10 zy Exp $ */ /* Macros to init/set/clear/test flags. */ @@ -54,3 +54,40 @@ enum nresult { NUM_ERR, NUM_OK, NUM_OVER, NUM_UNDER }; NUM_OK) #define NADD_USLONG(sp, v1, v2) \ (NPFITS(ULONG_MAX, (v1), (v2)) ? NUM_OK : NUM_OVER) + +/* Macros for min/max. */ +#undef MIN +#undef MAX +#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +#define MAX(_a,_b) ((_a)<(_b)?(_b):(_a)) + +/* Operations on timespecs */ +#undef timespecclear +#undef timespecisset +#undef timespeccmp +#undef timespecadd +#undef timespecsub +#define timespecclear(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0) +#define timespecisset(tvp) ((tvp)->tv_sec || (tvp)->tv_nsec) +#define timespeccmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#define timespecadd(vvp, uvp) \ + do { \ + (vvp)->tv_sec += (uvp)->tv_sec; \ + (vvp)->tv_nsec += (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec >= 1000000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_nsec -= 1000000000; \ + } \ + } while (0) +#define timespecsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_nsec -= (uvp)->tv_nsec; \ + if ((vvp)->tv_nsec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_nsec += 1000000000; \ + } \ + } while (0) |