Module Name: src
Committed By: christos
Date: Sun Jan 3 18:27:10 UTC 2010
Modified Files:
src/lib/libedit: chartype.h editline.3 histedit.h history.c readline.c
tokenizer.c
src/lib/libedit/TEST: Makefile
Added Files:
src/lib/libedit/TEST: wtc1.c
Log Message:
rename historyw -> history_w for consistency.
add wide tst code and make it the default.
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/lib/libedit/chartype.h
cvs rdiff -u -r1.71 -r1.72 src/lib/libedit/editline.3
cvs rdiff -u -r1.44 -r1.45 src/lib/libedit/histedit.h
cvs rdiff -u -r1.36 -r1.37 src/lib/libedit/history.c
cvs rdiff -u -r1.87 -r1.88 src/lib/libedit/readline.c
cvs rdiff -u -r1.17 -r1.18 src/lib/libedit/tokenizer.c
cvs rdiff -u -r1.3 -r1.4 src/lib/libedit/TEST/Makefile
cvs rdiff -u -r0 -r1.1 src/lib/libedit/TEST/wtc1.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libedit/chartype.h
diff -u src/lib/libedit/chartype.h:1.3 src/lib/libedit/chartype.h:1.4
--- src/lib/libedit/chartype.h:1.3 Thu Dec 31 13:32:37 2009
+++ src/lib/libedit/chartype.h Sun Jan 3 13:27:10 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: chartype.h,v 1.3 2009/12/31 18:32:37 christos Exp $ */
+/* $NetBSD: chartype.h,v 1.4 2010/01/03 18:27:10 christos Exp $ */
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
#define Char wchar_t
#define Int wint_t
#define FUN(prefix,rest) prefix ## _w ## rest
-#define FUNW(type) type ## w
+#define FUNW(type) type ## _w
#define TYPE(type) type ## W
#define FSTR "%ls"
#define STR(x) L ## x
Index: src/lib/libedit/editline.3
diff -u src/lib/libedit/editline.3:1.71 src/lib/libedit/editline.3:1.72
--- src/lib/libedit/editline.3:1.71 Thu Dec 31 10:58:26 2009
+++ src/lib/libedit/editline.3 Sun Jan 3 13:27:10 2010
@@ -1,4 +1,4 @@
-.\" $NetBSD: editline.3,v 1.71 2009/12/31 15:58:26 christos Exp $
+.\" $NetBSD: editline.3,v 1.72 2010/01/03 18:27:10 christos Exp $
.\"
.\" Copyright (c) 1997-2003 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -59,7 +59,7 @@
.Nm history_end ,
.Nm history_wend ,
.Nm history ,
-.Nm historyw ,
+.Nm history_w ,
.Nm tok_init ,
.Nm tok_winit ,
.Nm tok_end ,
@@ -130,7 +130,7 @@
.Ft int
.Fn history "History *h" "HistEvent *ev" "int op" "..."
.Ft int
-.Fn historyw "HistoryW *h" "HistEventW *ev" "int op" "..."
+.Fn history_w "HistoryW *h" "HistEventW *ev" "int op" "..."
.Ft Tokenizer *
.Fn tok_init "const char *IFS"
.Ft TokenizerW *
Index: src/lib/libedit/histedit.h
diff -u src/lib/libedit/histedit.h:1.44 src/lib/libedit/histedit.h:1.45
--- src/lib/libedit/histedit.h:1.44 Thu Dec 31 10:58:26 2009
+++ src/lib/libedit/histedit.h Sun Jan 3 13:27:10 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: histedit.h,v 1.44 2009/12/31 15:58:26 christos Exp $ */
+/* $NetBSD: histedit.h,v 1.45 2010/01/03 18:27:10 christos Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -114,13 +114,16 @@
int el_get(EditLine *, int, ...);
unsigned char _el_fn_complete(EditLine *, int);
-
/*
* el_set/el_get parameters
*
- * When using el_wset/el_wget:
- * wchar_t is wchar_t, otherwise it is char.
- * prompt_func is el_wpfunc_t, otherise it is el_pfunc_t .
+ * When using el_wset/el_wget (as opposed to el_set/el_get):
+ * Char is wchar_t, otherwise it is char.
+ * prompt_func is el_wpfunc_t, otherwise it is el_pfunc_t .
+
+ * Prompt function prototypes are:
+ * typedef char *(*el_pfunct_t) (EditLine *);
+ * typedef wchar_t *(*el_wpfunct_t) (EditLine *);
*
* For operations that support set or set/get, the argument types listed are for
* the "set" operation. For "get", each listed type must be a pointer.
@@ -128,17 +131,17 @@
*
* Operations that only support "get" have the correct argument types listed.
*/
-#define EL_PROMPT 0 /* , promt_func); set/get */
+#define EL_PROMPT 0 /* , prompt_func); set/get */
#define EL_TERMINAL 1 /* , const char *); set/get */
-#define EL_EDITOR 2 /* , const wchar_t *); set/get */
+#define EL_EDITOR 2 /* , const Char *); set/get */
#define EL_SIGNAL 3 /* , int); set/get */
-#define EL_BIND 4 /* , const wchar_t *, ..., NULL); set */
-#define EL_TELLTC 5 /* , const wchar_t *, ..., NULL); set */
-#define EL_SETTC 6 /* , const wchar_t *, ..., NULL); set */
-#define EL_ECHOTC 7 /* , const wchar_t *, ..., NULL); set */
-#define EL_SETTY 8 /* , const wchar_t *, ..., NULL); set */
-#define EL_ADDFN 9 /* , const wchar_t *, const wchar_t * set */
- /* , el_func_t); */
+#define EL_BIND 4 /* , const Char *, ..., NULL); set */
+#define EL_TELLTC 5 /* , const Char *, ..., NULL); set */
+#define EL_SETTC 6 /* , const Char *, ..., NULL); set */
+#define EL_ECHOTC 7 /* , const Char *, ..., NULL); set */
+#define EL_SETTY 8 /* , const Char *, ..., NULL); set */
+#define EL_ADDFN 9 /* , const Char *, const Char, set */
+ /* el_func_t); */
#define EL_HIST 10 /* , hist_fun_t, const ptr_t); set */
#define EL_EDITMODE 11 /* , int); set/get */
#define EL_RPROMPT 12 /* , prompt_func); set/get */
@@ -146,12 +149,12 @@
#define EL_CLIENTDATA 14 /* , void *); set/get */
#define EL_UNBUFFERED 15 /* , int); set/get */
#define EL_PREP_TERM 16 /* , int); set */
-#define EL_GETTC 17 /* , const wchar_t *, ..., NULL); get */
+#define EL_GETTC 17 /* , const Char *, ..., NULL); get */
#define EL_GETFP 18 /* , int, FILE **); get */
#define EL_SETFP 19 /* , int, FILE *); set */
#define EL_REFRESH 20 /* , void); set */
-#define EL_PROMPT_ESC 21 /* , prompt_func, wchar_t); set/get */
-#define EL_RPROMPT_ESC 22 /* , prompt_func, wchar_t); set/get */
+#define EL_PROMPT_ESC 21 /* , prompt_func, Char); set/get */
+#define EL_RPROMPT_ESC 22 /* , prompt_func, Char); set/get */
#define EL_BUILTIN_GETCFN (NULL)
@@ -280,22 +283,22 @@
/*
* ==== History ====
*/
-typedef struct histeventw {
+typedef struct histeventW {
int num;
const wchar_t *str;
} HistEventW;
-typedef struct historyw HistoryW;
+typedef struct historyW HistoryW;
HistoryW * history_winit(void);
void history_wend(HistoryW *);
-int historyw(HistoryW *, HistEventW *, int, ...);
+int history_w(HistoryW *, HistEventW *, int, ...);
/*
* ==== Tokenization ====
*/
-typedef struct tokenizerw TokenizerW;
+typedef struct tokenizerW TokenizerW;
/* Wide character tokenizer support */
TokenizerW *tok_winit(const wchar_t *);
Index: src/lib/libedit/history.c
diff -u src/lib/libedit/history.c:1.36 src/lib/libedit/history.c:1.37
--- src/lib/libedit/history.c:1.36 Wed Dec 30 18:54:52 2009
+++ src/lib/libedit/history.c Sun Jan 3 13:27:10 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: history.c,v 1.36 2009/12/30 23:54:52 christos Exp $ */
+/* $NetBSD: history.c,v 1.37 2010/01/03 18:27:10 christos Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93";
#else
-__RCSID("$NetBSD: history.c,v 1.36 2009/12/30 23:54:52 christos Exp $");
+__RCSID("$NetBSD: history.c,v 1.37 2010/01/03 18:27:10 christos Exp $");
#endif
#endif /* not lint && not SCCSID */
@@ -64,7 +64,7 @@
typedef void (*history_vfun_t)(ptr_t, TYPE(HistEvent) *);
typedef int (*history_sfun_t)(ptr_t, TYPE(HistEvent) *, const int);
-struct FUNW(history) {
+struct TYPE(history) {
ptr_t h_ref; /* Argument for history fcns */
int h_ent; /* Last entry point for history */
history_gfun_t h_first; /* Get the first element */
Index: src/lib/libedit/readline.c
diff -u src/lib/libedit/readline.c:1.87 src/lib/libedit/readline.c:1.88
--- src/lib/libedit/readline.c:1.87 Wed Dec 30 18:54:52 2009
+++ src/lib/libedit/readline.c Sun Jan 3 13:27:10 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: readline.c,v 1.87 2009/12/30 23:54:52 christos Exp $ */
+/* $NetBSD: readline.c,v 1.88 2010/01/03 18:27:10 christos Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
#include "config.h"
#if !defined(lint) && !defined(SCCSID)
-__RCSID("$NetBSD: readline.c,v 1.87 2009/12/30 23:54:52 christos Exp $");
+__RCSID("$NetBSD: readline.c,v 1.88 2010/01/03 18:27:10 christos Exp $");
#endif /* not lint && not SCCSID */
#include <sys/types.h>
@@ -1298,7 +1298,8 @@
rl_initialize();
if (filename == NULL && (filename = _default_history_file()) == NULL)
return errno;
- return (FUNW(history)(h, &ev, H_LOAD, filename) == -1 ? (errno ? errno : EINVAL) : 0);
+ return (FUNW(history)(h, &ev, H_LOAD, filename) == -1 ?
+ (errno ? errno : EINVAL) : 0);
}
@@ -1314,7 +1315,8 @@
rl_initialize();
if (filename == NULL && (filename = _default_history_file()) == NULL)
return errno;
- return (FUNW(history)(h, &ev, H_SAVE, filename) == -1 ? (errno ? errno : EINVAL) : 0);
+ return (FUNW(history)(h, &ev, H_SAVE, filename) == -1 ?
+ (errno ? errno : EINVAL) : 0);
}
@@ -1456,7 +1458,7 @@
{
TYPE(HistEvent) ev;
- FUNW(history)(h, &ev, H_CLEAR);
+ (void)FUNW(history)(h, &ev, H_CLEAR);
history_length = 0;
}
@@ -1474,7 +1476,7 @@
return (0);
curr_num = ev.num;
- FUNW(history)(h, &ev, H_FIRST);
+ (void)FUNW(history)(h, &ev, H_FIRST);
off = 1;
while (ev.num != curr_num && FUNW(history)(h, &ev, H_NEXT) == 0)
off++;
@@ -1508,7 +1510,7 @@
return (-1);
curr_num = ev.num;
- FUNW(history)(h, &ev, H_FIRST);
+ (void)FUNW(history)(h, &ev, H_FIRST);
size = 0;
do
size += Strlen(ev.str) * sizeof(*ev.str);
@@ -1533,7 +1535,7 @@
if (pos >= history_length || pos < 0)
return (-1);
- FUNW(history)(h, &ev, H_CURR);
+ (void)FUNW(history)(h, &ev, H_CURR);
curr_num = ev.num;
/*
@@ -1541,7 +1543,7 @@
* (void **)-1
*/
if (FUNW(history)(h, &ev, H_DELDATA, pos, (void **)-1)) {
- FUNW(history)(h, &ev, H_SET, curr_num);
+ (void)FUNW(history)(h, &ev, H_SET, curr_num);
return(-1);
}
return (0);
@@ -1592,7 +1594,7 @@
if (FUNW(history)(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0)
break;
}
- FUNW(history)(h, &ev, H_SET, curr_num);
+ (void)FUNW(history)(h, &ev, H_SET, curr_num);
return (-1);
}
@@ -1605,7 +1607,8 @@
{
TYPE(HistEvent) ev;
- return (FUNW(history)(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str));
+ return (FUNW(history)(h, &ev, direction < 0 ?
+ H_PREV_STR : H_NEXT_STR, str));
}
@@ -1641,7 +1644,8 @@
}
/* set "current" pointer back to previous state */
- FUNW(history)(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
+ (void)FUNW(history)(h, &ev,
+ pos < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);
return (-1);
}
Index: src/lib/libedit/tokenizer.c
diff -u src/lib/libedit/tokenizer.c:1.17 src/lib/libedit/tokenizer.c:1.18
--- src/lib/libedit/tokenizer.c:1.17 Wed Dec 30 18:54:52 2009
+++ src/lib/libedit/tokenizer.c Sun Jan 3 13:27:10 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: tokenizer.c,v 1.17 2009/12/30 23:54:52 christos Exp $ */
+/* $NetBSD: tokenizer.c,v 1.18 2010/01/03 18:27:10 christos Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93";
#else
-__RCSID("$NetBSD: tokenizer.c,v 1.17 2009/12/30 23:54:52 christos Exp $");
+__RCSID("$NetBSD: tokenizer.c,v 1.18 2010/01/03 18:27:10 christos Exp $");
#endif
#endif /* not lint && not SCCSID */
@@ -68,7 +68,7 @@
#define tok_strdup(a) Strdup(a)
-struct FUNW(tokenizer) {
+struct TYPE(tokenizer) {
Char *ifs; /* In field separator */
int argc, amax; /* Current and maximum number of args */
Char **argv; /* Argument list */
Index: src/lib/libedit/TEST/Makefile
diff -u src/lib/libedit/TEST/Makefile:1.3 src/lib/libedit/TEST/Makefile:1.4
--- src/lib/libedit/TEST/Makefile:1.3 Thu Aug 31 16:20:38 2006
+++ src/lib/libedit/TEST/Makefile Sun Jan 3 13:27:10 2010
@@ -1,7 +1,7 @@
-# $NetBSD: Makefile,v 1.3 2006/08/31 20:20:38 rpaulo Exp $
+# $NetBSD: Makefile,v 1.4 2010/01/03 18:27:10 christos Exp $
NOMAN=1
-PROG=tc1
+PROG=wtc1
CPPFLAGS=-I${.CURDIR}/..
LDADD+=-ledit -ltermcap
DPADD+=${LIBEDIT} ${LIBTERMCAP}
Added files:
Index: src/lib/libedit/TEST/wtc1.c
diff -u /dev/null src/lib/libedit/TEST/wtc1.c:1.1
--- /dev/null Sun Jan 3 13:27:10 2010
+++ src/lib/libedit/TEST/wtc1.c Sun Jan 3 13:27:10 2010
@@ -0,0 +1,269 @@
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <locale.h>
+
+#include "../histedit.h"
+
+
+static int continuation;
+volatile sig_atomic_t gotsig;
+
+static wchar_t *
+prompt(EditLine *el)
+{
+ static wchar_t a[] = L"\1\e[7m\1Edit$\1\e[0m\1 ";
+ static wchar_t b[] = L"Edit> ";
+
+ return continuation ? b : a;
+}
+
+
+static void
+sig(int i)
+{
+ gotsig = i;
+}
+
+const char *
+my_wcstombs(const wchar_t *wstr)
+{
+ static struct {
+ char *str;
+ int len;
+ } buf;
+
+ int needed = wcstombs(0, wstr, 0) + 1;
+ if (needed > buf.len) {
+ buf.str = malloc(needed);
+ buf.len = needed;
+ }
+ wcstombs(buf.str, wstr, needed);
+ buf.str[needed - 1] = 0;
+
+ return buf.str;
+}
+
+
+static unsigned char
+complete(EditLine *el, int ch)
+{
+ DIR *dd = opendir(".");
+ struct dirent *dp;
+ const wchar_t *ptr;
+ char *buf, *bptr;
+ const LineInfoW *lf = el_wline(el);
+ int len, mblen, i;
+ unsigned char res;
+
+ /* Find the last word */
+ for (ptr = lf->cursor -1; !iswspace(*ptr) && ptr > lf->buffer; --ptr)
+ continue;
+ len = lf->cursor - ++ptr;
+
+ /* Convert last word to multibyte encoding, so we can compare to it */
+ wctomb(NULL, 0); /* Reset shift state */
+ mblen = MB_LEN_MAX * len + 1;
+ buf = bptr =(char *)malloc(mblen);
+ for (i = 0; i < len; ++i) {
+ /* Note: really should test for -1 return from wctomb */
+ bptr += wctomb(bptr, ptr[i]);
+ }
+ *bptr = 0; /* Terminate multibyte string */
+ mblen = bptr - buf;
+
+ /* Scan directory for matching name */
+ for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
+ if (mblen > strlen(dp->d_name))
+ continue;
+ if (strncmp(dp->d_name, buf, mblen) == 0) {
+ if (el_insertstr(el, &dp->d_name[mblen]) == -1)
+ res = CC_ERROR;
+ else
+ res = CC_REFRESH;
+ break;
+ }
+ }
+
+ closedir(dd);
+ free(buf);
+ return res;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ EditLine *el = NULL;
+ int numc, ncontinuation;
+ const wchar_t *line;
+ TokenizerW *tok;
+ HistoryW *hist;
+ HistEventW ev;
+#ifdef DEBUG
+ int i;
+#endif
+
+ setlocale(LC_ALL, "");
+
+ (void)signal(SIGINT, sig);
+ (void)signal(SIGQUIT, sig);
+ (void)signal(SIGHUP, sig);
+ (void)signal(SIGTERM, sig);
+
+ hist = history_winit(); /* Init built-in history */
+ history_w(hist, &ev, H_SETSIZE, 100); /* Remember 100 events */
+
+ tok = tok_winit(NULL); /* Init the tokenizer */
+
+ el = el_init(argv[0], stdin, stdout, stderr);
+
+ el_wset(el, EL_EDITOR, L"vi"); /* Default editor is vi */
+ el_wset(el, EL_SIGNAL, 1); /* Handle signals gracefully */
+ el_wset(el, EL_PROMPT_ESC, prompt, '\1'); /* Set the prompt function */
+
+ el_wset(el, EL_HIST, history_w, hist); /* FIXME - history_w? */
+
+ /* Add a user-defined function */
+ el_wset(el, EL_ADDFN, L"ed-complete", L"Complete argument", complete);
+
+ /* Bind <tab> to it */
+ el_wset(el, EL_BIND, L"^I", L"ed-complete", NULL);
+
+ /*
+ * Bind j, k in vi command mode to previous and next line, instead
+ * of previous and next history.
+ */
+ el_wset(el, EL_BIND, L"-a", L"k", L"ed-prev-line", NULL);
+ el_wset(el, EL_BIND, L"-a", L"j", L"ed-next-line", NULL);
+
+ /* Source the user's defaults file. */
+ el_source(el, NULL);
+
+ while((line = el_wgets(el, &numc)) != NULL && numc != 0) {
+ int ac, cc, co, rc;
+ const wchar_t **av;
+
+ const LineInfoW *li;
+ li = el_wline(el);
+
+#ifdef DEBUG
+ (void)fwprintf(stderr, L"==> got %d %ls", numc, line);
+ (void)fwprintf(stderr, L" > li `%.*ls_%.*ls'\n",
+ (li->cursor - li->buffer), li->buffer,
+ (li->lastchar - 1 - li->cursor),
+ (li->cursor >= li->lastchar) ? L"" : li->cursor);
+#endif
+
+ if (gotsig) {
+ (void)fprintf(stderr, "Got signal %d.\n", gotsig);
+ gotsig = 0;
+ el_reset(el);
+ }
+
+ if(!continuation && numc == 1)
+ continue; /* Only got a linefeed */
+
+ ac = cc = co = 0;
+ ncontinuation = tok_wline(tok, li, &ac, &av, &cc, &co);
+ if (ncontinuation < 0) {
+ (void) fprintf(stderr, "Internal error\n");
+ continuation = 0;
+ continue;
+ }
+
+#ifdef DEBUG
+ (void)fprintf(stderr, " > nc %d ac %d cc %d co %d\n",
+ ncontinuation, ac, cc, co);
+#endif
+ history_w(hist, &ev, continuation ? H_APPEND : H_ENTER, line);
+
+ continuation = ncontinuation;
+ ncontinuation = 0;
+ if(continuation)
+ continue;
+
+#ifdef DEBUG
+ for (i = 0; i < ac; ++i) {
+ (void)fwprintf(stderr, L" > arg# %2d ", i);
+ if (i != cc)
+ (void)fwprintf(stderr, L"`%ls'\n", av[i]);
+ else
+ (void)fwprintf(stderr, L"`%.*ls_%ls'\n",
+ co, av[i], av[i] + co);
+ }
+#endif
+
+ if (wcscmp (av[0], L"history") == 0) {
+ switch(ac) {
+ case 1:
+ for(rc = history_w(hist, &ev, H_LAST);
+ rc != -1;
+ rc = history_w(hist, &ev, H_PREV))
+ (void)fwprintf(stdout, L"%4d %ls",
+ ev.num, ev.str);
+ break;
+ case 2:
+ if (wcscmp(av[1], L"clear") == 0)
+ history_w(hist, &ev, H_CLEAR);
+ else
+ goto badhist;
+ break;
+ case 3:
+ if (wcscmp(av[1], L"load") == 0)
+ history_w(hist, &ev, H_LOAD,
+ my_wcstombs(av[2]));
+ else if (wcscmp(av[1], L"save") == 0)
+ history_w(hist, &ev, H_SAVE,
+ my_wcstombs(av[2]));
+ else
+ goto badhist;
+ break;
+ badhist:
+ default:
+ (void)fprintf(stderr,
+ "Bad history arguments\n");
+ break;
+ }
+ } else if (el_wparse(el, ac, av) == -1) {
+ switch (fork()) {
+ case 0: {
+ Tokenizer *ntok = tok_init(NULL);
+ int nargc;
+ const char **nav;
+ tok_str(ntok, my_wcstombs(line), &nargc, &nav);
+ execvp(nav[0],(char **)nav);
+ perror(nav[0]);
+ _exit(1);
+ /* NOTREACHED */
+ break;
+ }
+ case -1:
+ perror("fork");
+ break;
+ default:
+ if (wait(&rc) == -1)
+ perror("wait");
+ (void)fprintf(stderr, "Exit %x\n", rc);
+ break;
+ }
+ }
+
+ tok_wreset(tok);
+ }
+
+ el_end(el);
+ tok_wend(tok);
+ history_wend(hist);
+
+ fprintf(stdout, "\n");
+ return 0;
+}
+
+