2016-04-09 21:43:17 +03:00
|
|
|
/* $NetBSD: keymacro.c,v 1.16 2016/04/09 18:43:17 christos Exp $ */
|
1997-01-11 09:47:47 +03:00
|
|
|
|
1994-05-06 10:01:42 +04:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1992, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Christos Zoulas of Cornell University.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 20:42:00 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1994-05-06 10:01:42 +04:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2002-03-18 19:00:50 +03:00
|
|
|
#include "config.h"
|
1994-05-06 10:01:42 +04:00
|
|
|
#if !defined(lint) && !defined(SCCSID)
|
1997-01-11 09:47:47 +03:00
|
|
|
#if 0
|
2011-07-28 07:52:19 +04:00
|
|
|
static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93";
|
1997-01-11 09:47:47 +03:00
|
|
|
#else
|
2016-04-09 21:43:17 +03:00
|
|
|
__RCSID("$NetBSD: keymacro.c,v 1.16 2016/04/09 18:43:17 christos Exp $");
|
1997-01-11 09:47:47 +03:00
|
|
|
#endif
|
1994-05-06 10:01:42 +04:00
|
|
|
#endif /* not lint && not SCCSID */
|
|
|
|
|
|
|
|
/*
|
2011-07-28 07:48:46 +04:00
|
|
|
* keymacro.c: This module contains the procedures for maintaining
|
|
|
|
* the extended-key map.
|
1994-05-06 10:01:42 +04:00
|
|
|
*
|
1999-07-02 19:14:07 +04:00
|
|
|
* An extended-key (key) is a sequence of keystrokes introduced
|
2005-08-08 18:05:37 +04:00
|
|
|
* with a sequence introducer and consisting of an arbitrary
|
2011-07-28 07:48:46 +04:00
|
|
|
* number of characters. This module maintains a map (the
|
|
|
|
* el->el_keymacro.map)
|
1999-07-02 19:14:07 +04:00
|
|
|
* to convert these extended-key sequences into input strs
|
1994-05-06 10:01:42 +04:00
|
|
|
* (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
|
|
|
|
*
|
|
|
|
* Warning:
|
|
|
|
* If key is a substr of some other keys, then the longer
|
|
|
|
* keys are lost!! That is, if the keys "abcd" and "abcef"
|
2011-07-28 07:48:46 +04:00
|
|
|
* are in el->el_keymacro.map, adding the key "abc" will cause
|
|
|
|
* the first two definitions to be lost.
|
1994-05-06 10:01:42 +04:00
|
|
|
*
|
|
|
|
* Restrictions:
|
|
|
|
* -------------
|
|
|
|
* 1) It is not possible to have one key that is a
|
|
|
|
* substr of another.
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
2016-02-17 22:47:49 +03:00
|
|
|
#include <string.h>
|
1994-05-06 10:01:42 +04:00
|
|
|
|
|
|
|
#include "el.h"
|
|
|
|
|
1999-07-02 19:14:07 +04:00
|
|
|
/*
|
2011-07-28 07:48:46 +04:00
|
|
|
* The Nodes of the el->el_keymacro.map. The el->el_keymacro.map is a
|
|
|
|
* linked list of these node elements
|
1994-05-06 10:01:42 +04:00
|
|
|
*/
|
2011-07-28 05:56:26 +04:00
|
|
|
struct keymacro_node_t {
|
2016-02-17 22:47:49 +03:00
|
|
|
Char ch; /* single character of key */
|
2011-07-28 07:48:46 +04:00
|
|
|
int type; /* node type */
|
|
|
|
keymacro_value_t val; /* command code or pointer to str, */
|
2016-02-17 22:47:49 +03:00
|
|
|
/* if this is a leaf */
|
2011-07-28 05:56:26 +04:00
|
|
|
struct keymacro_node_t *next; /* ptr to next char of this key */
|
2011-07-28 07:48:46 +04:00
|
|
|
struct keymacro_node_t *sibling;/* ptr to another key with same prefix*/
|
1994-05-06 10:01:42 +04:00
|
|
|
};
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
private int node_trav(EditLine *, keymacro_node_t *, Char *,
|
|
|
|
keymacro_value_t *);
|
|
|
|
private int node__try(EditLine *, keymacro_node_t *, const Char *,
|
|
|
|
keymacro_value_t *, int);
|
From Ingo Schwarze:
As we have seen before, "histedit.h" can never get rid of including
the <wchar.h> header because using the data types defined there is
deeply ingrained in the public interfaces of libedit.
Now POSIX unconditionally requires that <wchar.h> defines the type
wint_t. Consequently, it can be used unconditionally, no matter
whether WIDECHAR is active or not. Consequently, the #define Int
is pointless.
Note that removing it is not gratuitious churn. Auditing for
integer signedness problems is already hard when only fundamental
types like "int" and "unsigned" are involved. It gets very hard
when types come into the picture that have platform-dependent
signedness, like "char" and "wint_t". Adding yet another layer
on top, changing both the signedness and the width in a platform-
dependent way, makes auditing yet harder, which IMHO is really
dangerous. Note that while removing the #define, i already found
one bug caused by this excessive complication - in the function
re_putc() in refresh.c. If WIDECHAR was defined, it printed an
Int = wint_t value with %c. Fortunately, that bug only affects
debugging, not production. The fix is contained in the patch.
With WIDECHAR, this doesn't change anything. For the case without
WIDECHAR, i checked that none of the places wants to store values
that might not fit in wint_t.
This only changes internal interfaces; public ones remain unchanged.
2016-02-14 17:49:34 +03:00
|
|
|
private keymacro_node_t *node__get(wint_t);
|
2011-07-28 05:56:26 +04:00
|
|
|
private void node__free(keymacro_node_t *);
|
|
|
|
private void node__put(EditLine *, keymacro_node_t *);
|
2011-07-28 07:48:46 +04:00
|
|
|
private int node__delete(EditLine *, keymacro_node_t **,
|
|
|
|
const Char *);
|
|
|
|
private int node_lookup(EditLine *, const Char *,
|
|
|
|
keymacro_node_t *, size_t);
|
2011-07-28 05:56:26 +04:00
|
|
|
private int node_enum(EditLine *, keymacro_node_t *, size_t);
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
#define KEY_BUFSIZ EL_BUFSIZ
|
1994-05-06 10:01:42 +04:00
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_init():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Initialize the key maps
|
|
|
|
*/
|
|
|
|
protected int
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_init(EditLine *el)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2000-09-05 02:06:28 +04:00
|
|
|
|
2011-07-28 07:48:46 +04:00
|
|
|
el->el_keymacro.buf = el_malloc(KEY_BUFSIZ *
|
|
|
|
sizeof(*el->el_keymacro.buf));
|
2011-07-28 05:56:26 +04:00
|
|
|
if (el->el_keymacro.buf == NULL)
|
2011-07-29 19:16:33 +04:00
|
|
|
return -1;
|
2011-07-28 05:56:26 +04:00
|
|
|
el->el_keymacro.map = NULL;
|
|
|
|
keymacro_reset(el);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
1999-07-02 19:14:07 +04:00
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_end():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Free the key maps
|
|
|
|
*/
|
|
|
|
protected void
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_end(EditLine *el)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2000-09-05 02:06:28 +04:00
|
|
|
|
2011-07-29 00:50:55 +04:00
|
|
|
el_free(el->el_keymacro.buf);
|
2011-07-28 05:56:26 +04:00
|
|
|
el->el_keymacro.buf = NULL;
|
|
|
|
node__free(el->el_keymacro.map);
|
1999-07-02 19:14:07 +04:00
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_map_cmd():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Associate cmd with a key value
|
|
|
|
*/
|
2011-07-28 05:56:26 +04:00
|
|
|
protected keymacro_value_t *
|
|
|
|
keymacro_map_cmd(EditLine *el, int cmd)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2000-09-05 02:06:28 +04:00
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
el->el_keymacro.val.cmd = (el_action_t) cmd;
|
2011-07-29 19:16:33 +04:00
|
|
|
return &el->el_keymacro.val;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_map_str():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Associate str with a key value
|
|
|
|
*/
|
2011-07-28 05:56:26 +04:00
|
|
|
protected keymacro_value_t *
|
|
|
|
keymacro_map_str(EditLine *el, Char *str)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2000-09-05 02:06:28 +04:00
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
el->el_keymacro.val.str = str;
|
2011-07-29 19:16:33 +04:00
|
|
|
return &el->el_keymacro.val;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_reset():
|
2011-07-28 07:48:46 +04:00
|
|
|
* Takes all nodes on el->el_keymacro.map and puts them on free list.
|
|
|
|
* Then initializes el->el_keymacro.map with arrow keys
|
1994-05-06 10:01:42 +04:00
|
|
|
* [Always bind the ansi arrow keys?]
|
|
|
|
*/
|
|
|
|
protected void
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_reset(EditLine *el)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2000-09-05 02:06:28 +04:00
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
node__put(el, el->el_keymacro.map);
|
|
|
|
el->el_keymacro.map = NULL;
|
2000-09-05 02:06:28 +04:00
|
|
|
return;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_get():
|
|
|
|
* Calls the recursive function with entry point el->el_keymacro.map
|
1994-05-06 10:01:42 +04:00
|
|
|
* Looks up *ch in map and then reads characters until a
|
|
|
|
* complete match is found or a mismatch occurs. Returns the
|
|
|
|
* type of the match found (XK_STR, XK_CMD, or XK_EXE).
|
1999-07-02 19:14:07 +04:00
|
|
|
* Returns NULL in val.str and XK_STR for no match.
|
1994-05-06 10:01:42 +04:00
|
|
|
* The last character read is returned in *ch.
|
|
|
|
*/
|
|
|
|
protected int
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_get(EditLine *el, Char *ch, keymacro_value_t *val)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
|
|
|
|
2011-07-29 19:16:33 +04:00
|
|
|
return node_trav(el, el->el_keymacro.map, ch, val);
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_add():
|
2011-07-28 07:48:46 +04:00
|
|
|
* Adds key to the el->el_keymacro.map and associates the value in
|
|
|
|
* val with it. If key is already is in el->el_keymacro.map, the new
|
|
|
|
* code is applied to the existing key. Ntype specifies if code is a
|
|
|
|
* command, an out str or a unix command.
|
1994-05-06 10:01:42 +04:00
|
|
|
*/
|
|
|
|
protected void
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_add(EditLine *el, const Char *key, keymacro_value_t *val, int ntype)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
if (key[0] == '\0') {
|
|
|
|
(void) fprintf(el->el_errfile,
|
2011-07-28 05:56:26 +04:00
|
|
|
"keymacro_add: Null extended-key not allowed.\n");
|
2000-09-05 02:06:28 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
|
|
|
|
(void) fprintf(el->el_errfile,
|
2011-07-28 05:56:26 +04:00
|
|
|
"keymacro_add: sequence-lead-in command not allowed\n");
|
2000-09-05 02:06:28 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-07-28 05:56:26 +04:00
|
|
|
if (el->el_keymacro.map == NULL)
|
2000-09-05 02:06:28 +04:00
|
|
|
/* tree is initially empty. Set up new node to match key[0] */
|
2011-07-28 05:56:26 +04:00
|
|
|
el->el_keymacro.map = node__get(key[0]);
|
2000-09-05 02:06:28 +04:00
|
|
|
/* it is properly initialized */
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* Now recurse through el->el_keymacro.map */
|
|
|
|
(void) node__try(el, el->el_keymacro.map, key, val, ntype);
|
2000-09-05 02:06:28 +04:00
|
|
|
return;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_clear():
|
1994-05-06 10:01:42 +04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
protected void
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_clear(EditLine *el, el_action_t *map, const Char *in)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2009-12-31 01:37:40 +03:00
|
|
|
if (*in > N_KEYS) /* can't be in the map */
|
|
|
|
return;
|
2001-05-17 05:02:17 +04:00
|
|
|
if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
|
2000-09-05 02:06:28 +04:00
|
|
|
((map == el->el_map.key &&
|
2001-05-17 05:02:17 +04:00
|
|
|
el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
|
2000-09-05 02:06:28 +04:00
|
|
|
(map == el->el_map.alt &&
|
2001-05-17 05:02:17 +04:00
|
|
|
el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
|
2011-07-28 05:56:26 +04:00
|
|
|
(void) keymacro_delete(el, in);
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_delete():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Delete the key and all longer keys staring with key, if
|
|
|
|
* they exists.
|
|
|
|
*/
|
|
|
|
protected int
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_delete(EditLine *el, const Char *key)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
if (key[0] == '\0') {
|
|
|
|
(void) fprintf(el->el_errfile,
|
2011-07-28 05:56:26 +04:00
|
|
|
"keymacro_delete: Null extended-key not allowed.\n");
|
2011-07-29 19:16:33 +04:00
|
|
|
return -1;
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
2011-07-28 05:56:26 +04:00
|
|
|
if (el->el_keymacro.map == NULL)
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
(void) node__delete(el, &el->el_keymacro.map, key);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_print():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Print the binding associated with key key.
|
2011-07-28 05:56:26 +04:00
|
|
|
* Print entire el->el_keymacro.map if null
|
1994-05-06 10:01:42 +04:00
|
|
|
*/
|
|
|
|
protected void
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_print(EditLine *el, const Char *key)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* do nothing if el->el_keymacro.map is empty and null key specified */
|
|
|
|
if (el->el_keymacro.map == NULL && *key == 0)
|
2000-09-05 02:06:28 +04:00
|
|
|
return;
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
el->el_keymacro.buf[0] = '"';
|
2011-07-30 03:44:44 +04:00
|
|
|
if (node_lookup(el, key, el->el_keymacro.map, (size_t)1) <= -1)
|
2000-09-05 02:06:28 +04:00
|
|
|
/* key is not bound */
|
2016-04-09 21:43:17 +03:00
|
|
|
(void) fprintf(el->el_errfile, "Unbound extended key \"%ls"
|
2011-07-28 07:48:46 +04:00
|
|
|
"\"\n", key);
|
2000-09-05 02:06:28 +04:00
|
|
|
return;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* node_trav():
|
|
|
|
* recursively traverses node in tree until match or mismatch is
|
2016-02-17 22:47:49 +03:00
|
|
|
* found. May read in more characters.
|
1994-05-06 10:01:42 +04:00
|
|
|
*/
|
|
|
|
private int
|
2011-07-28 05:56:26 +04:00
|
|
|
node_trav(EditLine *el, keymacro_node_t *ptr, Char *ch, keymacro_value_t *val)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2016-02-24 17:25:38 +03:00
|
|
|
wchar_t wc;
|
2000-09-05 02:06:28 +04:00
|
|
|
|
|
|
|
if (ptr->ch == *ch) {
|
|
|
|
/* match found */
|
|
|
|
if (ptr->next) {
|
|
|
|
/* key not complete so get next char */
|
2016-02-24 17:25:38 +03:00
|
|
|
if (el_wgetc(el, &wc) != 1) {/* if EOF or error */
|
2000-09-05 02:06:28 +04:00
|
|
|
val->cmd = ED_END_OF_FILE;
|
2011-07-29 19:16:33 +04:00
|
|
|
return XK_CMD;
|
2000-09-05 02:06:28 +04:00
|
|
|
/* PWP: Pretend we just read an end-of-file */
|
|
|
|
}
|
2016-02-24 17:25:38 +03:00
|
|
|
*ch = (Char)wc;
|
2011-07-29 19:16:33 +04:00
|
|
|
return node_trav(el, ptr->next, ch, val);
|
2000-09-05 02:06:28 +04:00
|
|
|
} else {
|
|
|
|
*val = ptr->val;
|
|
|
|
if (ptr->type != XK_CMD)
|
|
|
|
*ch = '\0';
|
2011-07-29 19:16:33 +04:00
|
|
|
return ptr->type;
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* no match found here */
|
|
|
|
if (ptr->sibling) {
|
|
|
|
/* try next sibling */
|
2011-07-29 19:16:33 +04:00
|
|
|
return node_trav(el, ptr->sibling, ch, val);
|
2000-09-05 02:06:28 +04:00
|
|
|
} else {
|
|
|
|
/* no next sibling -- mismatch */
|
|
|
|
val->str = NULL;
|
2011-07-29 19:16:33 +04:00
|
|
|
return XK_STR;
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* node__try():
|
2016-02-17 22:47:49 +03:00
|
|
|
* Find a node that matches *str or allocate a new one
|
1994-05-06 10:01:42 +04:00
|
|
|
*/
|
|
|
|
private int
|
2011-07-28 07:48:46 +04:00
|
|
|
node__try(EditLine *el, keymacro_node_t *ptr, const Char *str,
|
|
|
|
keymacro_value_t *val, int ntype)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr->ch != *str) {
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_node_t *xm;
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
|
|
|
|
if (xm->sibling->ch == *str)
|
|
|
|
break;
|
|
|
|
if (xm->sibling == NULL)
|
|
|
|
xm->sibling = node__get(*str); /* setup new node */
|
|
|
|
ptr = xm->sibling;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
2000-09-05 02:06:28 +04:00
|
|
|
if (*++str == '\0') {
|
|
|
|
/* we're there */
|
|
|
|
if (ptr->next != NULL) {
|
2000-11-12 01:18:57 +03:00
|
|
|
node__put(el, ptr->next);
|
2000-09-05 02:06:28 +04:00
|
|
|
/* lose longer keys with this prefix */
|
|
|
|
ptr->next = NULL;
|
|
|
|
}
|
|
|
|
switch (ptr->type) {
|
|
|
|
case XK_CMD:
|
|
|
|
case XK_NOD:
|
|
|
|
break;
|
|
|
|
case XK_STR:
|
|
|
|
case XK_EXE:
|
|
|
|
if (ptr->val.str)
|
2011-07-29 00:50:55 +04:00
|
|
|
el_free(ptr->val.str);
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
default:
|
2000-11-12 01:18:57 +03:00
|
|
|
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
|
|
|
|
ptr->type));
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
switch (ptr->type = ntype) {
|
|
|
|
case XK_CMD:
|
|
|
|
ptr->val = *val;
|
|
|
|
break;
|
|
|
|
case XK_STR:
|
|
|
|
case XK_EXE:
|
2009-12-31 01:37:40 +03:00
|
|
|
if ((ptr->val.str = Strdup(val->str)) == NULL)
|
2003-10-19 03:48:42 +04:00
|
|
|
return -1;
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
default:
|
2000-11-12 01:18:57 +03:00
|
|
|
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* still more chars to go */
|
|
|
|
if (ptr->next == NULL)
|
|
|
|
ptr->next = node__get(*str); /* setup new node */
|
2000-11-12 01:18:57 +03:00
|
|
|
(void) node__try(el, ptr->next, str, val, ntype);
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* node__delete():
|
|
|
|
* Delete node that matches str
|
|
|
|
*/
|
|
|
|
private int
|
2011-07-28 05:56:26 +04:00
|
|
|
node__delete(EditLine *el, keymacro_node_t **inptr, const Char *str)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_node_t *ptr;
|
|
|
|
keymacro_node_t *prev_ptr = NULL;
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
ptr = *inptr;
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr->ch != *str) {
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_node_t *xm;
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
|
|
|
|
if (xm->sibling->ch == *str)
|
|
|
|
break;
|
|
|
|
if (xm->sibling == NULL)
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
2000-09-05 02:06:28 +04:00
|
|
|
prev_ptr = xm;
|
|
|
|
ptr = xm->sibling;
|
|
|
|
}
|
|
|
|
if (*++str == '\0') {
|
|
|
|
/* we're there */
|
|
|
|
if (prev_ptr == NULL)
|
|
|
|
*inptr = ptr->sibling;
|
|
|
|
else
|
|
|
|
prev_ptr->sibling = ptr->sibling;
|
|
|
|
ptr->sibling = NULL;
|
2000-11-12 01:18:57 +03:00
|
|
|
node__put(el, ptr);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 1;
|
2000-11-12 01:18:57 +03:00
|
|
|
} else if (ptr->next != NULL &&
|
|
|
|
node__delete(el, &ptr->next, str) == 1) {
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr->next != NULL)
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
2000-09-05 02:06:28 +04:00
|
|
|
if (prev_ptr == NULL)
|
|
|
|
*inptr = ptr->sibling;
|
|
|
|
else
|
|
|
|
prev_ptr->sibling = ptr->sibling;
|
|
|
|
ptr->sibling = NULL;
|
2000-11-12 01:18:57 +03:00
|
|
|
node__put(el, ptr);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 1;
|
2000-09-05 02:06:28 +04:00
|
|
|
} else {
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
|
1994-05-06 10:01:42 +04:00
|
|
|
/* node__put():
|
|
|
|
* Puts a tree of nodes onto free list using free(3).
|
|
|
|
*/
|
|
|
|
private void
|
2011-07-28 05:56:26 +04:00
|
|
|
node__put(EditLine *el, keymacro_node_t *ptr)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr == NULL)
|
|
|
|
return;
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr->next != NULL) {
|
2000-11-12 01:18:57 +03:00
|
|
|
node__put(el, ptr->next);
|
2000-09-05 02:06:28 +04:00
|
|
|
ptr->next = NULL;
|
|
|
|
}
|
2000-11-12 01:18:57 +03:00
|
|
|
node__put(el, ptr->sibling);
|
2000-09-05 02:06:28 +04:00
|
|
|
|
|
|
|
switch (ptr->type) {
|
|
|
|
case XK_CMD:
|
|
|
|
case XK_NOD:
|
|
|
|
break;
|
|
|
|
case XK_EXE:
|
|
|
|
case XK_STR:
|
|
|
|
if (ptr->val.str != NULL)
|
2011-07-29 00:50:55 +04:00
|
|
|
el_free(ptr->val.str);
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
default:
|
2000-11-12 01:18:57 +03:00
|
|
|
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
}
|
2011-07-29 00:50:55 +04:00
|
|
|
el_free(ptr);
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* node__get():
|
2011-07-28 05:56:26 +04:00
|
|
|
* Returns pointer to a keymacro_node_t for ch.
|
1994-05-06 10:01:42 +04:00
|
|
|
*/
|
2011-07-28 05:56:26 +04:00
|
|
|
private keymacro_node_t *
|
From Ingo Schwarze:
As we have seen before, "histedit.h" can never get rid of including
the <wchar.h> header because using the data types defined there is
deeply ingrained in the public interfaces of libedit.
Now POSIX unconditionally requires that <wchar.h> defines the type
wint_t. Consequently, it can be used unconditionally, no matter
whether WIDECHAR is active or not. Consequently, the #define Int
is pointless.
Note that removing it is not gratuitious churn. Auditing for
integer signedness problems is already hard when only fundamental
types like "int" and "unsigned" are involved. It gets very hard
when types come into the picture that have platform-dependent
signedness, like "char" and "wint_t". Adding yet another layer
on top, changing both the signedness and the width in a platform-
dependent way, makes auditing yet harder, which IMHO is really
dangerous. Note that while removing the #define, i already found
one bug caused by this excessive complication - in the function
re_putc() in refresh.c. If WIDECHAR was defined, it printed an
Int = wint_t value with %c. Fortunately, that bug only affects
debugging, not production. The fix is contained in the patch.
With WIDECHAR, this doesn't change anything. For the case without
WIDECHAR, i checked that none of the places wants to store values
that might not fit in wint_t.
This only changes internal interfaces; public ones remain unchanged.
2016-02-14 17:49:34 +03:00
|
|
|
node__get(wint_t ch)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_node_t *ptr;
|
2000-09-05 02:06:28 +04:00
|
|
|
|
2011-07-29 00:50:55 +04:00
|
|
|
ptr = el_malloc(sizeof(*ptr));
|
2001-01-04 18:56:31 +03:00
|
|
|
if (ptr == NULL)
|
|
|
|
return NULL;
|
2016-02-11 22:21:04 +03:00
|
|
|
ptr->ch = (Char)ch;
|
2000-09-05 02:06:28 +04:00
|
|
|
ptr->type = XK_NOD;
|
|
|
|
ptr->val.str = NULL;
|
|
|
|
ptr->next = NULL;
|
|
|
|
ptr->sibling = NULL;
|
2011-07-29 19:16:33 +04:00
|
|
|
return ptr;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
2005-07-07 01:13:02 +04:00
|
|
|
private void
|
2011-07-28 05:56:26 +04:00
|
|
|
node__free(keymacro_node_t *k)
|
2005-07-07 01:13:02 +04:00
|
|
|
{
|
|
|
|
if (k == NULL)
|
|
|
|
return;
|
|
|
|
node__free(k->sibling);
|
|
|
|
node__free(k->next);
|
2011-07-29 00:50:55 +04:00
|
|
|
el_free(k);
|
2005-07-07 01:13:02 +04:00
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
|
|
|
|
/* node_lookup():
|
|
|
|
* look for the str starting at node ptr.
|
|
|
|
* Print if last node
|
|
|
|
*/
|
|
|
|
private int
|
2011-07-28 05:56:26 +04:00
|
|
|
node_lookup(EditLine *el, const Char *str, keymacro_node_t *ptr, size_t cnt)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2009-12-31 01:37:40 +03:00
|
|
|
ssize_t used;
|
2000-09-05 02:06:28 +04:00
|
|
|
|
|
|
|
if (ptr == NULL)
|
2011-07-29 19:16:33 +04:00
|
|
|
return -1; /* cannot have null ptr */
|
2000-09-05 02:06:28 +04:00
|
|
|
|
2009-12-31 01:37:40 +03:00
|
|
|
if (!str || *str == 0) {
|
2000-09-05 02:06:28 +04:00
|
|
|
/* no more chars in str. node_enum from here. */
|
|
|
|
(void) node_enum(el, ptr, cnt);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
2000-09-05 02:06:28 +04:00
|
|
|
} else {
|
2011-07-28 05:56:26 +04:00
|
|
|
/* If match put this char into el->el_keymacro.buf. Recurse */
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr->ch == *str) {
|
|
|
|
/* match found */
|
2011-07-28 05:56:26 +04:00
|
|
|
used = ct_visual_char(el->el_keymacro.buf + cnt,
|
2009-12-31 01:37:40 +03:00
|
|
|
KEY_BUFSIZ - cnt, ptr->ch);
|
|
|
|
if (used == -1)
|
2011-07-29 19:16:33 +04:00
|
|
|
return -1; /* ran out of buffer space */
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr->next != NULL)
|
|
|
|
/* not yet at leaf */
|
|
|
|
return (node_lookup(el, str + 1, ptr->next,
|
2011-08-16 20:25:15 +04:00
|
|
|
(size_t)used + cnt));
|
2000-09-05 02:06:28 +04:00
|
|
|
else {
|
|
|
|
/* next node is null so key should be complete */
|
|
|
|
if (str[1] == 0) {
|
2011-08-16 20:25:15 +04:00
|
|
|
size_t px = cnt + (size_t)used;
|
2011-07-28 07:48:46 +04:00
|
|
|
el->el_keymacro.buf[px] = '"';
|
|
|
|
el->el_keymacro.buf[px + 1] = '\0';
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_kprint(el, el->el_keymacro.buf,
|
2000-09-05 02:06:28 +04:00
|
|
|
&ptr->val, ptr->type);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
2000-09-05 02:06:28 +04:00
|
|
|
} else
|
2011-07-29 19:16:33 +04:00
|
|
|
return -1;
|
2000-09-05 02:06:28 +04:00
|
|
|
/* mismatch -- str still has chars */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* no match found try sibling */
|
|
|
|
if (ptr->sibling)
|
|
|
|
return (node_lookup(el, str, ptr->sibling,
|
|
|
|
cnt));
|
|
|
|
else
|
2011-07-29 19:16:33 +04:00
|
|
|
return -1;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* node_enum():
|
|
|
|
* Traverse the node printing the characters it is bound in buffer
|
|
|
|
*/
|
|
|
|
private int
|
2011-07-28 05:56:26 +04:00
|
|
|
node_enum(EditLine *el, keymacro_node_t *ptr, size_t cnt)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2009-12-31 01:37:40 +03:00
|
|
|
ssize_t used;
|
1994-05-06 10:01:42 +04:00
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */
|
2011-07-28 05:56:26 +04:00
|
|
|
el->el_keymacro.buf[++cnt] = '"';
|
|
|
|
el->el_keymacro.buf[++cnt] = '\0';
|
2000-09-05 02:06:28 +04:00
|
|
|
(void) fprintf(el->el_errfile,
|
1994-05-06 10:01:42 +04:00
|
|
|
"Some extended keys too long for internal print buffer");
|
2016-04-09 21:43:17 +03:00
|
|
|
(void) fprintf(el->el_errfile, " \"%ls...\"\n",
|
2011-07-28 07:48:46 +04:00
|
|
|
el->el_keymacro.buf);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
|
|
|
if (ptr == NULL) {
|
1994-05-06 10:01:42 +04:00
|
|
|
#ifdef DEBUG_EDIT
|
2000-09-05 02:06:28 +04:00
|
|
|
(void) fprintf(el->el_errfile,
|
|
|
|
"node_enum: BUG!! Null ptr passed\n!");
|
1994-05-06 10:01:42 +04:00
|
|
|
#endif
|
2011-07-29 19:16:33 +04:00
|
|
|
return -1;
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
|
|
|
/* put this char at end of str */
|
2011-07-28 07:48:46 +04:00
|
|
|
used = ct_visual_char(el->el_keymacro.buf + cnt, KEY_BUFSIZ - cnt,
|
|
|
|
ptr->ch);
|
2000-09-05 02:06:28 +04:00
|
|
|
if (ptr->next == NULL) {
|
|
|
|
/* print this key and function */
|
2011-08-16 20:25:15 +04:00
|
|
|
el->el_keymacro.buf[cnt + (size_t)used ] = '"';
|
|
|
|
el->el_keymacro.buf[cnt + (size_t)used + 1] = '\0';
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_kprint(el, el->el_keymacro.buf, &ptr->val, ptr->type);
|
2000-09-05 02:06:28 +04:00
|
|
|
} else
|
2011-08-16 20:25:15 +04:00
|
|
|
(void) node_enum(el, ptr->next, cnt + (size_t)used);
|
2000-09-05 02:06:28 +04:00
|
|
|
|
|
|
|
/* go to sibling if there is one */
|
|
|
|
if (ptr->sibling)
|
|
|
|
(void) node_enum(el, ptr->sibling, cnt);
|
2011-07-29 19:16:33 +04:00
|
|
|
return 0;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro_kprint():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Print the specified key and its associated
|
|
|
|
* function specified by val
|
|
|
|
*/
|
|
|
|
protected void
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro_kprint(EditLine *el, const Char *key, keymacro_value_t *val, int ntype)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2000-09-05 02:06:28 +04:00
|
|
|
el_bindings_t *fp;
|
|
|
|
char unparsbuf[EL_BUFSIZ];
|
2000-10-04 20:21:39 +04:00
|
|
|
static const char fmt[] = "%-15s-> %s\n";
|
2000-09-05 02:06:28 +04:00
|
|
|
|
|
|
|
if (val != NULL)
|
|
|
|
switch (ntype) {
|
|
|
|
case XK_STR:
|
|
|
|
case XK_EXE:
|
2011-07-28 05:56:26 +04:00
|
|
|
(void) keymacro__decode_str(val->str, unparsbuf,
|
2016-02-17 22:47:49 +03:00
|
|
|
sizeof(unparsbuf),
|
2006-03-07 00:11:56 +03:00
|
|
|
ntype == XK_STR ? "\"\"" : "[]");
|
2009-12-31 01:37:40 +03:00
|
|
|
(void) fprintf(el->el_outfile, fmt,
|
|
|
|
ct_encode_string(key, &el->el_scratch), unparsbuf);
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
case XK_CMD:
|
|
|
|
for (fp = el->el_map.help; fp->name; fp++)
|
|
|
|
if (val->cmd == fp->func) {
|
2016-04-09 21:43:17 +03:00
|
|
|
wcstombs(unparsbuf, fp->name, sizeof(unparsbuf));
|
2009-12-31 01:37:40 +03:00
|
|
|
unparsbuf[sizeof(unparsbuf) -1] = '\0';
|
2000-09-05 02:06:28 +04:00
|
|
|
(void) fprintf(el->el_outfile, fmt,
|
2009-12-31 01:37:40 +03:00
|
|
|
ct_encode_string(key, &el->el_scratch), unparsbuf);
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
#ifdef DEBUG_KEY
|
2000-09-05 02:06:28 +04:00
|
|
|
if (fp->name == NULL)
|
|
|
|
(void) fprintf(el->el_outfile,
|
|
|
|
"BUG! Command not found.\n");
|
1994-05-06 10:01:42 +04:00
|
|
|
#endif
|
|
|
|
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
default:
|
2000-11-12 01:18:57 +03:00
|
|
|
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
|
2000-09-05 02:06:28 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
2009-12-31 01:37:40 +03:00
|
|
|
(void) fprintf(el->el_outfile, fmt, ct_encode_string(key,
|
|
|
|
&el->el_scratch), "no input");
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-03-07 00:11:56 +03:00
|
|
|
#define ADDC(c) \
|
|
|
|
if (b < eb) \
|
|
|
|
*b++ = c; \
|
|
|
|
else \
|
|
|
|
b++
|
2011-07-28 05:56:26 +04:00
|
|
|
/* keymacro__decode_str():
|
1994-05-06 10:01:42 +04:00
|
|
|
* Make a printable version of the ey
|
|
|
|
*/
|
2009-02-22 02:31:56 +03:00
|
|
|
protected size_t
|
2011-07-28 05:56:26 +04:00
|
|
|
keymacro__decode_str(const Char *str, char *buf, size_t len, const char *sep)
|
1994-05-06 10:01:42 +04:00
|
|
|
{
|
2006-03-07 00:11:56 +03:00
|
|
|
char *b = buf, *eb = b + len;
|
2009-12-31 01:37:40 +03:00
|
|
|
const Char *p;
|
2000-09-05 02:06:28 +04:00
|
|
|
|
|
|
|
b = buf;
|
2006-03-07 00:11:56 +03:00
|
|
|
if (sep[0] != '\0') {
|
|
|
|
ADDC(sep[0]);
|
|
|
|
}
|
|
|
|
if (*str == '\0') {
|
|
|
|
ADDC('^');
|
|
|
|
ADDC('@');
|
2009-12-31 01:37:40 +03:00
|
|
|
goto add_endsep;
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
2000-09-05 02:06:28 +04:00
|
|
|
for (p = str; *p != 0; p++) {
|
2009-12-31 01:37:40 +03:00
|
|
|
Char dbuf[VISUAL_WIDTH_MAX];
|
|
|
|
Char *p2 = dbuf;
|
|
|
|
ssize_t l = ct_visual_char(dbuf, VISUAL_WIDTH_MAX, *p);
|
|
|
|
while (l-- > 0) {
|
|
|
|
ssize_t n = ct_encode_char(b, (size_t)(eb - b), *p2++);
|
|
|
|
if (n == -1) /* ran out of space */
|
|
|
|
goto add_endsep;
|
|
|
|
else
|
|
|
|
b += n;
|
2000-09-05 02:06:28 +04:00
|
|
|
}
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|
2009-12-31 01:37:40 +03:00
|
|
|
add_endsep:
|
2006-03-07 00:11:56 +03:00
|
|
|
if (sep[0] != '\0' && sep[1] != '\0') {
|
|
|
|
ADDC(sep[1]);
|
|
|
|
}
|
|
|
|
ADDC('\0');
|
2009-02-16 03:15:45 +03:00
|
|
|
if ((size_t)(b - buf) >= len)
|
2006-03-07 00:11:56 +03:00
|
|
|
buf[len - 1] = '\0';
|
2009-02-22 02:31:56 +03:00
|
|
|
return (size_t)(b - buf);
|
1994-05-06 10:01:42 +04:00
|
|
|
}
|