aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2013-08-11 09:44:58 +0000
committerPeter Wemm <peter@FreeBSD.org>2013-08-11 09:44:58 +0000
commitbe3e4646eef6a3abcf58590dac24a5dfe54540f6 (patch)
tree5a0e2514f154d0eb24f2235092423adb95ac75ac /common
parent84ed61ee234d2654ec965be5bfdda4269f9dc4fd (diff)
downloadsrc-be3e4646eef6a3abcf58590dac24a5dfe54540f6.tar.gz
src-be3e4646eef6a3abcf58590dac24a5dfe54540f6.zip
Import nvi-2.1.1-4334a8297f into the work area. This is the gsoc-2011vendor/nvi/2.1.1-4334a8297f
project to clean up and backport multibyte support from other nvi forks in a form we can use. 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>
Notes
Notes: svn path=/vendor/nvi/dist/; revision=254211 svn path=/vendor/nvi/2.1.1-4334a8297f/; revision=254212; tag=vendor/nvi/2.1.1-4334a8297f
Diffstat (limited to 'common')
-rw-r--r--common/api.c525
-rw-r--r--common/args.h2
-rw-r--r--common/common.h15
-rw-r--r--common/conv.c446
-rw-r--r--common/conv.h57
-rw-r--r--common/cut.c143
-rw-r--r--common/cut.h18
-rw-r--r--common/delete.c39
-rw-r--r--common/encoding.c230
-rw-r--r--common/exf.c431
-rw-r--r--common/exf.h20
-rw-r--r--common/extern.h132
-rw-r--r--common/gs.h62
-rw-r--r--common/key.c257
-rw-r--r--common/key.h66
-rw-r--r--common/line.c278
-rw-r--r--common/log.c174
-rw-r--r--common/main.c98
-rw-r--r--common/mark.c74
-rw-r--r--common/mark.h5
-rw-r--r--common/mem.h130
-rw-r--r--common/msg.c295
-rw-r--r--common/msg.h4
-rw-r--r--common/multibyte.h115
-rw-r--r--common/options.c595
-rw-r--r--common/options.h5
-rw-r--r--common/options_def.h83
-rw-r--r--common/options_f.c212
-rw-r--r--common/put.c54
-rw-r--r--common/recover.c590
-rw-r--r--common/screen.c57
-rw-r--r--common/screen.h30
-rw-r--r--common/search.c72
-rw-r--r--common/seq.c151
-rw-r--r--common/seq.h6
-rw-r--r--common/util.c303
-rw-r--r--common/util.h39
37 files changed, 3514 insertions, 2299 deletions
diff --git a/common/api.c b/common/api.c
deleted file mode 100644
index 35d9f0c8f66e..000000000000
--- a/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/common/args.h b/common/args.h
index e84dc2ca04c1..b23699c250e3 100644
--- a/common/args.h
+++ b/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/common/common.h b/common/common.h
index 0e13fc80b844..71f4c7fb69cb 100644
--- a/common/common.h
+++ b/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/common/conv.c b/common/conv.c
new file mode 100644
index 000000000000..7803cec9922e
--- /dev/null
+++ b/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/common/conv.h b/common/conv.h
new file mode 100644
index 000000000000..b17c3bb24ace
--- /dev/null
+++ b/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/common/cut.c b/common/cut.c
index faceecd11166..11db42fb8158 100644
--- a/common/cut.c
+++ b/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/common/cut.h b/common/cut.h
index 43f3ca817efd..30e9350dbb75 100644
--- a/common/cut.h
+++ b/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/common/delete.c b/common/delete.c
index 001788f9bb38..bb476c0c8a7c 100644
--- a/common/delete.c
+++ b/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/common/encoding.c b/common/encoding.c
new file mode 100644
index 000000000000..6de509e5b8ec
--- /dev/null
+++ b/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/common/exf.c b/common/exf.c
index 2993b0f4a8a5..6579ab2118d3 100644
--- a/common/exf.c
+++ b/common/exf.c
@@ -10,13 +10,13 @@
#include "config.h"
#ifndef lint
-static const char sccsid[] = "@(#)exf.c 10.49 (Berkeley) 10/10/96";
+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
@@ -39,6 +39,7 @@ static const char sccsid[] = "@(#)exf.c 10.49 (Berkeley) 10/10/96";
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 *));
@@ -55,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;
@@ -76,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))
@@ -109,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);
}
@@ -123,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;
@@ -164,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);
/*
@@ -182,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_DIRECTORY, 0))
+ struct stat sb;
+
+ if (opts_empty(sp, O_TMPDIR, 0))
goto err;
- (void)snprintf(tname, sizeof(tname),
- "%s/vi.XXXXXX", O_STR(sp, O_DIRECTORY));
- if ((fd = mkstemp(tname)) == -1) {
+ if ((tname =
+ join(O_STR(sp, O_TMPDIR), "vi.XXXXXXXXXX")) == NULL) {
+ msgq(sp, M_SYSERR, NULL);
+ goto err;
+ }
+ 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,
@@ -235,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;
@@ -333,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;
@@ -391,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);
@@ -403,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);
@@ -441,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
@@ -461,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);
}
@@ -476,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')
@@ -494,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);
@@ -508,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;
@@ -548,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)) {
@@ -617,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;
@@ -665,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);
@@ -707,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);
@@ -729,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;
@@ -744,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;
@@ -807,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");
@@ -832,32 +844,46 @@ file_write(sp, fm, tm, name, flags)
SIGBLOCK;
if ((fd = open(name, oflags,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0) {
+ if (errno == EACCES && LF_ISSET(FS_FORCE)) {
+ /*
+ * If the user owns the file but does not
+ * have write permission on it, grant it
+ * automatically for the duration of the
+ * opening of the file, if possible.
+ */
+ struct stat sb;
+ mode_t fmode;
+
+ if (stat(name, &sb) != 0)
+ goto fail_open;
+ fmode = sb.st_mode;
+ if (!(sb.st_mode & S_IWUSR) && sb.st_uid == getuid())
+ fmode |= S_IWUSR;
+ else
+ goto fail_open;
+ if (chmod(name, fmode) != 0)
+ goto fail_open;
+ fd = open(name, oflags, S_IRUSR | S_IWUSR |
+ S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ if (fd == -1)
+ goto fail_open;
+ (void)fchmod(fd, sb.st_mode);
+ goto success_open;
+ fail_open:
+ errno = EACCES;
+ }
msgq_str(sp, M_SYSERR, name, "%s");
SIGUNBLOCK;
return (1);
}
+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.
*
@@ -891,13 +917,13 @@ file_write(sp, fm, tm, name, flags)
*/
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;
}
/*
@@ -970,7 +996,7 @@ file_write(sp, fm, tm, name, flags)
*--s = '.';
}
}
- msgq(sp, M_INFO, s);
+ msgq(sp, M_INFO, "%s", s);
if (nf)
FREE_SPACE(sp, p, 0);
return (0);
@@ -989,9 +1015,10 @@ file_write(sp, fm, tm, name, flags)
* 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;
@@ -1001,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;
@@ -1030,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.
@@ -1061,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++ = '%';
@@ -1084,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;
}
@@ -1098,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. */
@@ -1158,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)
@@ -1216,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;
@@ -1256,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;
@@ -1288,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;
@@ -1324,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);
@@ -1385,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);
@@ -1401,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
@@ -1438,61 +1511,13 @@ file_lock(sp, name, fdp, fd, iswrite)
* they are the former. There's no portable way to do this.
*/
errno = 0;
- return (flock(fd, LOCK_EX | LOCK_NB) ? errno == EAGAIN
-#ifdef EWOULDBLOCK
- || errno == EWOULDBLOCK
-#endif
- ? LOCK_UNAVAIL : LOCK_FAILED : LOCK_SUCCESS);
-#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))
+ if (!flock(fd, LOCK_EX | LOCK_NB)) {
+ 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
+ return (errno == EAGAIN
#ifdef EWOULDBLOCK
- || errno == EWOULDBLOCK
-#endif
- ? LOCK_UNAVAIL : LOCK_FAILED);
-}
-#endif
-#if !defined(HAVE_LOCK_FLOCK) && !defined(HAVE_LOCK_FCNTL)
- return (LOCK_SUCCESS);
+ || errno == EWOULDBLOCK
#endif
+ ? LOCK_UNAVAIL : LOCK_FAILED);
}
diff --git a/common/exf.h b/common/exf.h
index cdfaa8294485..8f70d51dbb61 100644
--- a/common/exf.h
+++ b/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/common/extern.h b/common/extern.h
new file mode 100644
index 000000000000..20672e380b14
--- /dev/null
+++ b/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/common/gs.h b/common/gs.h
index e5a43a656ac2..33a02458b0f9 100644
--- a/common/gs.h
+++ b/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/common/key.c b/common/key.c
index e1311ab571b0..652b8f3eae00 100644
--- a/common/key.c
+++ b/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/common/key.h b/common/key.h
index 76fb64f8e1ec..3eeca124a00a 100644
--- a/common/key.h
+++ b/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/common/line.c b/common/line.c
index bcb9e0c86bcb..0bceccfa5bcc 100644
--- a/common/line.c
+++ b/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/common/log.c b/common/log.c
index 9a9fe793ffb8..eb8d85bc84cf 100644
--- a/common/log.c
+++ b/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/common/main.c b/common/main.c
index 6fb2ed1fe2f0..16b3fb19e22d 100644
--- a/common/main.c
+++ b/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;
@@ -65,6 +64,8 @@ editor(gp, argc, argv)
u_int flags;
int ch, flagchk, lflag, secure, startup, readonly, rval, silent;
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)
@@ -72,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;
@@ -236,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;
@@ -331,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
@@ -342,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);
@@ -366,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);
@@ -400,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);
}
@@ -447,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)
@@ -480,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);
@@ -496,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);
@@ -524,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;
@@ -546,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') &&
@@ -578,8 +576,7 @@ nomem: v_estr(name, errno, NULL);
#ifdef DEBUG
static void
-attach(gp)
- GS *gp;
+attach(GS *gp)
{
int fd;
char ch;
@@ -604,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/common/mark.c b/common/mark.c
index 0ac1fc28bf9c..7a954392278c 100644
--- a/common/mark.c
+++ b/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/common/mark.h b/common/mark.h
index 9c63e183e83f..44b8a19938ca 100644
--- a/common/mark.h
+++ b/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/common/mem.h b/common/mem.h
index af42e6bcd1de..b2b44b62ec8e 100644
--- a/common/mem.h
+++ b/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/common/msg.c b/common/msg.c
index 2b18082c7ab8..c0930b88afcd 100644
--- a/common/msg.c
+++ b/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) {
@@ -472,7 +496,8 @@ mod_rpt(sp)
*p++ = ' ';
tlen += 2;
}
- len = snprintf(p, MAXNUM, "%lu ", sp->rptlines[cnt]);
+ len = snprintf(p, MAXNUM, "%lu ",
+ (u_long)sp->rptlines[cnt]);
p += len;
tlen += len;
t = msg_cat(sp,
@@ -511,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;
@@ -542,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,16 +647,17 @@ msgq_status(sp, lno, flags)
p += len;
} else {
t = msg_cat(sp, "027|line %lu of %lu [%ld%%]", &len);
- (void)sprintf(p, t, lno, last, (lno * 100) / last);
+ (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, 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';
@@ -677,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)
{
/*
* !!!
@@ -691,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);
}
/*
@@ -748,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);
}
/*
@@ -762,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:
@@ -800,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
@@ -815,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);
@@ -850,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. */
@@ -873,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/common/msg.h b/common/msg.h
index b10f4ccae5c6..d65bb1aaf542 100644
--- a/common/msg.h
+++ b/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/common/multibyte.h b/common/multibyte.h
new file mode 100644
index 000000000000..40e352100ec3
--- /dev/null
+++ b/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/common/options.c b/common/options.c
index 973778c78bbd..71a5e43e58cb 100644
--- a/common/options.c
+++ b/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,73 +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_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},
+ {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"
@@ -120,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
@@ -183,95 +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_DIRECTORY}, /* 4BSD */
- {"eb", O_ERRORBELLS}, /* 4BSD */
- {"ed", O_EDCOMPATIBLE}, /* 4BSD */
- {"ex", O_EXRC}, /* System V (undocumented) */
- {"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},
};
@@ -282,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;
@@ -300,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; \
@@ -327,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"));
/*
* !!!
@@ -338,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_DIRECTORY, b1);
- OI(O_ESCAPETIME, "escapetime=1");
- 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
@@ -370,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:
@@ -388,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;
@@ -416,6 +438,7 @@ opts_init(sp, oargs)
default:
abort();
}
+ }
/*
* !!!
@@ -425,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);
}
@@ -440,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) {
@@ -459,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;
}
@@ -521,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;
@@ -529,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;
@@ -552,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;
@@ -591,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;
@@ -647,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;
}
@@ -662,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;
@@ -674,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:
@@ -713,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;
@@ -757,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);
}
@@ -779,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;
@@ -836,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;
}
@@ -852,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:
@@ -913,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;
@@ -925,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;
}
@@ -945,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))
@@ -961,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;
@@ -999,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;
@@ -1026,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;
@@ -1045,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));
}
/*
@@ -1077,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;
@@ -1088,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 --
@@ -1124,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/common/options.h b/common/options.h
index 2646dc301b5a..fe1f80f5f16d 100644
--- a/common/options.h
+++ b/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/common/options_def.h b/common/options_def.h
new file mode 100644
index 000000000000..8e232786cfe6
--- /dev/null
+++ b/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/common/options_f.c b/common/options_f.c
index ea3c61160cf5..482a37e39d39 100644
--- a/common/options_f.c
+++ b/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/common/put.c b/common/put.c
index 8c0ca4b7c14f..6e9dc09902de 100644
--- a/common/put.c
+++ b/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/common/recover.c b/common/recover.c
index f3abaab5a536..b20471f111b2 100644
--- a/common/recover.c
+++ b/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/common/screen.c b/common/screen.c
index ba9e287b648b..9ff684509d94 100644
--- a/common/screen.c
+++ b/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/common/screen.h b/common/screen.h
index bb7254f62a21..a762706834dd 100644
--- a/common/screen.h
+++ b/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/common/search.c b/common/search.c
index 3fd2719778fa..22f020315070 100644
--- a/common/search.c
+++ b/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/common/seq.c b/common/seq.c
index e2be879ab686..45c6c1111083 100644
--- a/common/seq.c
+++ b/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/common/seq.h b/common/seq.h
index 984bb6c0bd18..2c5ae576e3ee 100644
--- a/common/seq.h
+++ b/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/common/util.c b/common/util.c
index 5a4422a2c422..43fa9d1e9f20 100644
--- a/common/util.c
+++ b/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/common/util.h b/common/util.h
index 46edb4aae5a8..e6b2bec94e15 100644
--- a/common/util.h
+++ b/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)