* Imported libutil.a and libedit.a from FreeBSD 6.1 release.
* Build of libedit.a is simplified; it does not recreate some automatically created files. * Build of libutil.a currently only includes fparseln.c, others may be added as needed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18438 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+2
-1
@@ -2,7 +2,7 @@ SubDir HAIKU_TOP src libs ;
|
||||
|
||||
SubInclude HAIKU_TOP src libs agg ;
|
||||
SubInclude HAIKU_TOP src libs bsd ;
|
||||
#SubInclude HAIKU_TOP src libs edit ;
|
||||
SubInclude HAIKU_TOP src libs edit ;
|
||||
SubInclude HAIKU_TOP src libs fluidsynth ;
|
||||
SubInclude HAIKU_TOP src libs freetype2 ;
|
||||
SubInclude HAIKU_TOP src libs icon ;
|
||||
@@ -11,4 +11,5 @@ SubInclude HAIKU_TOP src libs pdflib ;
|
||||
SubInclude HAIKU_TOP src libs png ;
|
||||
SubInclude HAIKU_TOP src libs stdc++ ;
|
||||
SubInclude HAIKU_TOP src libs termcap ;
|
||||
SubInclude HAIKU_TOP src libs util ;
|
||||
SubInclude HAIKU_TOP src libs zlib ;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
SubDir HAIKU_TOP src libs edit ;
|
||||
|
||||
SetSubDirSupportedPlatforms $(HAIKU_BONE_COMPATIBLE_PLATFORMS) ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) headers libs ncurses ] : true ;
|
||||
|
||||
local defines = [ FDefines SCCSID=0 ] ;
|
||||
SubDirCcFlags $(defines) ;
|
||||
|
||||
StaticLibrary libedit.a :
|
||||
chared.c
|
||||
common.c
|
||||
el.c
|
||||
emacs.c
|
||||
fcns.c
|
||||
help.c
|
||||
hist.c
|
||||
history.c
|
||||
key.c
|
||||
map.c
|
||||
parse.c
|
||||
prompt.c
|
||||
read.c
|
||||
refresh.c
|
||||
search.c
|
||||
sig.c
|
||||
tokenizer.c
|
||||
term.c
|
||||
tty.c
|
||||
vi.c
|
||||
;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# $NetBSD: Makefile,v 1.34 2005/05/28 12:02:53 lukem Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/4/93
|
||||
# $FreeBSD: src/lib/libedit/Makefile,v 1.30 2005/08/07 20:51:52 stefanf Exp $
|
||||
|
||||
LIB= edit
|
||||
SHLIB_MAJOR= 5
|
||||
SHLIBDIR?= /lib
|
||||
|
||||
OSRCS= chared.c common.c el.c emacs.c fcns.c help.c hist.c key.c map.c \
|
||||
parse.c prompt.c read.c refresh.c search.c sig.c term.c tty.c vi.c
|
||||
|
||||
DPADD= ${LIBNCURSES}
|
||||
LDADD= -lncurses
|
||||
|
||||
MAN= editline.3 editrc.5
|
||||
|
||||
MLINKS= editline.3 el_deletestr.3 editline.3 el_end.3 editline.3 el_init.3 \
|
||||
editline.3 el_get.3 editline.3 el_getc.3 editline.3 el_gets.3 \
|
||||
editline.3 history.3 editline.3 history_end.3 \
|
||||
editline.3 history_init.3 editline.3 el_insertstr.3 \
|
||||
editline.3 el_line.3 editline.3 el_parse.3 editline.3 el_push.3 \
|
||||
editline.3 el_reset.3 editline.3 el_resize.3 editline.3 el_set.3 \
|
||||
editline.3 el_source.3 \
|
||||
editline.3 tok_init.3 editline.3 tok_end.3 editline.3 tok_reset.3 \
|
||||
editline.3 tok_line.3 editline.3 tok_str.3
|
||||
|
||||
# For speed and debugging
|
||||
#SRCS= ${OSRCS} tokenizer.c history.c
|
||||
# For protection
|
||||
SRCS= editline.c tokenizer.c history.c
|
||||
SRCS+= common.h emacs.h fcns.h help.h vi.h
|
||||
CLEANFILES+= common.h editline.c emacs.h fcns.c fcns.h help.c help.h vi.h
|
||||
|
||||
CFLAGS+= -I. -I${.CURDIR}
|
||||
CFLAGS+= #-DDEBUG_TTY -DDEBUG_KEY -DDEBUG_READ -DDEBUG -DDEBUG_REFRESH
|
||||
CFLAGS+= #-DDEBUG_PASTE -DDEBUG_EDIT
|
||||
|
||||
AHDR= vi.h emacs.h common.h
|
||||
ASRC= ${.CURDIR}/vi.c ${.CURDIR}/emacs.c ${.CURDIR}/common.c
|
||||
|
||||
.for hdr in vi emacs common
|
||||
${hdr}.h: ${hdr}.c makelist
|
||||
sh ${.CURDIR}/makelist -h ${.CURDIR}/${hdr}.c > ${.TARGET}
|
||||
.endfor
|
||||
|
||||
fcns.h: ${AHDR} makelist
|
||||
sh ${.CURDIR}/makelist -fh ${AHDR} > ${.TARGET}
|
||||
|
||||
fcns.c: ${AHDR} fcns.h makelist
|
||||
sh ${.CURDIR}/makelist -fc ${AHDR} > ${.TARGET}
|
||||
|
||||
help.c: ${ASRC} makelist
|
||||
sh ${.CURDIR}/makelist -bc ${ASRC} > ${.TARGET}
|
||||
|
||||
help.h: ${ASRC} makelist
|
||||
sh ${.CURDIR}/makelist -bh ${ASRC} > ${.TARGET}
|
||||
|
||||
editline.c: ${OSRCS}
|
||||
sh ${.CURDIR}/makelist -e ${.ALLSRC:T} > ${.TARGET}
|
||||
|
||||
# minimal dependency to make "make depend" optional
|
||||
editline.o editline.po editline.So editline.ln: \
|
||||
common.h emacs.h fcns.c fcns.h help.c help.h vi.h
|
||||
|
||||
test.o: ${.CURDIR}/TEST/test.c
|
||||
|
||||
test: test.o libedit.a ${DPADD} ${LIBTERMCAP}
|
||||
${CC} ${CFLAGS} ${.ALLSRC} -o ${.TARGET} libedit.a ${LDADD}
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
@@ -0,0 +1,776 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: chared.c,v 1.25 2005/08/08 01:41:30 christos Exp $
|
||||
*/
|
||||
|
||||
#if !defined(lint) && !defined(SCCSID)
|
||||
static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* not lint && not SCCSID */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/chared.c,v 1.10 2005/08/09 13:31:59 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* chared.c: Character editor utilities
|
||||
*/
|
||||
#include "sys.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "el.h"
|
||||
|
||||
private void ch__clearmacro(EditLine *);
|
||||
|
||||
/* value to leave unused in line buffer */
|
||||
#define EL_LEAVE 2
|
||||
|
||||
/* cv_undo():
|
||||
* Handle state for the vi undo command
|
||||
*/
|
||||
protected void
|
||||
cv_undo(EditLine *el)
|
||||
{
|
||||
c_undo_t *vu = &el->el_chared.c_undo;
|
||||
c_redo_t *r = &el->el_chared.c_redo;
|
||||
unsigned int size;
|
||||
|
||||
/* Save entire line for undo */
|
||||
size = el->el_line.lastchar - el->el_line.buffer;
|
||||
vu->len = size;
|
||||
vu->cursor = el->el_line.cursor - el->el_line.buffer;
|
||||
memcpy(vu->buf, el->el_line.buffer, size);
|
||||
|
||||
/* save command info for redo */
|
||||
r->count = el->el_state.doingarg ? el->el_state.argument : 0;
|
||||
r->action = el->el_chared.c_vcmd.action;
|
||||
r->pos = r->buf;
|
||||
r->cmd = el->el_state.thiscmd;
|
||||
r->ch = el->el_state.thisch;
|
||||
}
|
||||
|
||||
/* cv_yank():
|
||||
* Save yank/delete data for paste
|
||||
*/
|
||||
protected void
|
||||
cv_yank(EditLine *el, const char *ptr, int size)
|
||||
{
|
||||
c_kill_t *k = &el->el_chared.c_kill;
|
||||
|
||||
memcpy(k->buf, ptr, size +0u);
|
||||
k->last = k->buf + size;
|
||||
}
|
||||
|
||||
|
||||
/* c_insert():
|
||||
* Insert num characters
|
||||
*/
|
||||
protected void
|
||||
c_insert(EditLine *el, int num)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (el->el_line.lastchar + num >= el->el_line.limit) {
|
||||
if (!ch_enlargebufs(el, num +0u))
|
||||
return; /* can't go past end of buffer */
|
||||
}
|
||||
|
||||
if (el->el_line.cursor < el->el_line.lastchar) {
|
||||
/* if I must move chars */
|
||||
for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
|
||||
cp[num] = *cp;
|
||||
}
|
||||
el->el_line.lastchar += num;
|
||||
}
|
||||
|
||||
|
||||
/* c_delafter():
|
||||
* Delete num characters after the cursor
|
||||
*/
|
||||
protected void
|
||||
c_delafter(EditLine *el, int num)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor + num > el->el_line.lastchar)
|
||||
num = el->el_line.lastchar - el->el_line.cursor;
|
||||
|
||||
if (el->el_map.current != el->el_map.emacs) {
|
||||
cv_undo(el);
|
||||
cv_yank(el, el->el_line.cursor, num);
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
char *cp;
|
||||
|
||||
for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
|
||||
*cp = cp[num];
|
||||
|
||||
el->el_line.lastchar -= num;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* c_delafter1():
|
||||
* Delete the character after the cursor, do not yank
|
||||
*/
|
||||
protected void
|
||||
c_delafter1(EditLine *el)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
|
||||
*cp = cp[1];
|
||||
|
||||
el->el_line.lastchar--;
|
||||
}
|
||||
|
||||
|
||||
/* c_delbefore():
|
||||
* Delete num characters before the cursor
|
||||
*/
|
||||
protected void
|
||||
c_delbefore(EditLine *el, int num)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor - num < el->el_line.buffer)
|
||||
num = el->el_line.cursor - el->el_line.buffer;
|
||||
|
||||
if (el->el_map.current != el->el_map.emacs) {
|
||||
cv_undo(el);
|
||||
cv_yank(el, el->el_line.cursor - num, num);
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
char *cp;
|
||||
|
||||
for (cp = el->el_line.cursor - num;
|
||||
cp <= el->el_line.lastchar;
|
||||
cp++)
|
||||
*cp = cp[num];
|
||||
|
||||
el->el_line.lastchar -= num;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* c_delbefore1():
|
||||
* Delete the character before the cursor, do not yank
|
||||
*/
|
||||
protected void
|
||||
c_delbefore1(EditLine *el)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
|
||||
*cp = cp[1];
|
||||
|
||||
el->el_line.lastchar--;
|
||||
}
|
||||
|
||||
|
||||
/* ce__isword():
|
||||
* Return if p is part of a word according to emacs
|
||||
*/
|
||||
protected int
|
||||
ce__isword(int p)
|
||||
{
|
||||
return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL);
|
||||
}
|
||||
|
||||
|
||||
/* cv__isword():
|
||||
* Return if p is part of a word according to vi
|
||||
*/
|
||||
protected int
|
||||
cv__isword(int p)
|
||||
{
|
||||
if (isalnum(p) || p == '_')
|
||||
return 1;
|
||||
if (isgraph(p))
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* cv__isWord():
|
||||
* Return if p is part of a big word according to vi
|
||||
*/
|
||||
protected int
|
||||
cv__isWord(int p)
|
||||
{
|
||||
return (!isspace(p));
|
||||
}
|
||||
|
||||
|
||||
/* c__prev_word():
|
||||
* Find the previous word
|
||||
*/
|
||||
protected char *
|
||||
c__prev_word(char *p, char *low, int n, int (*wtest)(int))
|
||||
{
|
||||
p--;
|
||||
|
||||
while (n--) {
|
||||
while ((p >= low) && !(*wtest)((unsigned char) *p))
|
||||
p--;
|
||||
while ((p >= low) && (*wtest)((unsigned char) *p))
|
||||
p--;
|
||||
}
|
||||
|
||||
/* cp now points to one character before the word */
|
||||
p++;
|
||||
if (p < low)
|
||||
p = low;
|
||||
/* cp now points where we want it */
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
/* c__next_word():
|
||||
* Find the next word
|
||||
*/
|
||||
protected char *
|
||||
c__next_word(char *p, char *high, int n, int (*wtest)(int))
|
||||
{
|
||||
while (n--) {
|
||||
while ((p < high) && !(*wtest)((unsigned char) *p))
|
||||
p++;
|
||||
while ((p < high) && (*wtest)((unsigned char) *p))
|
||||
p++;
|
||||
}
|
||||
if (p > high)
|
||||
p = high;
|
||||
/* p now points where we want it */
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* cv_next_word():
|
||||
* Find the next word vi style
|
||||
*/
|
||||
protected char *
|
||||
cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
|
||||
{
|
||||
int test;
|
||||
|
||||
while (n--) {
|
||||
test = (*wtest)((unsigned char) *p);
|
||||
while ((p < high) && (*wtest)((unsigned char) *p) == test)
|
||||
p++;
|
||||
/*
|
||||
* vi historically deletes with cw only the word preserving the
|
||||
* trailing whitespace! This is not what 'w' does..
|
||||
*/
|
||||
if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
|
||||
while ((p < high) && isspace((unsigned char) *p))
|
||||
p++;
|
||||
}
|
||||
|
||||
/* p now points where we want it */
|
||||
if (p > high)
|
||||
return (high);
|
||||
else
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
/* cv_prev_word():
|
||||
* Find the previous word vi style
|
||||
*/
|
||||
protected char *
|
||||
cv_prev_word(char *p, char *low, int n, int (*wtest)(int))
|
||||
{
|
||||
int test;
|
||||
|
||||
p--;
|
||||
while (n--) {
|
||||
while ((p > low) && isspace((unsigned char) *p))
|
||||
p--;
|
||||
test = (*wtest)((unsigned char) *p);
|
||||
while ((p >= low) && (*wtest)((unsigned char) *p) == test)
|
||||
p--;
|
||||
}
|
||||
p++;
|
||||
|
||||
/* p now points where we want it */
|
||||
if (p < low)
|
||||
return (low);
|
||||
else
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
#ifdef notdef
|
||||
/* c__number():
|
||||
* Ignore character p points to, return number appearing after that.
|
||||
* A '$' by itself means a big number; "$-" is for negative; '^' means 1.
|
||||
* Return p pointing to last char used.
|
||||
*/
|
||||
protected char *
|
||||
c__number(
|
||||
char *p, /* character position */
|
||||
int *num, /* Return value */
|
||||
int dval) /* dval is the number to subtract from like $-3 */
|
||||
{
|
||||
int i;
|
||||
int sign = 1;
|
||||
|
||||
if (*++p == '^') {
|
||||
*num = 1;
|
||||
return (p);
|
||||
}
|
||||
if (*p == '$') {
|
||||
if (*++p != '-') {
|
||||
*num = 0x7fffffff; /* Handle $ */
|
||||
return (--p);
|
||||
}
|
||||
sign = -1; /* Handle $- */
|
||||
++p;
|
||||
}
|
||||
for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
|
||||
continue;
|
||||
*num = (sign < 0 ? dval - i : i);
|
||||
return (--p);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* cv_delfini():
|
||||
* Finish vi delete action
|
||||
*/
|
||||
protected void
|
||||
cv_delfini(EditLine *el)
|
||||
{
|
||||
int size;
|
||||
int action = el->el_chared.c_vcmd.action;
|
||||
|
||||
if (action & INSERT)
|
||||
el->el_map.current = el->el_map.key;
|
||||
|
||||
if (el->el_chared.c_vcmd.pos == 0)
|
||||
/* sanity */
|
||||
return;
|
||||
|
||||
size = el->el_line.cursor - el->el_chared.c_vcmd.pos;
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
el->el_line.cursor = el->el_chared.c_vcmd.pos;
|
||||
if (action & YANK) {
|
||||
if (size > 0)
|
||||
cv_yank(el, el->el_line.cursor, size);
|
||||
else
|
||||
cv_yank(el, el->el_line.cursor + size, -size);
|
||||
} else {
|
||||
if (size > 0) {
|
||||
c_delafter(el, size);
|
||||
re_refresh_cursor(el);
|
||||
} else {
|
||||
c_delbefore(el, -size);
|
||||
el->el_line.cursor += size;
|
||||
}
|
||||
}
|
||||
el->el_chared.c_vcmd.action = NOP;
|
||||
}
|
||||
|
||||
|
||||
#ifdef notdef
|
||||
/* ce__endword():
|
||||
* Go to the end of this word according to emacs
|
||||
*/
|
||||
protected char *
|
||||
ce__endword(char *p, char *high, int n)
|
||||
{
|
||||
p++;
|
||||
|
||||
while (n--) {
|
||||
while ((p < high) && isspace((unsigned char) *p))
|
||||
p++;
|
||||
while ((p < high) && !isspace((unsigned char) *p))
|
||||
p++;
|
||||
}
|
||||
|
||||
p--;
|
||||
return (p);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* cv__endword():
|
||||
* Go to the end of this word according to vi
|
||||
*/
|
||||
protected char *
|
||||
cv__endword(char *p, char *high, int n, int (*wtest)(int))
|
||||
{
|
||||
int test;
|
||||
|
||||
p++;
|
||||
|
||||
while (n--) {
|
||||
while ((p < high) && isspace((unsigned char) *p))
|
||||
p++;
|
||||
|
||||
test = (*wtest)((unsigned char) *p);
|
||||
while ((p < high) && (*wtest)((unsigned char) *p) == test)
|
||||
p++;
|
||||
}
|
||||
p--;
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* ch_init():
|
||||
* Initialize the character editor
|
||||
*/
|
||||
protected int
|
||||
ch_init(EditLine *el)
|
||||
{
|
||||
c_macro_t *ma = &el->el_chared.c_macro;
|
||||
|
||||
el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ);
|
||||
if (el->el_line.buffer == NULL)
|
||||
return (-1);
|
||||
|
||||
(void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
el->el_line.lastchar = el->el_line.buffer;
|
||||
el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
|
||||
|
||||
el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ);
|
||||
if (el->el_chared.c_undo.buf == NULL)
|
||||
return (-1);
|
||||
(void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
|
||||
el->el_chared.c_undo.len = -1;
|
||||
el->el_chared.c_undo.cursor = 0;
|
||||
el->el_chared.c_redo.buf = (char *) el_malloc(EL_BUFSIZ);
|
||||
if (el->el_chared.c_redo.buf == NULL)
|
||||
return (-1);
|
||||
el->el_chared.c_redo.pos = el->el_chared.c_redo.buf;
|
||||
el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ;
|
||||
el->el_chared.c_redo.cmd = ED_UNASSIGNED;
|
||||
|
||||
el->el_chared.c_vcmd.action = NOP;
|
||||
el->el_chared.c_vcmd.pos = el->el_line.buffer;
|
||||
|
||||
el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ);
|
||||
if (el->el_chared.c_kill.buf == NULL)
|
||||
return (-1);
|
||||
(void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
|
||||
el->el_chared.c_kill.mark = el->el_line.buffer;
|
||||
el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
|
||||
|
||||
el->el_map.current = el->el_map.key;
|
||||
|
||||
el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
|
||||
el->el_state.doingarg = 0;
|
||||
el->el_state.metanext = 0;
|
||||
el->el_state.argument = 1;
|
||||
el->el_state.lastcmd = ED_UNASSIGNED;
|
||||
|
||||
ma->level = -1;
|
||||
ma->offset = 0;
|
||||
ma->macro = (char **) el_malloc(EL_MAXMACRO * sizeof(char *));
|
||||
if (ma->macro == NULL)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ch_reset():
|
||||
* Reset the character editor
|
||||
*/
|
||||
protected void
|
||||
ch_reset(EditLine *el, int mclear)
|
||||
{
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
el->el_line.lastchar = el->el_line.buffer;
|
||||
|
||||
el->el_chared.c_undo.len = -1;
|
||||
el->el_chared.c_undo.cursor = 0;
|
||||
|
||||
el->el_chared.c_vcmd.action = NOP;
|
||||
el->el_chared.c_vcmd.pos = el->el_line.buffer;
|
||||
|
||||
el->el_chared.c_kill.mark = el->el_line.buffer;
|
||||
|
||||
el->el_map.current = el->el_map.key;
|
||||
|
||||
el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
|
||||
el->el_state.doingarg = 0;
|
||||
el->el_state.metanext = 0;
|
||||
el->el_state.argument = 1;
|
||||
el->el_state.lastcmd = ED_UNASSIGNED;
|
||||
|
||||
el->el_history.eventno = 0;
|
||||
|
||||
if (mclear)
|
||||
ch__clearmacro(el);
|
||||
}
|
||||
|
||||
private void
|
||||
ch__clearmacro(el)
|
||||
EditLine *el;
|
||||
{
|
||||
c_macro_t *ma = &el->el_chared.c_macro;
|
||||
while (ma->level >= 0)
|
||||
el_free((ptr_t)ma->macro[ma->level--]);
|
||||
}
|
||||
|
||||
/* ch_enlargebufs():
|
||||
* Enlarge line buffer to be able to hold twice as much characters.
|
||||
* Returns 1 if successful, 0 if not.
|
||||
*/
|
||||
protected int
|
||||
ch_enlargebufs(el, addlen)
|
||||
EditLine *el;
|
||||
size_t addlen;
|
||||
{
|
||||
size_t sz, newsz;
|
||||
char *newbuffer, *oldbuf, *oldkbuf;
|
||||
|
||||
sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
|
||||
newsz = sz * 2;
|
||||
/*
|
||||
* If newly required length is longer than current buffer, we need
|
||||
* to make the buffer big enough to hold both old and new stuff.
|
||||
*/
|
||||
if (addlen > sz) {
|
||||
while(newsz - sz < addlen)
|
||||
newsz *= 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reallocate line buffer.
|
||||
*/
|
||||
newbuffer = el_realloc(el->el_line.buffer, newsz);
|
||||
if (!newbuffer)
|
||||
return 0;
|
||||
|
||||
/* zero the newly added memory, leave old data in */
|
||||
(void) memset(&newbuffer[sz], 0, newsz - sz);
|
||||
|
||||
oldbuf = el->el_line.buffer;
|
||||
|
||||
el->el_line.buffer = newbuffer;
|
||||
el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
|
||||
el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
|
||||
/* don't set new size until all buffers are enlarged */
|
||||
el->el_line.limit = &newbuffer[sz - EL_LEAVE];
|
||||
|
||||
/*
|
||||
* Reallocate kill buffer.
|
||||
*/
|
||||
newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
|
||||
if (!newbuffer)
|
||||
return 0;
|
||||
|
||||
/* zero the newly added memory, leave old data in */
|
||||
(void) memset(&newbuffer[sz], 0, newsz - sz);
|
||||
|
||||
oldkbuf = el->el_chared.c_kill.buf;
|
||||
|
||||
el->el_chared.c_kill.buf = newbuffer;
|
||||
el->el_chared.c_kill.last = newbuffer +
|
||||
(el->el_chared.c_kill.last - oldkbuf);
|
||||
el->el_chared.c_kill.mark = el->el_line.buffer +
|
||||
(el->el_chared.c_kill.mark - oldbuf);
|
||||
|
||||
/*
|
||||
* Reallocate undo buffer.
|
||||
*/
|
||||
newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
|
||||
if (!newbuffer)
|
||||
return 0;
|
||||
|
||||
/* zero the newly added memory, leave old data in */
|
||||
(void) memset(&newbuffer[sz], 0, newsz - sz);
|
||||
el->el_chared.c_undo.buf = newbuffer;
|
||||
|
||||
newbuffer = el_realloc(el->el_chared.c_redo.buf, newsz);
|
||||
if (!newbuffer)
|
||||
return 0;
|
||||
el->el_chared.c_redo.pos = newbuffer +
|
||||
(el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
|
||||
el->el_chared.c_redo.lim = newbuffer +
|
||||
(el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
|
||||
el->el_chared.c_redo.buf = newbuffer;
|
||||
|
||||
if (!hist_enlargebuf(el, sz, newsz))
|
||||
return 0;
|
||||
|
||||
/* Safe to set enlarged buffer size */
|
||||
el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ch_end():
|
||||
* Free the data structures used by the editor
|
||||
*/
|
||||
protected void
|
||||
ch_end(EditLine *el)
|
||||
{
|
||||
el_free((ptr_t) el->el_line.buffer);
|
||||
el->el_line.buffer = NULL;
|
||||
el->el_line.limit = NULL;
|
||||
el_free((ptr_t) el->el_chared.c_undo.buf);
|
||||
el->el_chared.c_undo.buf = NULL;
|
||||
el_free((ptr_t) el->el_chared.c_redo.buf);
|
||||
el->el_chared.c_redo.buf = NULL;
|
||||
el->el_chared.c_redo.pos = NULL;
|
||||
el->el_chared.c_redo.lim = NULL;
|
||||
el->el_chared.c_redo.cmd = ED_UNASSIGNED;
|
||||
el_free((ptr_t) el->el_chared.c_kill.buf);
|
||||
el->el_chared.c_kill.buf = NULL;
|
||||
ch_reset(el, 1);
|
||||
el_free((ptr_t) el->el_chared.c_macro.macro);
|
||||
el->el_chared.c_macro.macro = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* el_insertstr():
|
||||
* Insert string at cursorI
|
||||
*/
|
||||
public int
|
||||
el_insertstr(EditLine *el, const char *s)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if ((len = strlen(s)) == 0)
|
||||
return (-1);
|
||||
if (el->el_line.lastchar + len >= el->el_line.limit) {
|
||||
if (!ch_enlargebufs(el, len))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
c_insert(el, (int)len);
|
||||
while (*s)
|
||||
*el->el_line.cursor++ = *s++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* el_deletestr():
|
||||
* Delete num characters before the cursor
|
||||
*/
|
||||
public void
|
||||
el_deletestr(EditLine *el, int n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return;
|
||||
|
||||
if (el->el_line.cursor < &el->el_line.buffer[n])
|
||||
return;
|
||||
|
||||
c_delbefore(el, n); /* delete before dot */
|
||||
el->el_line.cursor -= n;
|
||||
if (el->el_line.cursor < el->el_line.buffer)
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
}
|
||||
|
||||
/* c_gets():
|
||||
* Get a string
|
||||
*/
|
||||
protected int
|
||||
c_gets(EditLine *el, char *buf, const char *prompt)
|
||||
{
|
||||
char ch;
|
||||
int len;
|
||||
char *cp = el->el_line.buffer;
|
||||
|
||||
if (prompt) {
|
||||
len = strlen(prompt);
|
||||
memcpy(cp, prompt, len + 0u);
|
||||
cp += len;
|
||||
}
|
||||
len = 0;
|
||||
|
||||
for (;;) {
|
||||
el->el_line.cursor = cp;
|
||||
*cp = ' ';
|
||||
el->el_line.lastchar = cp + 1;
|
||||
re_refresh(el);
|
||||
|
||||
if (el_getc(el, &ch) != 1) {
|
||||
ed_end_of_file(el, 0);
|
||||
len = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
|
||||
case '\010': /* Delete and backspace */
|
||||
case '\177':
|
||||
if (len <= 0) {
|
||||
len = -1;
|
||||
break;
|
||||
}
|
||||
cp--;
|
||||
continue;
|
||||
|
||||
case '\033': /* ESC */
|
||||
case '\r': /* Newline */
|
||||
case '\n':
|
||||
buf[len] = ch;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (len >= EL_BUFSIZ - 16)
|
||||
term_beep(el);
|
||||
else {
|
||||
buf[len++] = ch;
|
||||
*cp++ = ch;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
el->el_line.buffer[0] = '\0';
|
||||
el->el_line.lastchar = el->el_line.buffer;
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* c_hpos():
|
||||
* Return the current horizontal position of the cursor
|
||||
*/
|
||||
protected int
|
||||
c_hpos(EditLine *el)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
/*
|
||||
* Find how many characters till the beginning of this line.
|
||||
*/
|
||||
if (el->el_line.cursor == el->el_line.buffer)
|
||||
return (0);
|
||||
else {
|
||||
for (ptr = el->el_line.cursor - 1;
|
||||
ptr >= el->el_line.buffer && *ptr != '\n';
|
||||
ptr--)
|
||||
continue;
|
||||
return (el->el_line.cursor - ptr - 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)chared.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: chared.h,v 1.16 2005/08/08 14:05:37 christos Exp $
|
||||
* $FreeBSD: src/lib/libedit/chared.h,v 1.8 2005/08/09 13:37:59 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.chared.h: Character editor interface
|
||||
*/
|
||||
#ifndef _h_el_chared
|
||||
#define _h_el_chared
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "histedit.h"
|
||||
|
||||
#define EL_MAXMACRO 10
|
||||
|
||||
/*
|
||||
* This is an issue of basic "vi" look-and-feel. Defining VI_MOVE works
|
||||
* like real vi: i.e. the transition from command<->insert modes moves
|
||||
* the cursor.
|
||||
*
|
||||
* On the other hand we really don't want to move the cursor, because
|
||||
* all the editing commands don't include the character under the cursor.
|
||||
* Probably the best fix is to make all the editing commands aware of
|
||||
* this fact.
|
||||
*/
|
||||
#define VI_MOVE
|
||||
|
||||
|
||||
typedef struct c_macro_t {
|
||||
int level;
|
||||
int offset;
|
||||
char **macro;
|
||||
} c_macro_t;
|
||||
|
||||
/*
|
||||
* Undo information for vi - no undo in emacs (yet)
|
||||
*/
|
||||
typedef struct c_undo_t {
|
||||
int len; /* length of saved line */
|
||||
int cursor; /* position of saved cursor */
|
||||
char *buf; /* full saved text */
|
||||
} c_undo_t;
|
||||
|
||||
/* redo for vi */
|
||||
typedef struct c_redo_t {
|
||||
char *buf; /* redo insert key sequence */
|
||||
char *pos;
|
||||
char *lim;
|
||||
el_action_t cmd; /* command to redo */
|
||||
char ch; /* char that invoked it */
|
||||
int count;
|
||||
int action; /* from cv_action() */
|
||||
} c_redo_t;
|
||||
|
||||
/*
|
||||
* Current action information for vi
|
||||
*/
|
||||
typedef struct c_vcmd_t {
|
||||
int action;
|
||||
char *pos;
|
||||
} c_vcmd_t;
|
||||
|
||||
/*
|
||||
* Kill buffer for emacs
|
||||
*/
|
||||
typedef struct c_kill_t {
|
||||
char *buf;
|
||||
char *last;
|
||||
char *mark;
|
||||
} c_kill_t;
|
||||
|
||||
/*
|
||||
* Note that we use both data structures because the user can bind
|
||||
* commands from both editors!
|
||||
*/
|
||||
typedef struct el_chared_t {
|
||||
c_undo_t c_undo;
|
||||
c_kill_t c_kill;
|
||||
c_redo_t c_redo;
|
||||
c_vcmd_t c_vcmd;
|
||||
c_macro_t c_macro;
|
||||
} el_chared_t;
|
||||
|
||||
|
||||
#define STReof "^D\b\b"
|
||||
#define STRQQ "\"\""
|
||||
|
||||
#define isglob(a) (strchr("*[]?", (a)) != NULL)
|
||||
#define isword(a) (isprint(a))
|
||||
|
||||
#define NOP 0x00
|
||||
#define DELETE 0x01
|
||||
#define INSERT 0x02
|
||||
#define YANK 0x04
|
||||
|
||||
#define CHAR_FWD (+1)
|
||||
#define CHAR_BACK (-1)
|
||||
|
||||
#define MODE_INSERT 0
|
||||
#define MODE_REPLACE 1
|
||||
#define MODE_REPLACE_1 2
|
||||
|
||||
#include "common.h"
|
||||
#include "vi.h"
|
||||
#include "emacs.h"
|
||||
#include "search.h"
|
||||
#include "fcns.h"
|
||||
|
||||
|
||||
protected int cv__isword(int);
|
||||
protected int cv__isWord(int);
|
||||
protected void cv_delfini(EditLine *);
|
||||
protected char *cv__endword(char *, char *, int, int (*)(int));
|
||||
protected int ce__isword(int);
|
||||
protected void cv_undo(EditLine *);
|
||||
protected void cv_yank(EditLine *, const char *, int);
|
||||
protected char *cv_next_word(EditLine*, char *, char *, int, int (*)(int));
|
||||
protected char *cv_prev_word(char *, char *, int, int (*)(int));
|
||||
protected char *c__next_word(char *, char *, int, int (*)(int));
|
||||
protected char *c__prev_word(char *, char *, int, int (*)(int));
|
||||
protected void c_insert(EditLine *, int);
|
||||
protected void c_delbefore(EditLine *, int);
|
||||
protected void c_delbefore1(EditLine *);
|
||||
protected void c_delafter(EditLine *, int);
|
||||
protected void c_delafter1(EditLine *);
|
||||
protected int c_gets(EditLine *, char *, const char *);
|
||||
protected int c_hpos(EditLine *);
|
||||
|
||||
protected int ch_init(EditLine *);
|
||||
protected void ch_reset(EditLine *, int);
|
||||
protected int ch_enlargebufs(EditLine *, size_t);
|
||||
protected void ch_end(EditLine *);
|
||||
|
||||
#endif /* _h_el_chared */
|
||||
@@ -0,0 +1,920 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: common.c,v 1.18 2005/08/08 14:05:37 christos Exp $
|
||||
*/
|
||||
|
||||
#if !defined(lint) && !defined(SCCSID)
|
||||
static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* not lint && not SCCSID */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/common.c,v 1.11 2005/08/09 13:37:59 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* common.c: Common Editor functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include "el.h"
|
||||
|
||||
/* ed_end_of_file():
|
||||
* Indicate end of file
|
||||
* [^D]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_end_of_file(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
re_goto_bottom(el);
|
||||
*el->el_line.lastchar = '\0';
|
||||
return (CC_EOF);
|
||||
}
|
||||
|
||||
|
||||
/* ed_insert():
|
||||
* Add character to the line
|
||||
* Insert a character [bound to all insert keys]
|
||||
*/
|
||||
protected el_action_t
|
||||
ed_insert(EditLine *el, int c)
|
||||
{
|
||||
int count = el->el_state.argument;
|
||||
|
||||
if (c == '\0')
|
||||
return (CC_ERROR);
|
||||
|
||||
if (el->el_line.lastchar + el->el_state.argument >=
|
||||
el->el_line.limit) {
|
||||
/* end of buffer space, try to allocate more */
|
||||
if (!ch_enlargebufs(el, (size_t) count))
|
||||
return CC_ERROR; /* error allocating more */
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
if (el->el_state.inputmode == MODE_INSERT
|
||||
|| el->el_line.cursor >= el->el_line.lastchar)
|
||||
c_insert(el, 1);
|
||||
|
||||
*el->el_line.cursor++ = c;
|
||||
re_fastaddc(el); /* fast refresh for one char. */
|
||||
} else {
|
||||
if (el->el_state.inputmode != MODE_REPLACE_1)
|
||||
c_insert(el, el->el_state.argument);
|
||||
|
||||
while (count-- && el->el_line.cursor < el->el_line.lastchar)
|
||||
*el->el_line.cursor++ = c;
|
||||
re_refresh(el);
|
||||
}
|
||||
|
||||
if (el->el_state.inputmode == MODE_REPLACE_1)
|
||||
return vi_command_mode(el, 0);
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_delete_prev_word():
|
||||
* Delete from beginning of current word to cursor
|
||||
* [M-^?] [^W]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_delete_prev_word(EditLine *el, int c __unused)
|
||||
{
|
||||
char *cp, *p, *kp;
|
||||
|
||||
if (el->el_line.cursor == el->el_line.buffer)
|
||||
return (CC_ERROR);
|
||||
|
||||
cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
|
||||
el->el_state.argument, ce__isword);
|
||||
|
||||
for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
|
||||
*kp++ = *p;
|
||||
el->el_chared.c_kill.last = kp;
|
||||
|
||||
c_delbefore(el, el->el_line.cursor - cp); /* delete before dot */
|
||||
el->el_line.cursor = cp;
|
||||
if (el->el_line.cursor < el->el_line.buffer)
|
||||
el->el_line.cursor = el->el_line.buffer; /* bounds check */
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* ed_delete_next_char():
|
||||
* Delete character under cursor
|
||||
* [^D] [x]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_delete_next_char(EditLine *el, int c __unused)
|
||||
{
|
||||
#ifdef notdef /* XXX */
|
||||
#define EL el->el_line
|
||||
(void) fprintf(el->el_errlfile,
|
||||
"\nD(b: %x(%s) c: %x(%s) last: %x(%s) limit: %x(%s)\n",
|
||||
EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
|
||||
EL.lastchar, EL.limit, EL.limit);
|
||||
#endif
|
||||
if (el->el_line.cursor == el->el_line.lastchar) {
|
||||
/* if I'm at the end */
|
||||
if (el->el_map.type == MAP_VI) {
|
||||
if (el->el_line.cursor == el->el_line.buffer) {
|
||||
/* if I'm also at the beginning */
|
||||
#ifdef KSHVI
|
||||
return (CC_ERROR);
|
||||
#else
|
||||
term_overwrite(el, STReof, 4);
|
||||
/* then do an EOF */
|
||||
term__flush();
|
||||
return (CC_EOF);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef KSHVI
|
||||
el->el_line.cursor--;
|
||||
#else
|
||||
return (CC_ERROR);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (el->el_line.cursor != el->el_line.buffer)
|
||||
el->el_line.cursor--;
|
||||
else
|
||||
return (CC_ERROR);
|
||||
}
|
||||
}
|
||||
c_delafter(el, el->el_state.argument); /* delete after dot */
|
||||
if (el->el_line.cursor >= el->el_line.lastchar &&
|
||||
el->el_line.cursor > el->el_line.buffer)
|
||||
/* bounds check */
|
||||
el->el_line.cursor = el->el_line.lastchar - 1;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* ed_kill_line():
|
||||
* Cut to the end of line
|
||||
* [^K] [^K]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_kill_line(EditLine *el, int c __unused)
|
||||
{
|
||||
char *kp, *cp;
|
||||
|
||||
cp = el->el_line.cursor;
|
||||
kp = el->el_chared.c_kill.buf;
|
||||
while (cp < el->el_line.lastchar)
|
||||
*kp++ = *cp++; /* copy it */
|
||||
el->el_chared.c_kill.last = kp;
|
||||
/* zap! -- delete to end */
|
||||
el->el_line.lastchar = el->el_line.cursor;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* ed_move_to_end():
|
||||
* Move cursor to the end of line
|
||||
* [^E] [^E]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_move_to_end(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
if (el->el_map.type == MAP_VI) {
|
||||
#ifdef VI_MOVE
|
||||
el->el_line.cursor--;
|
||||
#endif
|
||||
if (el->el_chared.c_vcmd.action != NOP) {
|
||||
cv_delfini(el);
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
}
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_move_to_beg():
|
||||
* Move cursor to the beginning of line
|
||||
* [^A] [^A]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_move_to_beg(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
|
||||
if (el->el_map.type == MAP_VI) {
|
||||
/* We want FIRST non space character */
|
||||
while (isspace((unsigned char) *el->el_line.cursor))
|
||||
el->el_line.cursor++;
|
||||
if (el->el_chared.c_vcmd.action != NOP) {
|
||||
cv_delfini(el);
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
}
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_transpose_chars():
|
||||
* Exchange the character to the left of the cursor with the one under it
|
||||
* [^T] [^T]
|
||||
*/
|
||||
protected el_action_t
|
||||
ed_transpose_chars(EditLine *el, int c)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor < el->el_line.lastchar) {
|
||||
if (el->el_line.lastchar <= &el->el_line.buffer[1])
|
||||
return (CC_ERROR);
|
||||
else
|
||||
el->el_line.cursor++;
|
||||
}
|
||||
if (el->el_line.cursor > &el->el_line.buffer[1]) {
|
||||
/* must have at least two chars entered */
|
||||
c = el->el_line.cursor[-2];
|
||||
el->el_line.cursor[-2] = el->el_line.cursor[-1];
|
||||
el->el_line.cursor[-1] = c;
|
||||
return (CC_REFRESH);
|
||||
} else
|
||||
return (CC_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_next_char():
|
||||
* Move to the right one character
|
||||
* [^F] [^F]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_next_char(EditLine *el, int c __unused)
|
||||
{
|
||||
char *lim = el->el_line.lastchar;
|
||||
|
||||
if (el->el_line.cursor >= lim ||
|
||||
(el->el_line.cursor == lim - 1 &&
|
||||
el->el_map.type == MAP_VI &&
|
||||
el->el_chared.c_vcmd.action == NOP))
|
||||
return (CC_ERROR);
|
||||
|
||||
el->el_line.cursor += el->el_state.argument;
|
||||
if (el->el_line.cursor > lim)
|
||||
el->el_line.cursor = lim;
|
||||
|
||||
if (el->el_map.type == MAP_VI)
|
||||
if (el->el_chared.c_vcmd.action != NOP) {
|
||||
cv_delfini(el);
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_prev_word():
|
||||
* Move to the beginning of the current word
|
||||
* [M-b] [b]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_prev_word(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor == el->el_line.buffer)
|
||||
return (CC_ERROR);
|
||||
|
||||
el->el_line.cursor = c__prev_word(el->el_line.cursor,
|
||||
el->el_line.buffer,
|
||||
el->el_state.argument,
|
||||
ce__isword);
|
||||
|
||||
if (el->el_map.type == MAP_VI)
|
||||
if (el->el_chared.c_vcmd.action != NOP) {
|
||||
cv_delfini(el);
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_prev_char():
|
||||
* Move to the left one character
|
||||
* [^B] [^B]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_prev_char(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor > el->el_line.buffer) {
|
||||
el->el_line.cursor -= el->el_state.argument;
|
||||
if (el->el_line.cursor < el->el_line.buffer)
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
|
||||
if (el->el_map.type == MAP_VI)
|
||||
if (el->el_chared.c_vcmd.action != NOP) {
|
||||
cv_delfini(el);
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
return (CC_CURSOR);
|
||||
} else
|
||||
return (CC_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_quoted_insert():
|
||||
* Add the next character typed verbatim
|
||||
* [^V] [^V]
|
||||
*/
|
||||
protected el_action_t
|
||||
ed_quoted_insert(EditLine *el, int c)
|
||||
{
|
||||
int num;
|
||||
char tc;
|
||||
|
||||
tty_quotemode(el);
|
||||
num = el_getc(el, &tc);
|
||||
c = (unsigned char) tc;
|
||||
tty_noquotemode(el);
|
||||
if (num == 1)
|
||||
return (ed_insert(el, c));
|
||||
else
|
||||
return (ed_end_of_file(el, 0));
|
||||
}
|
||||
|
||||
|
||||
/* ed_digit():
|
||||
* Adds to argument or enters a digit
|
||||
*/
|
||||
protected el_action_t
|
||||
ed_digit(EditLine *el, int c)
|
||||
{
|
||||
|
||||
if (!isdigit((unsigned char) c))
|
||||
return (CC_ERROR);
|
||||
|
||||
if (el->el_state.doingarg) {
|
||||
/* if doing an arg, add this in... */
|
||||
if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
|
||||
el->el_state.argument = c - '0';
|
||||
else {
|
||||
if (el->el_state.argument > 1000000)
|
||||
return (CC_ERROR);
|
||||
el->el_state.argument =
|
||||
(el->el_state.argument * 10) + (c - '0');
|
||||
}
|
||||
return (CC_ARGHACK);
|
||||
}
|
||||
|
||||
return ed_insert(el, c);
|
||||
}
|
||||
|
||||
|
||||
/* ed_argument_digit():
|
||||
* Digit that starts argument
|
||||
* For ESC-n
|
||||
*/
|
||||
protected el_action_t
|
||||
ed_argument_digit(EditLine *el, int c)
|
||||
{
|
||||
|
||||
if (!isdigit((unsigned char) c))
|
||||
return (CC_ERROR);
|
||||
|
||||
if (el->el_state.doingarg) {
|
||||
if (el->el_state.argument > 1000000)
|
||||
return (CC_ERROR);
|
||||
el->el_state.argument = (el->el_state.argument * 10) +
|
||||
(c - '0');
|
||||
} else { /* else starting an argument */
|
||||
el->el_state.argument = c - '0';
|
||||
el->el_state.doingarg = 1;
|
||||
}
|
||||
return (CC_ARGHACK);
|
||||
}
|
||||
|
||||
|
||||
/* ed_unassigned():
|
||||
* Indicates unbound character
|
||||
* Bound to keys that are not assigned
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_unassigned(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
return (CC_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** TTY key handling.
|
||||
**/
|
||||
|
||||
/* ed_tty_sigint():
|
||||
* Tty interrupt character
|
||||
* [^C]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_tty_sigint(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_tty_dsusp():
|
||||
* Tty delayed suspend character
|
||||
* [^Y]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_tty_dsusp(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_tty_flush_output():
|
||||
* Tty flush output characters
|
||||
* [^O]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_tty_flush_output(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_tty_sigquit():
|
||||
* Tty quit character
|
||||
* [^\]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_tty_sigquit(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_tty_sigtstp():
|
||||
* Tty suspend character
|
||||
* [^Z]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_tty_sigtstp(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_tty_stop_output():
|
||||
* Tty disallow output characters
|
||||
* [^S]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_tty_stop_output(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_tty_start_output():
|
||||
* Tty allow output characters
|
||||
* [^Q]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_tty_start_output(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_newline():
|
||||
* Execute command
|
||||
* [^J]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_newline(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
re_goto_bottom(el);
|
||||
*el->el_line.lastchar++ = '\n';
|
||||
*el->el_line.lastchar = '\0';
|
||||
return (CC_NEWLINE);
|
||||
}
|
||||
|
||||
|
||||
/* ed_delete_prev_char():
|
||||
* Delete the character to the left of the cursor
|
||||
* [^?]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_delete_prev_char(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor <= el->el_line.buffer)
|
||||
return (CC_ERROR);
|
||||
|
||||
c_delbefore(el, el->el_state.argument);
|
||||
el->el_line.cursor -= el->el_state.argument;
|
||||
if (el->el_line.cursor < el->el_line.buffer)
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* ed_clear_screen():
|
||||
* Clear screen leaving current line at the top
|
||||
* [^L]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_clear_screen(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
term_clear_screen(el); /* clear the whole real screen */
|
||||
re_clear_display(el); /* reset everything */
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* ed_redisplay():
|
||||
* Redisplay everything
|
||||
* ^R
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_redisplay(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_REDISPLAY);
|
||||
}
|
||||
|
||||
|
||||
/* ed_start_over():
|
||||
* Erase current line and start from scratch
|
||||
* [^G]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_start_over(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
ch_reset(el, 0);
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* ed_sequence_lead_in():
|
||||
* First character in a bound sequence
|
||||
* Placeholder for external keys
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_sequence_lead_in(EditLine *el __unused,
|
||||
int c __unused)
|
||||
{
|
||||
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* ed_prev_history():
|
||||
* Move to the previous history line
|
||||
* [^P] [k]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_prev_history(EditLine *el, int c __unused)
|
||||
{
|
||||
char beep = 0;
|
||||
int sv_event = el->el_history.eventno;
|
||||
|
||||
el->el_chared.c_undo.len = -1;
|
||||
*el->el_line.lastchar = '\0'; /* just in case */
|
||||
|
||||
if (el->el_history.eventno == 0) { /* save the current buffer
|
||||
* away */
|
||||
(void) strncpy(el->el_history.buf, el->el_line.buffer,
|
||||
EL_BUFSIZ);
|
||||
el->el_history.last = el->el_history.buf +
|
||||
(el->el_line.lastchar - el->el_line.buffer);
|
||||
}
|
||||
el->el_history.eventno += el->el_state.argument;
|
||||
|
||||
if (hist_get(el) == CC_ERROR) {
|
||||
if (el->el_map.type == MAP_VI) {
|
||||
el->el_history.eventno = sv_event;
|
||||
return CC_ERROR;
|
||||
}
|
||||
beep = 1;
|
||||
/* el->el_history.eventno was fixed by first call */
|
||||
(void) hist_get(el);
|
||||
}
|
||||
if (beep)
|
||||
return CC_REFRESH_BEEP;
|
||||
return CC_REFRESH;
|
||||
}
|
||||
|
||||
|
||||
/* ed_next_history():
|
||||
* Move to the next history line
|
||||
* [^N] [j]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_next_history(EditLine *el, int c __unused)
|
||||
{
|
||||
el_action_t beep = CC_REFRESH, rval;
|
||||
|
||||
el->el_chared.c_undo.len = -1;
|
||||
*el->el_line.lastchar = '\0'; /* just in case */
|
||||
|
||||
el->el_history.eventno -= el->el_state.argument;
|
||||
|
||||
if (el->el_history.eventno < 0) {
|
||||
el->el_history.eventno = 0;
|
||||
beep = CC_REFRESH_BEEP;
|
||||
}
|
||||
rval = hist_get(el);
|
||||
if (rval == CC_REFRESH)
|
||||
return beep;
|
||||
return rval;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ed_search_prev_history():
|
||||
* Search previous in history for a line matching the current
|
||||
* next search history [M-P] [K]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_search_prev_history(EditLine *el, int c __unused)
|
||||
{
|
||||
const char *hp;
|
||||
int h;
|
||||
bool_t found = 0;
|
||||
|
||||
el->el_chared.c_vcmd.action = NOP;
|
||||
el->el_chared.c_undo.len = -1;
|
||||
*el->el_line.lastchar = '\0'; /* just in case */
|
||||
if (el->el_history.eventno < 0) {
|
||||
#ifdef DEBUG_EDIT
|
||||
(void) fprintf(el->el_errfile,
|
||||
"e_prev_search_hist(): eventno < 0;\n");
|
||||
#endif
|
||||
el->el_history.eventno = 0;
|
||||
return (CC_ERROR);
|
||||
}
|
||||
if (el->el_history.eventno == 0) {
|
||||
(void) strncpy(el->el_history.buf, el->el_line.buffer,
|
||||
EL_BUFSIZ);
|
||||
el->el_history.last = el->el_history.buf +
|
||||
(el->el_line.lastchar - el->el_line.buffer);
|
||||
}
|
||||
if (el->el_history.ref == NULL)
|
||||
return (CC_ERROR);
|
||||
|
||||
hp = HIST_FIRST(el);
|
||||
if (hp == NULL)
|
||||
return (CC_ERROR);
|
||||
|
||||
c_setpat(el); /* Set search pattern !! */
|
||||
|
||||
for (h = 1; h <= el->el_history.eventno; h++)
|
||||
hp = HIST_NEXT(el);
|
||||
|
||||
while (hp != NULL) {
|
||||
#ifdef SDEBUG
|
||||
(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
|
||||
#endif
|
||||
if ((strncmp(hp, el->el_line.buffer, (size_t)
|
||||
(el->el_line.lastchar - el->el_line.buffer)) ||
|
||||
hp[el->el_line.lastchar - el->el_line.buffer]) &&
|
||||
c_hmatch(el, hp)) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
h++;
|
||||
hp = HIST_NEXT(el);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
#ifdef SDEBUG
|
||||
(void) fprintf(el->el_errfile, "not found\n");
|
||||
#endif
|
||||
return (CC_ERROR);
|
||||
}
|
||||
el->el_history.eventno = h;
|
||||
|
||||
return (hist_get(el));
|
||||
}
|
||||
|
||||
|
||||
/* ed_search_next_history():
|
||||
* Search next in history for a line matching the current
|
||||
* [M-N] [J]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_search_next_history(EditLine *el, int c __unused)
|
||||
{
|
||||
const char *hp;
|
||||
int h;
|
||||
bool_t found = 0;
|
||||
|
||||
el->el_chared.c_vcmd.action = NOP;
|
||||
el->el_chared.c_undo.len = -1;
|
||||
*el->el_line.lastchar = '\0'; /* just in case */
|
||||
|
||||
if (el->el_history.eventno == 0)
|
||||
return (CC_ERROR);
|
||||
|
||||
if (el->el_history.ref == NULL)
|
||||
return (CC_ERROR);
|
||||
|
||||
hp = HIST_FIRST(el);
|
||||
if (hp == NULL)
|
||||
return (CC_ERROR);
|
||||
|
||||
c_setpat(el); /* Set search pattern !! */
|
||||
|
||||
for (h = 1; h < el->el_history.eventno && hp; h++) {
|
||||
#ifdef SDEBUG
|
||||
(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
|
||||
#endif
|
||||
if ((strncmp(hp, el->el_line.buffer, (size_t)
|
||||
(el->el_line.lastchar - el->el_line.buffer)) ||
|
||||
hp[el->el_line.lastchar - el->el_line.buffer]) &&
|
||||
c_hmatch(el, hp))
|
||||
found = h;
|
||||
hp = HIST_NEXT(el);
|
||||
}
|
||||
|
||||
if (!found) { /* is it the current history number? */
|
||||
if (!c_hmatch(el, el->el_history.buf)) {
|
||||
#ifdef SDEBUG
|
||||
(void) fprintf(el->el_errfile, "not found\n");
|
||||
#endif
|
||||
return (CC_ERROR);
|
||||
}
|
||||
}
|
||||
el->el_history.eventno = found;
|
||||
|
||||
return (hist_get(el));
|
||||
}
|
||||
|
||||
|
||||
/* ed_prev_line():
|
||||
* Move up one line
|
||||
* Could be [k] [^p]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_prev_line(EditLine *el, int c __unused)
|
||||
{
|
||||
char *ptr;
|
||||
int nchars = c_hpos(el);
|
||||
|
||||
/*
|
||||
* Move to the line requested
|
||||
*/
|
||||
if (*(ptr = el->el_line.cursor) == '\n')
|
||||
ptr--;
|
||||
|
||||
for (; ptr >= el->el_line.buffer; ptr--)
|
||||
if (*ptr == '\n' && --el->el_state.argument <= 0)
|
||||
break;
|
||||
|
||||
if (el->el_state.argument > 0)
|
||||
return (CC_ERROR);
|
||||
|
||||
/*
|
||||
* Move to the beginning of the line
|
||||
*/
|
||||
for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Move to the character requested
|
||||
*/
|
||||
for (ptr++;
|
||||
nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
|
||||
ptr++)
|
||||
continue;
|
||||
|
||||
el->el_line.cursor = ptr;
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_next_line():
|
||||
* Move down one line
|
||||
* Could be [j] [^n]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_next_line(EditLine *el, int c __unused)
|
||||
{
|
||||
char *ptr;
|
||||
int nchars = c_hpos(el);
|
||||
|
||||
/*
|
||||
* Move to the line requested
|
||||
*/
|
||||
for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
|
||||
if (*ptr == '\n' && --el->el_state.argument <= 0)
|
||||
break;
|
||||
|
||||
if (el->el_state.argument > 0)
|
||||
return (CC_ERROR);
|
||||
|
||||
/*
|
||||
* Move to the character requested
|
||||
*/
|
||||
for (ptr++;
|
||||
nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
|
||||
ptr++)
|
||||
continue;
|
||||
|
||||
el->el_line.cursor = ptr;
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* ed_command():
|
||||
* Editline extended command
|
||||
* [M-X] [:]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
ed_command(EditLine *el, int c __unused)
|
||||
{
|
||||
char tmpbuf[EL_BUFSIZ];
|
||||
int tmplen;
|
||||
|
||||
tmplen = c_gets(el, tmpbuf, "\n: ");
|
||||
term__putc('\n');
|
||||
|
||||
if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
|
||||
term_beep(el);
|
||||
|
||||
el->el_map.current = el->el_map.key;
|
||||
re_clear_display(el);
|
||||
return CC_REFRESH;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* Automatically generated file, do not edit */
|
||||
#ifndef _h_common_c
|
||||
#define _h_common_c
|
||||
protected el_action_t ed_end_of_file (EditLine *, int);
|
||||
protected el_action_t ed_insert (EditLine *, int);
|
||||
protected el_action_t ed_delete_prev_word (EditLine *, int);
|
||||
protected el_action_t ed_delete_next_char (EditLine *, int);
|
||||
protected el_action_t ed_kill_line (EditLine *, int);
|
||||
protected el_action_t ed_move_to_end (EditLine *, int);
|
||||
protected el_action_t ed_move_to_beg (EditLine *, int);
|
||||
protected el_action_t ed_transpose_chars (EditLine *, int);
|
||||
protected el_action_t ed_next_char (EditLine *, int);
|
||||
protected el_action_t ed_prev_word (EditLine *, int);
|
||||
protected el_action_t ed_prev_char (EditLine *, int);
|
||||
protected el_action_t ed_quoted_insert (EditLine *, int);
|
||||
protected el_action_t ed_digit (EditLine *, int);
|
||||
protected el_action_t ed_argument_digit (EditLine *, int);
|
||||
protected el_action_t ed_unassigned (EditLine *, int);
|
||||
protected el_action_t ed_tty_sigint (EditLine *, int);
|
||||
protected el_action_t ed_tty_dsusp (EditLine *, int);
|
||||
protected el_action_t ed_tty_flush_output (EditLine *, int);
|
||||
protected el_action_t ed_tty_sigquit (EditLine *, int);
|
||||
protected el_action_t ed_tty_sigtstp (EditLine *, int);
|
||||
protected el_action_t ed_tty_stop_output (EditLine *, int);
|
||||
protected el_action_t ed_tty_start_output (EditLine *, int);
|
||||
protected el_action_t ed_newline (EditLine *, int);
|
||||
protected el_action_t ed_delete_prev_char (EditLine *, int);
|
||||
protected el_action_t ed_clear_screen (EditLine *, int);
|
||||
protected el_action_t ed_redisplay (EditLine *, int);
|
||||
protected el_action_t ed_start_over (EditLine *, int);
|
||||
protected el_action_t ed_sequence_lead_in (EditLine *, int);
|
||||
protected el_action_t ed_prev_history (EditLine *, int);
|
||||
protected el_action_t ed_next_history (EditLine *, int);
|
||||
protected el_action_t ed_search_prev_history (EditLine *, int);
|
||||
protected el_action_t ed_search_next_history (EditLine *, int);
|
||||
protected el_action_t ed_prev_line (EditLine *, int);
|
||||
protected el_action_t ed_next_line (EditLine *, int);
|
||||
protected el_action_t ed_command (EditLine *, int);
|
||||
#endif /* _h_common_c */
|
||||
@@ -0,0 +1,788 @@
|
||||
.\" $NetBSD: editline.3,v 1.50 2005/10/12 09:29:43 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2003 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This file was contributed to The NetBSD Foundation by Luke Mewburn.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the NetBSD
|
||||
.\" Foundation, Inc. and its contributors.
|
||||
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
.\" contributors may be used to endorse or promote products derived
|
||||
.\" from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libedit/editline.3,v 1.29 2005/11/24 10:32:39 ru Exp $
|
||||
.\"
|
||||
.Dd October 4, 2005
|
||||
.Os
|
||||
.Dt EDITLINE 3
|
||||
.Sh NAME
|
||||
.Nm editline ,
|
||||
.Nm el_init ,
|
||||
.Nm el_end ,
|
||||
.Nm el_reset ,
|
||||
.Nm el_gets ,
|
||||
.Nm el_getc ,
|
||||
.Nm el_push ,
|
||||
.Nm el_parse ,
|
||||
.Nm el_set ,
|
||||
.Nm el_get ,
|
||||
.Nm el_source ,
|
||||
.Nm el_resize ,
|
||||
.Nm el_line ,
|
||||
.Nm el_insertstr ,
|
||||
.Nm el_deletestr ,
|
||||
.Nm history_init ,
|
||||
.Nm history_end ,
|
||||
.Nm history ,
|
||||
.Nm tok_init ,
|
||||
.Nm tok_end ,
|
||||
.Nm tok_reset ,
|
||||
.Nm tok_line ,
|
||||
.Nm tok_str
|
||||
.Nd line editor, history and tokenization functions
|
||||
.Sh LIBRARY
|
||||
.Lb libedit
|
||||
.Sh SYNOPSIS
|
||||
.In histedit.h
|
||||
.Ft EditLine *
|
||||
.Fn el_init "const char *prog" "FILE *fin" "FILE *fout" "FILE *ferr"
|
||||
.Ft void
|
||||
.Fn el_end "EditLine *e"
|
||||
.Ft void
|
||||
.Fn el_reset "EditLine *e"
|
||||
.Ft const char *
|
||||
.Fn el_gets "EditLine *e" "int *count"
|
||||
.Ft int
|
||||
.Fn el_getc "EditLine *e" "char *ch"
|
||||
.Ft void
|
||||
.Fn el_push "EditLine *e" "char *str"
|
||||
.Ft int
|
||||
.Fn el_parse "EditLine *e" "int argc" "const char *argv[]"
|
||||
.Ft int
|
||||
.Fn el_set "EditLine *e" "int op" "..."
|
||||
.Ft int
|
||||
.Fn el_get "EditLine *e" "int op" "void *result"
|
||||
.Ft int
|
||||
.Fn el_source "EditLine *e" "const char *file"
|
||||
.Ft void
|
||||
.Fn el_resize "EditLine *e"
|
||||
.Ft const LineInfo *
|
||||
.Fn el_line "EditLine *e"
|
||||
.Ft int
|
||||
.Fn el_insertstr "EditLine *e" "const char *str"
|
||||
.Ft void
|
||||
.Fn el_deletestr "EditLine *e" "int count"
|
||||
.Ft History *
|
||||
.Fn history_init
|
||||
.Ft void
|
||||
.Fn history_end "History *h"
|
||||
.Ft int
|
||||
.Fn history "History *h" "HistEvent *ev" "int op" "..."
|
||||
.Ft Tokenizer *
|
||||
.Fn tok_init "const char *IFS"
|
||||
.Ft void
|
||||
.Fn tok_end "Tokenizer *t"
|
||||
.Ft void
|
||||
.Fn tok_reset "Tokenizer *t"
|
||||
.Ft int
|
||||
.Fo tok_line
|
||||
.Fa "Tokenizer *t" "const LineInfo *li" "int *argc" "const char **argv[]"
|
||||
.Fa "int *cursorc" "int *cursoro"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn tok_str "Tokenizer *t" "const char *str" "int *argc" "const char **argv[]"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
library provides generic line editing, history and tokenization functions,
|
||||
similar to those found in
|
||||
.Xr sh 1 .
|
||||
.Pp
|
||||
These functions are available in the
|
||||
.Nm libedit
|
||||
library (which needs the
|
||||
.Nm libtermcap
|
||||
library).
|
||||
Programs should be linked with
|
||||
.Fl ledit ltermcap .
|
||||
.Sh LINE EDITING FUNCTIONS
|
||||
The line editing functions use a common data structure,
|
||||
.Fa EditLine ,
|
||||
which is created by
|
||||
.Fn el_init
|
||||
and freed by
|
||||
.Fn el_end .
|
||||
.Pp
|
||||
The following functions are available:
|
||||
.Bl -tag -width 4n
|
||||
.It Fn el_init
|
||||
Initialise the line editor, and return a data structure
|
||||
to be used by all other line editing functions.
|
||||
.Fa prog
|
||||
is the name of the invoking program, used when reading the
|
||||
.Xr editrc 5
|
||||
file to determine which settings to use.
|
||||
.Fa fin ,
|
||||
.Fa fout
|
||||
and
|
||||
.Fa ferr
|
||||
are the input, output, and error streams (respectively) to use.
|
||||
In this documentation, references to
|
||||
.Dq the tty
|
||||
are actually to this input/output stream combination.
|
||||
.It Fn el_end
|
||||
Clean up and finish with
|
||||
.Fa e ,
|
||||
assumed to have been created with
|
||||
.Fn el_init .
|
||||
.It Fn el_reset
|
||||
Reset the tty and the parser.
|
||||
This should be called after an error which may have upset the tty's
|
||||
state.
|
||||
.It Fn el_gets
|
||||
Read a line from the tty.
|
||||
.Fa count
|
||||
is modified to contain the number of characters read.
|
||||
Returns the line read if successful, or
|
||||
.Dv NULL
|
||||
if no characters were read or if an error occurred.
|
||||
.It Fn el_getc
|
||||
Read a character from the tty.
|
||||
.Fa ch
|
||||
is modified to contain the character read.
|
||||
Returns the number of characters read if successful, \-1 otherwise.
|
||||
.It Fn el_push
|
||||
Pushes
|
||||
.Fa str
|
||||
back onto the input stream.
|
||||
This is used by the macro expansion mechanism.
|
||||
Refer to the description of
|
||||
.Ic bind
|
||||
.Fl s
|
||||
in
|
||||
.Xr editrc 5
|
||||
for more information.
|
||||
.It Fn el_parse
|
||||
Parses the
|
||||
.Fa argv
|
||||
array (which is
|
||||
.Fa argc
|
||||
elements in size)
|
||||
to execute builtin
|
||||
.Nm
|
||||
commands.
|
||||
If the command is prefixed with
|
||||
.Dq prog:
|
||||
then
|
||||
.Fn el_parse
|
||||
will only execute the command if
|
||||
.Dq prog
|
||||
matches the
|
||||
.Fa prog
|
||||
argument supplied to
|
||||
.Fn el_init .
|
||||
The return value is
|
||||
\-1 if the command is unknown,
|
||||
0 if there was no error or
|
||||
.Dq prog
|
||||
did not match, or
|
||||
1 if the command returned an error.
|
||||
Refer to
|
||||
.Xr editrc 5
|
||||
for more information.
|
||||
.It Fn el_set
|
||||
Set
|
||||
.Nm
|
||||
parameters.
|
||||
.Fa op
|
||||
determines which parameter to set, and each operation has its
|
||||
own parameter list.
|
||||
.Pp
|
||||
The following values for
|
||||
.Fa op
|
||||
are supported, along with the required argument list:
|
||||
.Bl -tag -width 4n
|
||||
.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)"
|
||||
Define prompt printing function as
|
||||
.Fa f ,
|
||||
which is to return a string that contains the prompt.
|
||||
.It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)"
|
||||
Define right side prompt printing function as
|
||||
.Fa f ,
|
||||
which is to return a string that contains the prompt.
|
||||
.It Dv EL_TERMINAL , Fa "const char *type"
|
||||
Define terminal type of the tty to be
|
||||
.Fa type ,
|
||||
or to
|
||||
.Ev TERM
|
||||
if
|
||||
.Fa type
|
||||
is
|
||||
.Dv NULL .
|
||||
.It Dv EL_EDITOR , Fa "const char *mode"
|
||||
Set editing mode to
|
||||
.Fa mode ,
|
||||
which must be one of
|
||||
.Dq emacs
|
||||
or
|
||||
.Dq vi .
|
||||
.It Dv EL_SIGNAL , Fa "int flag"
|
||||
If
|
||||
.Fa flag
|
||||
is non-zero,
|
||||
.Nm
|
||||
will install its own signal handler for the following signals when
|
||||
reading command input:
|
||||
.Dv SIGCONT ,
|
||||
.Dv SIGHUP ,
|
||||
.Dv SIGINT ,
|
||||
.Dv SIGQUIT ,
|
||||
.Dv SIGSTOP ,
|
||||
.Dv SIGTERM ,
|
||||
.Dv SIGTSTP ,
|
||||
and
|
||||
.Dv SIGWINCH .
|
||||
Otherwise, the current signal handlers will be used.
|
||||
.It Dv EL_BIND , Xo
|
||||
.Fa "const char *" ,
|
||||
.Fa "..." ,
|
||||
.Dv NULL
|
||||
.Xc
|
||||
Perform the
|
||||
.Ic bind
|
||||
builtin command.
|
||||
Refer to
|
||||
.Xr editrc 5
|
||||
for more information.
|
||||
.It Dv EL_ECHOTC , Xo
|
||||
.Fa "const char *" ,
|
||||
.Fa "..." ,
|
||||
.Dv NULL
|
||||
.Xc
|
||||
Perform the
|
||||
.Ic echotc
|
||||
builtin command.
|
||||
Refer to
|
||||
.Xr editrc 5
|
||||
for more information.
|
||||
.It Dv EL_SETTC , Xo
|
||||
.Fa "const char *" ,
|
||||
.Fa "..." ,
|
||||
.Dv NULL
|
||||
.Xc
|
||||
Perform the
|
||||
.Ic settc
|
||||
builtin command.
|
||||
Refer to
|
||||
.Xr editrc 5
|
||||
for more information.
|
||||
.It Dv EL_SETTY , Xo
|
||||
.Fa "const char *" ,
|
||||
.Fa "..." ,
|
||||
.Dv NULL
|
||||
.Xc
|
||||
Perform the
|
||||
.Ic setty
|
||||
builtin command.
|
||||
Refer to
|
||||
.Xr editrc 5
|
||||
for more information.
|
||||
.It Dv EL_TELLTC , Xo
|
||||
.Fa "const char *" ,
|
||||
.Fa "..." ,
|
||||
.Dv NULL
|
||||
.Xc
|
||||
Perform the
|
||||
.Ic telltc
|
||||
builtin command.
|
||||
Refer to
|
||||
.Xr editrc 5
|
||||
for more information.
|
||||
.It Dv EL_ADDFN , Xo
|
||||
.Fa "const char *name" ,
|
||||
.Fa "const char *help" ,
|
||||
.Fa "unsigned char (*func)(EditLine *e, int ch)"
|
||||
.Xc
|
||||
Add a user defined function,
|
||||
.Fn func ,
|
||||
referred to as
|
||||
.Fa name
|
||||
which is invoked when a key which is bound to
|
||||
.Fa name
|
||||
is entered.
|
||||
.Fa help
|
||||
is a description of
|
||||
.Fa name .
|
||||
At invocation time,
|
||||
.Fa ch
|
||||
is the key which caused the invocation.
|
||||
The return value of
|
||||
.Fn func
|
||||
should be one of:
|
||||
.Bl -tag -width "CC_REDISPLAY"
|
||||
.It Dv CC_NORM
|
||||
Add a normal character.
|
||||
.It Dv CC_NEWLINE
|
||||
End of line was entered.
|
||||
.It Dv CC_EOF
|
||||
EOF was entered.
|
||||
.It Dv CC_ARGHACK
|
||||
Expecting further command input as arguments, do nothing visually.
|
||||
.It Dv CC_REFRESH
|
||||
Refresh display.
|
||||
.It Dv CC_REFRESH_BEEP
|
||||
Refresh display, and beep.
|
||||
.It Dv CC_CURSOR
|
||||
Cursor moved, so update and perform
|
||||
.Dv CC_REFRESH .
|
||||
.It Dv CC_REDISPLAY
|
||||
Redisplay entire input line.
|
||||
This is useful if a key binding outputs extra information.
|
||||
.It Dv CC_ERROR
|
||||
An error occurred.
|
||||
Beep, and flush tty.
|
||||
.It Dv CC_FATAL
|
||||
Fatal error, reset tty to known state.
|
||||
.El
|
||||
.It Dv EL_HIST , Xo
|
||||
.Fa "History *(*func)(History *, int op, ...)" ,
|
||||
.Fa "const char *ptr"
|
||||
.Xc
|
||||
Defines which history function to use, which is usually
|
||||
.Fn history .
|
||||
.Fa ptr
|
||||
should be the value returned by
|
||||
.Fn history_init .
|
||||
.It Dv EL_EDITMODE , Fa "int flag"
|
||||
If
|
||||
.Fa flag
|
||||
is non-zero,
|
||||
editing is enabled (the default).
|
||||
Note that this is only an indication, and does not
|
||||
affect the operation of
|
||||
.Nm .
|
||||
At this time, it is the caller's responsibility to
|
||||
check this
|
||||
(using
|
||||
.Fn el_get )
|
||||
to determine if editing should be enabled or not.
|
||||
.It Dv EL_GETCFN , Fa "int (*f)(EditLine *, char *c)"
|
||||
Define the character reading function as
|
||||
.Fa f ,
|
||||
which is to return the number of characters read and store them in
|
||||
.Fa c .
|
||||
This function is called internally by
|
||||
.Fn el_gets
|
||||
and
|
||||
.Fn el_getc .
|
||||
The builtin function can be set or restored with the special function
|
||||
name
|
||||
.Dv EL_BUILTIN_GETCFN .
|
||||
.It Dv EL_CLIENTDATA , Fa "void *data"
|
||||
Register
|
||||
.Fa data
|
||||
to be associated with this EditLine structure.
|
||||
It can be retrieved with the corresponding
|
||||
.Fn el_get
|
||||
call.
|
||||
.El
|
||||
.It Fn el_get
|
||||
Get
|
||||
.Nm
|
||||
parameters.
|
||||
.Fa op
|
||||
determines which parameter to retrieve into
|
||||
.Fa result .
|
||||
Returns 0 if successful, \-1 otherwise.
|
||||
.Pp
|
||||
The following values for
|
||||
.Fa op
|
||||
are supported, along with actual type of
|
||||
.Fa result :
|
||||
.Bl -tag -width 4n
|
||||
.It Dv EL_PROMPT , Fa "char *(*f)(EditLine *)"
|
||||
Return a pointer to the function that displays the prompt.
|
||||
.It Dv EL_RPROMPT , Fa "char *(*f)(EditLine *)"
|
||||
Return a pointer to the function that displays the rightside prompt.
|
||||
.It Dv EL_EDITOR , Fa "const char *"
|
||||
Return the name of the editor, which will be one of
|
||||
.Dq emacs
|
||||
or
|
||||
.Dq vi .
|
||||
.It Dv EL_SIGNAL , Fa "int *"
|
||||
Return non-zero if
|
||||
.Nm
|
||||
has installed private signal handlers (see
|
||||
.Fn el_get
|
||||
above).
|
||||
.It Dv EL_EDITMODE, Fa "int *"
|
||||
Return non-zero if editing is enabled.
|
||||
.It Dv EL_GETCFN, Fa "int (**f)(EditLine *, char *)"
|
||||
Return a pointer to the function that read characters, which is equal to
|
||||
.Dv EL_BUILTIN_GETCFN
|
||||
in the case of the default builtin function.
|
||||
.It Dv EL_CLIENTDATA , Fa "void **data"
|
||||
Retrieve
|
||||
.Fa data
|
||||
previously registered with the corresponding
|
||||
.Fn el_set
|
||||
call.
|
||||
.It Dv EL_UNBUFFERED, Fa "int"
|
||||
Sets or clears unbuffered mode.
|
||||
In this mode,
|
||||
.Fn el_gets
|
||||
will return immediately after processing a single character.
|
||||
.It Dv EL_PREP_TERM, Fa "int"
|
||||
Sets or clears terminal editing mode.
|
||||
.El
|
||||
.It Fn el_source
|
||||
Initialise
|
||||
.Nm
|
||||
by reading the contents of
|
||||
.Fa file .
|
||||
.Fn el_parse
|
||||
is called for each line in
|
||||
.Fa file .
|
||||
If
|
||||
.Fa file
|
||||
is
|
||||
.Dv NULL ,
|
||||
try
|
||||
.Pa $PWD/.editrc
|
||||
then
|
||||
.Pa $HOME/.editrc .
|
||||
Refer to
|
||||
.Xr editrc 5
|
||||
for details on the format of
|
||||
.Fa file .
|
||||
.It Fn el_resize
|
||||
Must be called if the terminal size changes.
|
||||
If
|
||||
.Dv EL_SIGNAL
|
||||
has been set with
|
||||
.Fn el_set ,
|
||||
then this is done automatically.
|
||||
Otherwise, it is the responsibility of the application to call
|
||||
.Fn el_resize
|
||||
on the appropriate occasions.
|
||||
.It Fn el_line
|
||||
Return the editing information for the current line in a
|
||||
.Fa LineInfo
|
||||
structure, which is defined as follows:
|
||||
.Bd -literal
|
||||
typedef struct lineinfo {
|
||||
const char *buffer; /* address of buffer */
|
||||
const char *cursor; /* address of cursor */
|
||||
const char *lastchar; /* address of last character */
|
||||
} LineInfo;
|
||||
.Ed
|
||||
.Pp
|
||||
.Fa buffer
|
||||
is not NUL terminated.
|
||||
This function may be called after
|
||||
.Fn el_gets
|
||||
to obtain the
|
||||
.Fa LineInfo
|
||||
structure pertaining to line returned by that function,
|
||||
and from within user defined functions added with
|
||||
.Dv EL_ADDFN .
|
||||
.It Fn el_insertstr
|
||||
Insert
|
||||
.Fa str
|
||||
into the line at the cursor.
|
||||
Returns \-1 if
|
||||
.Fa str
|
||||
is empty or will not fit, and 0 otherwise.
|
||||
.It Fn el_deletestr
|
||||
Delete
|
||||
.Fa num
|
||||
characters before the cursor.
|
||||
.El
|
||||
.Sh HISTORY LIST FUNCTIONS
|
||||
The history functions use a common data structure,
|
||||
.Fa History ,
|
||||
which is created by
|
||||
.Fn history_init
|
||||
and freed by
|
||||
.Fn history_end .
|
||||
.Pp
|
||||
The following functions are available:
|
||||
.Bl -tag -width 4n
|
||||
.It Fn history_init
|
||||
Initialise the history list, and return a data structure
|
||||
to be used by all other history list functions.
|
||||
.It Fn history_end
|
||||
Clean up and finish with
|
||||
.Fa h ,
|
||||
assumed to have been created with
|
||||
.Fn history_init .
|
||||
.It Fn history
|
||||
Perform operation
|
||||
.Fa op
|
||||
on the history list, with optional arguments as needed by the
|
||||
operation.
|
||||
.Fa ev
|
||||
is changed accordingly to operation.
|
||||
The following values for
|
||||
.Fa op
|
||||
are supported, along with the required argument list:
|
||||
.Bl -tag -width 4n
|
||||
.It Dv H_SETSIZE , Fa "int size"
|
||||
Set size of history to
|
||||
.Fa size
|
||||
elements.
|
||||
.It Dv H_GETSIZE
|
||||
Get number of events currently in history.
|
||||
.It Dv H_END
|
||||
Cleans up and finishes with
|
||||
.Fa h ,
|
||||
assumed to be created with
|
||||
.Fn history_init .
|
||||
.It Dv H_CLEAR
|
||||
Clear the history.
|
||||
.It Dv H_FUNC , Xo
|
||||
.Fa "void *ptr" ,
|
||||
.Fa "history_gfun_t first" ,
|
||||
.Fa "history_gfun_t next" ,
|
||||
.Fa "history_gfun_t last" ,
|
||||
.Fa "history_gfun_t prev" ,
|
||||
.Fa "history_gfun_t curr" ,
|
||||
.Fa "history_sfun_t set" ,
|
||||
.Fa "history_vfun_t clear" ,
|
||||
.Fa "history_efun_t enter" ,
|
||||
.Fa "history_efun_t add"
|
||||
.Xc
|
||||
Define functions to perform various history operations.
|
||||
.Fa ptr
|
||||
is the argument given to a function when it is invoked.
|
||||
.It Dv H_FIRST
|
||||
Return the first element in the history.
|
||||
.It Dv H_LAST
|
||||
Return the last element in the history.
|
||||
.It Dv H_PREV
|
||||
Return the previous element in the history.
|
||||
.It Dv H_NEXT
|
||||
Return the next element in the history.
|
||||
.It Dv H_CURR
|
||||
Return the current element in the history.
|
||||
.It Dv H_SET
|
||||
Set the cursor to point to the requested element.
|
||||
.It Dv H_ADD , Fa "const char *str"
|
||||
Append
|
||||
.Fa str
|
||||
to the current element of the history, or perform the
|
||||
.Dv H_ENTER
|
||||
operation with argument
|
||||
.Fa str
|
||||
if there is no current element.
|
||||
.It Dv H_APPEND , Fa "const char *str"
|
||||
Append
|
||||
.Fa str
|
||||
to the last new element of the history.
|
||||
.It Dv H_ENTER , Fa "const char *str"
|
||||
Add
|
||||
.Fa str
|
||||
as a new element to the history, and, if necessary,
|
||||
removing the oldest entry to keep the list to the created size.
|
||||
If
|
||||
.Dv H_SETUNIQUE
|
||||
was has been called with a non-zero arguments, the element
|
||||
will not be entered into the history if its contents match
|
||||
the ones of the current history element.
|
||||
If the element is entered
|
||||
.Fn history
|
||||
returns 1, if it is ignored as a duplicate returns 0.
|
||||
Finally
|
||||
.Fn history
|
||||
returns \-1 if an error occurred.
|
||||
.It Dv H_PREV_STR , Fa "const char *str"
|
||||
Return the closest previous event that starts with
|
||||
.Fa str .
|
||||
.It Dv H_NEXT_STR , Fa "const char *str"
|
||||
Return the closest next event that starts with
|
||||
.Fa str .
|
||||
.It Dv H_PREV_EVENT , Fa "int e"
|
||||
Return the previous event numbered
|
||||
.Fa e .
|
||||
.It Dv H_NEXT_EVENT , Fa "int e"
|
||||
Return the next event numbered
|
||||
.Fa e .
|
||||
.It Dv H_LOAD , Fa "const char *file"
|
||||
Load the history list stored in
|
||||
.Fa file .
|
||||
.It Dv H_SAVE , Fa "const char *file"
|
||||
Save the history list to
|
||||
.Fa file .
|
||||
.It Dv H_SETUNIQUE , Fa "int unique"
|
||||
Set flag that adjacent identical event strings should not be entered
|
||||
into the history.
|
||||
.It Dv H_GETUNIQUE
|
||||
Retrieve the current setting if adjacent identical elements should
|
||||
be entered into the history.
|
||||
.It Dv H_DEL , Fa "int num"
|
||||
Delete the event numbered
|
||||
.Fa e .
|
||||
This function is only provided for
|
||||
.Xr readline 3
|
||||
compatibility.
|
||||
The caller is responsible for free'ing the string in the returned
|
||||
.Fa HistEvent .
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn history
|
||||
function returns \*[Ge] 0 if the operation
|
||||
.Fa op
|
||||
succeeds.
|
||||
Otherwise, \-1 is returned and
|
||||
.Fa ev
|
||||
is updated to contain more details about the error.
|
||||
.El
|
||||
.Sh TOKENIZATION FUNCTIONS
|
||||
The tokenization functions use a common data structure,
|
||||
.Fa Tokenizer ,
|
||||
which is created by
|
||||
.Fn tok_init
|
||||
and freed by
|
||||
.Fn tok_end .
|
||||
.Pp
|
||||
The following functions are available:
|
||||
.Bl -tag -width 4n
|
||||
.It Fn tok_init
|
||||
Initialise the tokenizer, and return a data structure
|
||||
to be used by all other tokenizer functions.
|
||||
.Fa IFS
|
||||
contains the Input Field Separators, which defaults to
|
||||
.Aq space ,
|
||||
.Aq tab ,
|
||||
and
|
||||
.Aq newline
|
||||
if
|
||||
.Dv NULL .
|
||||
.It Fn tok_end
|
||||
Clean up and finish with
|
||||
.Fa t ,
|
||||
assumed to have been created with
|
||||
.Fn tok_init .
|
||||
.It Fn tok_reset
|
||||
Reset the tokenizer state.
|
||||
Use after a line has been successfully tokenized
|
||||
by
|
||||
.Fn tok_line
|
||||
or
|
||||
.Fn tok_str
|
||||
and before a new line is to be tokenized.
|
||||
.It Fn tok_line
|
||||
Tokenize
|
||||
.Fa li ,
|
||||
If successful, modify:
|
||||
.Fa argv
|
||||
to contain the words,
|
||||
.Fa argc
|
||||
to contain the number of words,
|
||||
.Fa cursorc
|
||||
(if not
|
||||
.Dv NULL )
|
||||
to contain the index of the word containing the cursor,
|
||||
and
|
||||
.Fa cursoro
|
||||
(if not
|
||||
.Dv NULL )
|
||||
to contain the offset within
|
||||
.Fa argv[cursorc]
|
||||
of the cursor.
|
||||
.Pp
|
||||
Returns
|
||||
0 if successful,
|
||||
\-1 for an internal error,
|
||||
1 for an unmatched single quote,
|
||||
2 for an unmatched double quote,
|
||||
and
|
||||
3 for a backslash quoted
|
||||
.Aq newline .
|
||||
A positive exit code indicates that another line should be read
|
||||
and tokenization attempted again.
|
||||
.It Fn tok_str
|
||||
A simpler form of
|
||||
.Fn tok_line ;
|
||||
.Fa str
|
||||
is a NUL terminated string to tokenize.
|
||||
.El
|
||||
.\"XXX.Sh EXAMPLES
|
||||
.\"XXX: provide some examples
|
||||
.Sh SEE ALSO
|
||||
.Xr sh 1 ,
|
||||
.Xr signal 3 ,
|
||||
.Xr termcap 3 ,
|
||||
.Xr editrc 5
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
library first appeared in
|
||||
.Bx 4.4 .
|
||||
.Dv CC_REDISPLAY
|
||||
appeared in
|
||||
.Nx 1.3 .
|
||||
.Dv CC_REFRESH_BEEP
|
||||
and
|
||||
.Dv EL_EDITMODE
|
||||
appeared in
|
||||
.Nx 1.4 .
|
||||
.Dv EL_RPROMPT
|
||||
appeared in
|
||||
.Nx 1.5 .
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
library was written by
|
||||
.An Christos Zoulas .
|
||||
.An Luke Mewburn
|
||||
wrote this manual and implemented
|
||||
.Dv CC_REDISPLAY ,
|
||||
.Dv CC_REFRESH_BEEP ,
|
||||
.Dv EL_EDITMODE ,
|
||||
and
|
||||
.Dv EL_RPROMPT .
|
||||
.Sh BUGS
|
||||
At this time, it is the responsibility of the caller to
|
||||
check the result of the
|
||||
.Dv EL_EDITMODE
|
||||
operation of
|
||||
.Fn el_get
|
||||
(after an
|
||||
.Fn el_source
|
||||
or
|
||||
.Fn el_parse )
|
||||
to determine if
|
||||
.Nm
|
||||
should be used for further input.
|
||||
I.e.,
|
||||
.Dv EL_EDITMODE
|
||||
is purely an indication of the result of the most recent
|
||||
.Xr editrc 5
|
||||
.Ic edit
|
||||
command.
|
||||
@@ -0,0 +1,516 @@
|
||||
.\" $NetBSD: editrc.5,v 1.19 2003/11/01 23:35:33 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997-2000 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This file was contributed to The NetBSD Foundation by Luke Mewburn.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the NetBSD
|
||||
.\" Foundation, Inc. and its contributors.
|
||||
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
.\" contributors may be used to endorse or promote products derived
|
||||
.\" from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libedit/editrc.5,v 1.19 2005/11/17 13:00:00 ru Exp $
|
||||
.\"
|
||||
.Dd October 18, 2003
|
||||
.Os
|
||||
.Dt EDITRC 5
|
||||
.Sh NAME
|
||||
.Nm editrc
|
||||
.Nd configuration file for editline library
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
file defines various settings to be used by the
|
||||
.Xr editline 3
|
||||
library.
|
||||
.Pp
|
||||
The format of each line is:
|
||||
.Dl [prog:]command [arg [...]]
|
||||
.Pp
|
||||
.Ar command
|
||||
is one of the
|
||||
.Xr editline 3
|
||||
builtin commands.
|
||||
Refer to
|
||||
.Sx BUILTIN COMMANDS
|
||||
for more information.
|
||||
.Pp
|
||||
.Ar prog
|
||||
is the program name string that a program defines when it calls
|
||||
.Xr el_init 3
|
||||
to set up
|
||||
.Xr editline 3 ,
|
||||
which is usually
|
||||
.Va argv[0] .
|
||||
.Ar command
|
||||
will be executed for any program which matches
|
||||
.Ar prog .
|
||||
.Pp
|
||||
.Ar prog
|
||||
may also be a
|
||||
.Xr regex 3
|
||||
style
|
||||
regular expression, in which case
|
||||
.Ar command
|
||||
will be executed for any program that matches the regular expression.
|
||||
.Pp
|
||||
If
|
||||
.Ar prog
|
||||
is absent,
|
||||
.Ar command
|
||||
is executed for all programs.
|
||||
.Sh BUILTIN COMMANDS
|
||||
The
|
||||
.Nm editline
|
||||
library has some builtin commands, which affect the way
|
||||
that the line editing and history functions operate.
|
||||
These are based on similar named builtins present in the
|
||||
.Xr tcsh 1
|
||||
shell.
|
||||
.Pp
|
||||
The following builtin commands are available:
|
||||
.Bl -tag -width 4n
|
||||
.It Ic bind Xo
|
||||
.Op Fl a
|
||||
.Op Fl e
|
||||
.Op Fl k
|
||||
.Op Fl l
|
||||
.Op Fl r
|
||||
.Op Fl s
|
||||
.Op Fl v
|
||||
.Op Ar key Op Ar command
|
||||
.Xc
|
||||
Without options, list all bound keys, and the editor command to which
|
||||
each is bound.
|
||||
If
|
||||
.Ar key
|
||||
is supplied, show the bindings for
|
||||
.Ar key .
|
||||
If
|
||||
.Ar key command
|
||||
is supplied, bind
|
||||
.Ar command
|
||||
to
|
||||
.Ar key .
|
||||
Options include:
|
||||
.Bl -tag -width 4n
|
||||
.It Fl e
|
||||
Bind all keys to the standard GNU Emacs-like bindings.
|
||||
.It Fl v
|
||||
Bind all keys to the standard
|
||||
.Xr vi 1 Ns -like
|
||||
bindings.
|
||||
.It Fl a
|
||||
List or change key bindings in the
|
||||
.Xr vi 1
|
||||
mode alternate (command mode) key map.
|
||||
.It Fl k
|
||||
.Ar key
|
||||
is interpreted as a symbolic arrow key name, which may be one of
|
||||
.Sq up ,
|
||||
.Sq down ,
|
||||
.Sq left
|
||||
or
|
||||
.Sq right .
|
||||
.It Fl l
|
||||
List all editor commands and a short description of each.
|
||||
.It Fl r
|
||||
Remove a key's binding.
|
||||
.It Fl s
|
||||
.Ar command
|
||||
is taken as a literal string and treated as terminal input when
|
||||
.Ar key
|
||||
is typed.
|
||||
Bound keys in
|
||||
.Ar command
|
||||
are themselves reinterpreted, and this continues for ten levels of
|
||||
interpretation.
|
||||
.El
|
||||
.Pp
|
||||
.Ar command
|
||||
may be one of the commands documented in
|
||||
.Sx "EDITOR COMMANDS"
|
||||
below, or another key.
|
||||
.Pp
|
||||
.Ar key
|
||||
and
|
||||
.Ar command
|
||||
can contain control characters of the form
|
||||
.Sm off
|
||||
.Sq No ^ Ar character
|
||||
.Sm on
|
||||
(e.g.\&
|
||||
.Sq ^A ) ,
|
||||
and the following backslashed escape sequences:
|
||||
.Pp
|
||||
.Bl -tag -compact -offset indent -width 4n
|
||||
.It Ic \ea
|
||||
Bell
|
||||
.It Ic \eb
|
||||
Backspace
|
||||
.It Ic \ee
|
||||
Escape
|
||||
.It Ic \ef
|
||||
Formfeed
|
||||
.It Ic \en
|
||||
Newline
|
||||
.It Ic \er
|
||||
Carriage return
|
||||
.It Ic \et
|
||||
Horizontal tab
|
||||
.It Ic \ev
|
||||
Vertical tab
|
||||
.Sm off
|
||||
.It Sy \e Ar nnn
|
||||
.Sm on
|
||||
The ASCII character corresponding to the octal number
|
||||
.Ar nnn .
|
||||
.El
|
||||
.Pp
|
||||
.Sq \e
|
||||
nullifies the special meaning of the following character,
|
||||
if it has any, notably
|
||||
.Sq \e
|
||||
and
|
||||
.Sq ^ .
|
||||
.It Ic echotc Xo
|
||||
.Op Fl sv
|
||||
.Ar arg
|
||||
.Ar ...
|
||||
.Xc
|
||||
Exercise terminal capabilities given in
|
||||
.Ar arg Ar ... .
|
||||
If
|
||||
.Ar arg
|
||||
is
|
||||
.Sq baud ,
|
||||
.Sq cols ,
|
||||
.Sq lines ,
|
||||
.Sq rows ,
|
||||
.Sq meta or
|
||||
.Sq tabs ,
|
||||
the value of that capability is printed, with
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no
|
||||
indicating that the terminal does or does not have that capability.
|
||||
.Pp
|
||||
.Fl s
|
||||
returns an empty string for non-existent capabilities, rather than
|
||||
causing an error.
|
||||
.Fl v
|
||||
causes messages to be verbose.
|
||||
.It Ic edit Op Cm on | off
|
||||
Enable or disable the
|
||||
.Nm editline
|
||||
functionality in a program.
|
||||
.It Ic history Ar list | Ar size Dv n | Ar unique Dv n
|
||||
The
|
||||
.Ar list
|
||||
command lists all entries in the history.
|
||||
The
|
||||
.Ar size
|
||||
command sets the history size to
|
||||
.Dv n
|
||||
entries.
|
||||
The
|
||||
.Ar unique
|
||||
command controls if history should keep duplicate entries.
|
||||
If
|
||||
.Dv n
|
||||
is non zero, only keep unique history entries.
|
||||
If
|
||||
.Dv n
|
||||
is zero, then keep all entries (the default).
|
||||
.It Ic telltc
|
||||
List the values of all the terminal capabilities (see
|
||||
.Xr termcap 5 ) .
|
||||
.It Ic settc Ar cap Ar val
|
||||
Set the terminal capability
|
||||
.Ar cap
|
||||
to
|
||||
.Ar val ,
|
||||
as defined in
|
||||
.Xr termcap 5 .
|
||||
No sanity checking is done.
|
||||
.It Ic setty Xo
|
||||
.Op Fl a
|
||||
.Op Fl d
|
||||
.Op Fl q
|
||||
.Op Fl x
|
||||
.Op Ar +mode
|
||||
.Op Ar -mode
|
||||
.Op Ar mode
|
||||
.Op Ar char=c
|
||||
.Xc
|
||||
Control which tty modes that
|
||||
.Nm
|
||||
will not allow the user to change.
|
||||
.Fl d ,
|
||||
.Fl q
|
||||
or
|
||||
.Fl x
|
||||
tells
|
||||
.Ic setty
|
||||
to act on the
|
||||
.Sq edit ,
|
||||
.Sq quote
|
||||
or
|
||||
.Sq execute
|
||||
set of tty modes respectively; defaulting to
|
||||
.Fl x .
|
||||
.Pp
|
||||
Without other arguments,
|
||||
.Ic setty
|
||||
lists the modes in the chosen set which are fixed on
|
||||
.Pq Sq +mode
|
||||
or off
|
||||
.Pq Sq -mode .
|
||||
.Fl a
|
||||
lists all tty modes in the chosen set regardless of the setting.
|
||||
With
|
||||
.Ar +mode ,
|
||||
.Ar -mode
|
||||
or
|
||||
.Ar mode ,
|
||||
fixes
|
||||
.Ar mode
|
||||
on or off or removes control of
|
||||
.Ar mode
|
||||
in the chosen set.
|
||||
.Pp
|
||||
.Ic Setty
|
||||
can also be used to set tty characters to particular values using
|
||||
.Ar char=value .
|
||||
If
|
||||
.Ar value
|
||||
is empty
|
||||
then the character is set to
|
||||
.Dv _POSIX_VDISABLE .
|
||||
.El
|
||||
.Sh EDITOR COMMANDS
|
||||
The following editor commands are available for use in key bindings:
|
||||
.\" Section automatically generated with makelist
|
||||
.Bl -tag -width 4n
|
||||
.It Ic vi-paste-next
|
||||
Vi paste previous deletion to the right of the cursor.
|
||||
.It Ic vi-paste-prev
|
||||
Vi paste previous deletion to the left of the cursor.
|
||||
.It Ic vi-prev-space-word
|
||||
Vi move to the previous space delimited word.
|
||||
.It Ic vi-prev-word
|
||||
Vi move to the previous word.
|
||||
.It Ic vi-next-space-word
|
||||
Vi move to the next space delimited word.
|
||||
.It Ic vi-next-word
|
||||
Vi move to the next word.
|
||||
.It Ic vi-change-case
|
||||
Vi change case of character under the cursor and advance one character.
|
||||
.It Ic vi-change-meta
|
||||
Vi change prefix command.
|
||||
.It Ic vi-insert-at-bol
|
||||
Vi enter insert mode at the beginning of line.
|
||||
.It Ic vi-replace-char
|
||||
Vi replace character under the cursor with the next character typed.
|
||||
.It Ic vi-replace-mode
|
||||
Vi enter replace mode.
|
||||
.It Ic vi-substitute-char
|
||||
Vi replace character under the cursor and enter insert mode.
|
||||
.It Ic vi-substitute-line
|
||||
Vi substitute entire line.
|
||||
.It Ic vi-change-to-eol
|
||||
Vi change to end of line.
|
||||
.It Ic vi-insert
|
||||
Vi enter insert mode.
|
||||
.It Ic vi-add
|
||||
Vi enter insert mode after the cursor.
|
||||
.It Ic vi-add-at-eol
|
||||
Vi enter insert mode at end of line.
|
||||
.It Ic vi-delete-meta
|
||||
Vi delete prefix command.
|
||||
.It Ic vi-end-word
|
||||
Vi move to the end of the current space delimited word.
|
||||
.It Ic vi-to-end-word
|
||||
Vi move to the end of the current word.
|
||||
.It Ic vi-undo
|
||||
Vi undo last change.
|
||||
.It Ic vi-command-mode
|
||||
Vi enter command mode (use alternative key bindings).
|
||||
.It Ic vi-zero
|
||||
Vi move to the beginning of line.
|
||||
.It Ic vi-delete-prev-char
|
||||
Vi move to previous character (backspace).
|
||||
.It Ic vi-list-or-eof
|
||||
Vi list choices for completion or indicate end of file if empty line.
|
||||
.It Ic vi-kill-line-prev
|
||||
Vi cut from beginning of line to cursor.
|
||||
.It Ic vi-search-prev
|
||||
Vi search history previous.
|
||||
.It Ic vi-search-next
|
||||
Vi search history next.
|
||||
.It Ic vi-repeat-search-next
|
||||
Vi repeat current search in the same search direction.
|
||||
.It Ic vi-repeat-search-prev
|
||||
Vi repeat current search in the opposite search direction.
|
||||
.It Ic vi-next-char
|
||||
Vi move to the character specified next.
|
||||
.It Ic vi-prev-char
|
||||
Vi move to the character specified previous.
|
||||
.It Ic vi-to-next-char
|
||||
Vi move up to the character specified next.
|
||||
.It Ic vi-to-prev-char
|
||||
Vi move up to the character specified previous.
|
||||
.It Ic vi-repeat-next-char
|
||||
Vi repeat current character search in the same search direction.
|
||||
.It Ic vi-repeat-prev-char
|
||||
Vi repeat current character search in the opposite search direction.
|
||||
.It Ic em-delete-or-list
|
||||
Delete character under cursor or list completions if at end of line.
|
||||
.It Ic em-delete-next-word
|
||||
Cut from cursor to end of current word.
|
||||
.It Ic em-yank
|
||||
Paste cut buffer at cursor position.
|
||||
.It Ic em-kill-line
|
||||
Cut the entire line and save in cut buffer.
|
||||
.It Ic em-kill-region
|
||||
Cut area between mark and cursor and save in cut buffer.
|
||||
.It Ic em-copy-region
|
||||
Copy area between mark and cursor to cut buffer.
|
||||
.It Ic em-gosmacs-transpose
|
||||
Exchange the two characters before the cursor.
|
||||
.It Ic em-next-word
|
||||
Move next to end of current word.
|
||||
.It Ic em-upper-case
|
||||
Uppercase the characters from cursor to end of current word.
|
||||
.It Ic em-capitol-case
|
||||
Capitalize the characters from cursor to end of current word.
|
||||
.It Ic em-lower-case
|
||||
Lowercase the characters from cursor to end of current word.
|
||||
.It Ic em-set-mark
|
||||
Set the mark at cursor.
|
||||
.It Ic em-exchange-mark
|
||||
Exchange the cursor and mark.
|
||||
.It Ic em-universal-argument
|
||||
Universal argument (argument times 4).
|
||||
.It Ic em-meta-next
|
||||
Add 8th bit to next character typed.
|
||||
.It Ic em-toggle-overwrite
|
||||
Switch from insert to overwrite mode or vice versa.
|
||||
.It Ic em-copy-prev-word
|
||||
Copy current word to cursor.
|
||||
.It Ic em-inc-search-next
|
||||
Emacs incremental next search.
|
||||
.It Ic em-inc-search-prev
|
||||
Emacs incremental reverse search.
|
||||
.It Ic ed-end-of-file
|
||||
Indicate end of file.
|
||||
.It Ic ed-insert
|
||||
Add character to the line.
|
||||
.It Ic ed-delete-prev-word
|
||||
Delete from beginning of current word to cursor.
|
||||
.It Ic ed-delete-next-char
|
||||
Delete character under cursor.
|
||||
.It Ic ed-kill-line
|
||||
Cut to the end of line.
|
||||
.It Ic ed-move-to-end
|
||||
Move cursor to the end of line.
|
||||
.It Ic ed-move-to-beg
|
||||
Move cursor to the beginning of line.
|
||||
.It Ic ed-transpose-chars
|
||||
Exchange the character to the left of the cursor with the one under it.
|
||||
.It Ic ed-next-char
|
||||
Move to the right one character.
|
||||
.It Ic ed-prev-word
|
||||
Move to the beginning of the current word.
|
||||
.It Ic ed-prev-char
|
||||
Move to the left one character.
|
||||
.It Ic ed-quoted-insert
|
||||
Add the next character typed verbatim.
|
||||
.It Ic ed-digit
|
||||
Adds to argument or enters a digit.
|
||||
.It Ic ed-argument-digit
|
||||
Digit that starts argument.
|
||||
.It Ic ed-unassigned
|
||||
Indicates unbound character.
|
||||
.It Ic ed-tty-sigint
|
||||
Tty interrupt character.
|
||||
.It Ic ed-tty-dsusp
|
||||
Tty delayed suspend character.
|
||||
.It Ic ed-tty-flush-output
|
||||
Tty flush output characters.
|
||||
.It Ic ed-tty-sigquit
|
||||
Tty quit character.
|
||||
.It Ic ed-tty-sigtstp
|
||||
Tty suspend character.
|
||||
.It Ic ed-tty-stop-output
|
||||
Tty disallow output characters.
|
||||
.It Ic ed-tty-start-output
|
||||
Tty allow output characters.
|
||||
.It Ic ed-newline
|
||||
Execute command.
|
||||
.It Ic ed-delete-prev-char
|
||||
Delete the character to the left of the cursor.
|
||||
.It Ic ed-clear-screen
|
||||
Clear screen leaving current line at the top.
|
||||
.It Ic ed-redisplay
|
||||
Redisplay everything.
|
||||
.It Ic ed-start-over
|
||||
Erase current line and start from scratch.
|
||||
.It Ic ed-sequence-lead-in
|
||||
First character in a bound sequence.
|
||||
.It Ic ed-prev-history
|
||||
Move to the previous history line.
|
||||
.It Ic ed-next-history
|
||||
Move to the next history line.
|
||||
.It Ic ed-search-prev-history
|
||||
Search previous in history for a line matching the current.
|
||||
.It Ic ed-search-next-history
|
||||
Search next in history for a line matching the current.
|
||||
.It Ic ed-prev-line
|
||||
Move up one line.
|
||||
.It Ic ed-next-line
|
||||
Move down one line.
|
||||
.It Ic ed-command
|
||||
Editline extended command.
|
||||
.El
|
||||
.\" End of section automatically generated with makelist
|
||||
.Sh SEE ALSO
|
||||
.Xr editline 3 ,
|
||||
.Xr regex 3 ,
|
||||
.Xr termcap 5
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm editline
|
||||
library was written by
|
||||
.An Christos Zoulas ,
|
||||
and this manual was written by
|
||||
.An Luke Mewburn ,
|
||||
with some sections inspired by
|
||||
.Xr tcsh 1 .
|
||||
@@ -0,0 +1,556 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: el.c,v 1.41 2005/08/19 04:21:47 christos Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.c: EditLine interface functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "el.h"
|
||||
|
||||
#define HAVE_ISSETUGID
|
||||
|
||||
/* el_init():
|
||||
* Initialize editline and set default parameters.
|
||||
*/
|
||||
public EditLine *
|
||||
el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
|
||||
{
|
||||
|
||||
EditLine *el = (EditLine *) el_malloc(sizeof(EditLine));
|
||||
|
||||
if (el == NULL)
|
||||
return (NULL);
|
||||
|
||||
memset(el, 0, sizeof(EditLine));
|
||||
|
||||
el->el_infd = fileno(fin);
|
||||
el->el_outfile = fout;
|
||||
el->el_errfile = ferr;
|
||||
if ((el->el_prog = el_strdup(prog)) == NULL) {
|
||||
el_free(el);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all the modules. Order is important!!!
|
||||
*/
|
||||
el->el_flags = 0;
|
||||
|
||||
if (term_init(el) == -1) {
|
||||
el_free(el->el_prog);
|
||||
el_free(el);
|
||||
return NULL;
|
||||
}
|
||||
(void) key_init(el);
|
||||
(void) map_init(el);
|
||||
if (tty_init(el) == -1)
|
||||
el->el_flags |= NO_TTY;
|
||||
(void) ch_init(el);
|
||||
(void) search_init(el);
|
||||
(void) hist_init(el);
|
||||
(void) prompt_init(el);
|
||||
(void) sig_init(el);
|
||||
(void) read_init(el);
|
||||
|
||||
return (el);
|
||||
}
|
||||
|
||||
|
||||
/* el_end():
|
||||
* Clean up.
|
||||
*/
|
||||
public void
|
||||
el_end(EditLine *el)
|
||||
{
|
||||
|
||||
if (el == NULL)
|
||||
return;
|
||||
|
||||
el_reset(el);
|
||||
|
||||
term_end(el);
|
||||
key_end(el);
|
||||
map_end(el);
|
||||
tty_end(el);
|
||||
ch_end(el);
|
||||
search_end(el);
|
||||
hist_end(el);
|
||||
prompt_end(el);
|
||||
sig_end(el);
|
||||
|
||||
el_free((ptr_t) el->el_prog);
|
||||
el_free((ptr_t) el);
|
||||
}
|
||||
|
||||
|
||||
/* el_reset():
|
||||
* Reset the tty and the parser
|
||||
*/
|
||||
public void
|
||||
el_reset(EditLine *el)
|
||||
{
|
||||
|
||||
tty_cookedmode(el);
|
||||
ch_reset(el, 0); /* XXX: Do we want that? */
|
||||
}
|
||||
|
||||
|
||||
/* el_set():
|
||||
* set the editline parameters
|
||||
*/
|
||||
public int
|
||||
el_set(EditLine *el, int op, ...)
|
||||
{
|
||||
va_list va;
|
||||
int rv = 0;
|
||||
|
||||
if (el == NULL)
|
||||
return (-1);
|
||||
va_start(va, op);
|
||||
|
||||
switch (op) {
|
||||
case EL_PROMPT:
|
||||
case EL_RPROMPT:
|
||||
rv = prompt_set(el, va_arg(va, el_pfunc_t), op);
|
||||
break;
|
||||
|
||||
case EL_TERMINAL:
|
||||
rv = term_set(el, va_arg(va, char *));
|
||||
break;
|
||||
|
||||
case EL_EDITOR:
|
||||
rv = map_set_editor(el, va_arg(va, char *));
|
||||
break;
|
||||
|
||||
case EL_SIGNAL:
|
||||
if (va_arg(va, int))
|
||||
el->el_flags |= HANDLE_SIGNALS;
|
||||
else
|
||||
el->el_flags &= ~HANDLE_SIGNALS;
|
||||
break;
|
||||
|
||||
case EL_BIND:
|
||||
case EL_TELLTC:
|
||||
case EL_SETTC:
|
||||
case EL_ECHOTC:
|
||||
case EL_SETTY:
|
||||
{
|
||||
const char *argv[20];
|
||||
int i;
|
||||
|
||||
for (i = 1; i < 20; i++)
|
||||
if ((argv[i] = va_arg(va, char *)) == NULL)
|
||||
break;
|
||||
|
||||
switch (op) {
|
||||
case EL_BIND:
|
||||
argv[0] = "bind";
|
||||
rv = map_bind(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_TELLTC:
|
||||
argv[0] = "telltc";
|
||||
rv = term_telltc(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_SETTC:
|
||||
argv[0] = "settc";
|
||||
rv = term_settc(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_ECHOTC:
|
||||
argv[0] = "echotc";
|
||||
rv = term_echotc(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_SETTY:
|
||||
argv[0] = "setty";
|
||||
rv = tty_stty(el, i, argv);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = -1;
|
||||
EL_ABORT((el->el_errfile, "Bad op %d\n", op));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EL_ADDFN:
|
||||
{
|
||||
char *name = va_arg(va, char *);
|
||||
char *help = va_arg(va, char *);
|
||||
el_func_t func = va_arg(va, el_func_t);
|
||||
|
||||
rv = map_addfunc(el, name, help, func);
|
||||
break;
|
||||
}
|
||||
|
||||
case EL_HIST:
|
||||
{
|
||||
hist_fun_t func = va_arg(va, hist_fun_t);
|
||||
ptr_t ptr = va_arg(va, char *);
|
||||
|
||||
rv = hist_set(el, func, ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case EL_EDITMODE:
|
||||
if (va_arg(va, int))
|
||||
el->el_flags &= ~EDIT_DISABLED;
|
||||
else
|
||||
el->el_flags |= EDIT_DISABLED;
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
case EL_GETCFN:
|
||||
{
|
||||
el_rfunc_t rc = va_arg(va, el_rfunc_t);
|
||||
rv = el_read_setfn(el, rc);
|
||||
break;
|
||||
}
|
||||
|
||||
case EL_CLIENTDATA:
|
||||
el->el_data = va_arg(va, void *);
|
||||
break;
|
||||
|
||||
case EL_UNBUFFERED:
|
||||
rv = va_arg(va, int);
|
||||
if (rv && !(el->el_flags & UNBUFFERED)) {
|
||||
el->el_flags |= UNBUFFERED;
|
||||
read_prepare(el);
|
||||
} else if (!rv && (el->el_flags & UNBUFFERED)) {
|
||||
el->el_flags &= ~UNBUFFERED;
|
||||
read_finish(el);
|
||||
}
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
case EL_PREP_TERM:
|
||||
rv = va_arg(va, int);
|
||||
if (rv)
|
||||
(void) tty_rawmode(el);
|
||||
else
|
||||
(void) tty_cookedmode(el);
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(va);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
|
||||
/* el_get():
|
||||
* retrieve the editline parameters
|
||||
*/
|
||||
public int
|
||||
el_get(EditLine *el, int op, void *ret)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (el == NULL || ret == NULL)
|
||||
return (-1);
|
||||
switch (op) {
|
||||
case EL_PROMPT:
|
||||
case EL_RPROMPT:
|
||||
rv = prompt_get(el, (el_pfunc_t *) ret, op);
|
||||
break;
|
||||
|
||||
case EL_EDITOR:
|
||||
rv = map_get_editor(el, (const char **)ret);
|
||||
break;
|
||||
|
||||
case EL_SIGNAL:
|
||||
*((int *) ret) = (el->el_flags & HANDLE_SIGNALS);
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
case EL_EDITMODE:
|
||||
*((int *) ret) = (!(el->el_flags & EDIT_DISABLED));
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
case EL_TERMINAL:
|
||||
term_get(el, (const char **)ret);
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
#if 0 /* XXX */
|
||||
case EL_BIND:
|
||||
case EL_TELLTC:
|
||||
case EL_SETTC:
|
||||
case EL_ECHOTC:
|
||||
case EL_SETTY:
|
||||
{
|
||||
const char *argv[20];
|
||||
int i;
|
||||
|
||||
for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++)
|
||||
if ((argv[i] = va_arg(va, char *)) == NULL)
|
||||
break;
|
||||
|
||||
switch (op) {
|
||||
case EL_BIND:
|
||||
argv[0] = "bind";
|
||||
rv = map_bind(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_TELLTC:
|
||||
argv[0] = "telltc";
|
||||
rv = term_telltc(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_SETTC:
|
||||
argv[0] = "settc";
|
||||
rv = term_settc(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_ECHOTC:
|
||||
argv[0] = "echotc";
|
||||
rv = term_echotc(el, i, argv);
|
||||
break;
|
||||
|
||||
case EL_SETTY:
|
||||
argv[0] = "setty";
|
||||
rv = tty_stty(el, i, argv);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = -1;
|
||||
EL_ABORT((el->errfile, "Bad op %d\n", op));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EL_ADDFN:
|
||||
{
|
||||
char *name = va_arg(va, char *);
|
||||
char *help = va_arg(va, char *);
|
||||
el_func_t func = va_arg(va, el_func_t);
|
||||
|
||||
rv = map_addfunc(el, name, help, func);
|
||||
break;
|
||||
}
|
||||
|
||||
case EL_HIST:
|
||||
{
|
||||
hist_fun_t func = va_arg(va, hist_fun_t);
|
||||
ptr_t ptr = va_arg(va, char *);
|
||||
rv = hist_set(el, func, ptr);
|
||||
}
|
||||
break;
|
||||
#endif /* XXX */
|
||||
|
||||
case EL_GETCFN:
|
||||
*((el_rfunc_t *)ret) = el_read_getfn(el);
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
case EL_CLIENTDATA:
|
||||
*((void **)ret) = el->el_data;
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
case EL_UNBUFFERED:
|
||||
*((int *) ret) = (!(el->el_flags & UNBUFFERED));
|
||||
rv = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/* el_data_get():
|
||||
* Set user private data.
|
||||
*/
|
||||
public void
|
||||
el_data_set (el, data)
|
||||
EditLine *el;
|
||||
void *data;
|
||||
{
|
||||
el->el_data = data;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* el_data_get():
|
||||
* Return user private data.
|
||||
*/
|
||||
public void *
|
||||
el_data_get (el)
|
||||
EditLine *el;
|
||||
{
|
||||
if (el->el_data)
|
||||
return (el->el_data);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* el_line():
|
||||
* Return editing info
|
||||
*/
|
||||
public const LineInfo *
|
||||
el_line(EditLine *el)
|
||||
{
|
||||
|
||||
return (const LineInfo *) (void *) &el->el_line;
|
||||
}
|
||||
|
||||
|
||||
/* el_source():
|
||||
* Source a file
|
||||
*/
|
||||
public int
|
||||
el_source(EditLine *el, const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
size_t len;
|
||||
char *ptr;
|
||||
|
||||
fp = NULL;
|
||||
if (fname == NULL) {
|
||||
#ifdef HAVE_ISSETUGID
|
||||
static const char elpath[] = "/.editrc";
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
if (issetugid())
|
||||
return (-1);
|
||||
if ((ptr = getenv("HOME")) == NULL)
|
||||
return (-1);
|
||||
if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
|
||||
return (-1);
|
||||
if (strlcat(path, elpath, sizeof(path)) >= sizeof(path))
|
||||
return (-1);
|
||||
fname = path;
|
||||
#else
|
||||
/*
|
||||
* If issetugid() is missing, always return an error, in order
|
||||
* to keep from inadvertently opening up the user to a security
|
||||
* hole.
|
||||
*/
|
||||
return (-1);
|
||||
#endif
|
||||
}
|
||||
if (fp == NULL)
|
||||
fp = fopen(fname, "r");
|
||||
if (fp == NULL)
|
||||
return (-1);
|
||||
|
||||
while ((ptr = fgetln(fp, &len)) != NULL) {
|
||||
if (len > 0 && ptr[len - 1] == '\n')
|
||||
--len;
|
||||
ptr[len] = '\0';
|
||||
if (parse_line(el, ptr) == -1) {
|
||||
(void) fclose(fp);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
(void) fclose(fp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* el_resize():
|
||||
* Called from program when terminal is resized
|
||||
*/
|
||||
public void
|
||||
el_resize(EditLine *el)
|
||||
{
|
||||
int lins, cols;
|
||||
sigset_t oset, nset;
|
||||
|
||||
(void) sigemptyset(&nset);
|
||||
(void) sigaddset(&nset, SIGWINCH);
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
|
||||
/* get the correct window size */
|
||||
if (term_get_size(el, &lins, &cols))
|
||||
term_change_size(el, lins, cols);
|
||||
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* el_beep():
|
||||
* Called from the program to beep
|
||||
*/
|
||||
public void
|
||||
el_beep(EditLine *el)
|
||||
{
|
||||
|
||||
term_beep(el);
|
||||
}
|
||||
|
||||
|
||||
/* el_editmode()
|
||||
* Set the state of EDIT_DISABLED from the `edit' command.
|
||||
*/
|
||||
protected int
|
||||
/*ARGSUSED*/
|
||||
el_editmode(EditLine *el, int argc, const char **argv)
|
||||
{
|
||||
const char *how;
|
||||
|
||||
if (argv == NULL || argc != 2 || argv[1] == NULL)
|
||||
return (-1);
|
||||
|
||||
how = argv[1];
|
||||
if (strcmp(how, "on") == 0) {
|
||||
el->el_flags &= ~EDIT_DISABLED;
|
||||
tty_rawmode(el);
|
||||
} else if (strcmp(how, "off") == 0) {
|
||||
tty_cookedmode(el);
|
||||
el->el_flags |= EDIT_DISABLED;
|
||||
}
|
||||
else {
|
||||
(void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how);
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)el.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: el.h,v 1.16 2003/10/18 23:48:42 christos Exp $
|
||||
* $FreeBSD: src/lib/libedit/el.h,v 1.6 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.h: Internal structures.
|
||||
*/
|
||||
#ifndef _h_el
|
||||
#define _h_el
|
||||
/*
|
||||
* Local defaults
|
||||
*/
|
||||
#define KSHVI
|
||||
#define VIDEFAULT
|
||||
#define ANCHOR
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define EL_BUFSIZ 1024 /* Maximum line size */
|
||||
|
||||
#define HANDLE_SIGNALS 0x01
|
||||
#define NO_TTY 0x02
|
||||
#define EDIT_DISABLED 0x04
|
||||
#define UNBUFFERED 0x08
|
||||
|
||||
typedef int bool_t; /* True or not */
|
||||
|
||||
typedef unsigned char el_action_t; /* Index to command array */
|
||||
|
||||
typedef struct coord_t { /* Position on the screen */
|
||||
int h;
|
||||
int v;
|
||||
} coord_t;
|
||||
|
||||
typedef struct el_line_t {
|
||||
char *buffer; /* Input line */
|
||||
char *cursor; /* Cursor position */
|
||||
char *lastchar; /* Last character */
|
||||
const char *limit; /* Max position */
|
||||
} el_line_t;
|
||||
|
||||
/*
|
||||
* Editor state
|
||||
*/
|
||||
typedef struct el_state_t {
|
||||
int inputmode; /* What mode are we in? */
|
||||
int doingarg; /* Are we getting an argument? */
|
||||
int argument; /* Numeric argument */
|
||||
int metanext; /* Is the next char a meta char */
|
||||
el_action_t lastcmd; /* Previous command */
|
||||
el_action_t thiscmd; /* this command */
|
||||
char thisch; /* char that generated it */
|
||||
} el_state_t;
|
||||
|
||||
/*
|
||||
* Until we come up with something better...
|
||||
*/
|
||||
#define el_strdup(a) strdup(a)
|
||||
#define el_malloc(a) malloc(a)
|
||||
#define el_realloc(a,b) realloc(a, b)
|
||||
#define el_free(a) free(a)
|
||||
|
||||
#include "tty.h"
|
||||
#include "prompt.h"
|
||||
#include "key.h"
|
||||
#include "term.h"
|
||||
#include "refresh.h"
|
||||
#include "chared.h"
|
||||
#include "common.h"
|
||||
#include "search.h"
|
||||
#include "hist.h"
|
||||
#include "map.h"
|
||||
#include "parse.h"
|
||||
#include "sig.h"
|
||||
#include "help.h"
|
||||
#include "read.h"
|
||||
|
||||
struct editline {
|
||||
char *el_prog; /* the program name */
|
||||
FILE *el_outfile; /* Stdio stuff */
|
||||
FILE *el_errfile; /* Stdio stuff */
|
||||
int el_infd; /* Input file descriptor */
|
||||
int el_flags; /* Various flags. */
|
||||
coord_t el_cursor; /* Cursor location */
|
||||
char **el_display; /* Real screen image = what is there */
|
||||
char **el_vdisplay; /* Virtual screen image = what we see */
|
||||
void *el_data; /* Client data */
|
||||
el_line_t el_line; /* The current line information */
|
||||
el_state_t el_state; /* Current editor state */
|
||||
el_term_t el_term; /* Terminal dependent stuff */
|
||||
el_tty_t el_tty; /* Tty dependent stuff */
|
||||
el_refresh_t el_refresh; /* Refresh stuff */
|
||||
el_prompt_t el_prompt; /* Prompt stuff */
|
||||
el_prompt_t el_rprompt; /* Prompt stuff */
|
||||
el_chared_t el_chared; /* Characted editor stuff */
|
||||
el_map_t el_map; /* Key mapping stuff */
|
||||
el_key_t el_key; /* Key binding stuff */
|
||||
el_history_t el_history; /* History stuff */
|
||||
el_search_t el_search; /* Search stuff */
|
||||
el_signal_t el_signal; /* Signal handling stuff */
|
||||
el_read_t el_read; /* Character reading stuff */
|
||||
};
|
||||
|
||||
protected int el_editmode(EditLine *, int, const char **);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define EL_ABORT(a) do { \
|
||||
fprintf(el->el_errfile, "%s, %d: ", \
|
||||
__FILE__, __LINE__); \
|
||||
fprintf a; \
|
||||
abort(); \
|
||||
} while( /*CONSTCOND*/0);
|
||||
#else
|
||||
#define EL_ABORT(a) abort()
|
||||
#endif
|
||||
#endif /* _h_el */
|
||||
@@ -0,0 +1,503 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: emacs.c,v 1.20 2005/08/08 14:05:37 christos Exp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/emacs.c,v 1.10 2005/08/09 13:37:59 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* emacs.c: Emacs functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include "el.h"
|
||||
|
||||
/* em_delete_or_list():
|
||||
* Delete character under cursor or list completions if at end of line
|
||||
* [^D]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_delete_or_list(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor == el->el_line.lastchar) {
|
||||
/* if I'm at the end */
|
||||
if (el->el_line.cursor == el->el_line.buffer) {
|
||||
/* and the beginning */
|
||||
term_overwrite(el, STReof, 4); /* then do an EOF */
|
||||
term__flush();
|
||||
return (CC_EOF);
|
||||
} else {
|
||||
/*
|
||||
* Here we could list completions, but it is an
|
||||
* error right now
|
||||
*/
|
||||
term_beep(el);
|
||||
return (CC_ERROR);
|
||||
}
|
||||
} else {
|
||||
if (el->el_state.doingarg)
|
||||
c_delafter(el, el->el_state.argument);
|
||||
else
|
||||
c_delafter1(el);
|
||||
if (el->el_line.cursor > el->el_line.lastchar)
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
/* bounds check */
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* em_delete_next_word():
|
||||
* Cut from cursor to end of current word
|
||||
* [M-d]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_delete_next_word(EditLine *el, int c __unused)
|
||||
{
|
||||
char *cp, *p, *kp;
|
||||
|
||||
if (el->el_line.cursor == el->el_line.lastchar)
|
||||
return (CC_ERROR);
|
||||
|
||||
cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
|
||||
el->el_state.argument, ce__isword);
|
||||
|
||||
for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
|
||||
/* save the text */
|
||||
*kp++ = *p;
|
||||
el->el_chared.c_kill.last = kp;
|
||||
|
||||
c_delafter(el, cp - el->el_line.cursor); /* delete after dot */
|
||||
if (el->el_line.cursor > el->el_line.lastchar)
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
/* bounds check */
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_yank():
|
||||
* Paste cut buffer at cursor position
|
||||
* [^Y]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_yank(EditLine *el, int c __unused)
|
||||
{
|
||||
char *kp, *cp;
|
||||
|
||||
if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
|
||||
return (CC_NORM);
|
||||
|
||||
if (el->el_line.lastchar +
|
||||
(el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
|
||||
el->el_line.limit)
|
||||
return (CC_ERROR);
|
||||
|
||||
el->el_chared.c_kill.mark = el->el_line.cursor;
|
||||
cp = el->el_line.cursor;
|
||||
|
||||
/* open the space, */
|
||||
c_insert(el, el->el_chared.c_kill.last - el->el_chared.c_kill.buf);
|
||||
/* copy the chars */
|
||||
for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
|
||||
*cp++ = *kp;
|
||||
|
||||
/* if an arg, cursor at beginning else cursor at end */
|
||||
if (el->el_state.argument == 1)
|
||||
el->el_line.cursor = cp;
|
||||
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_kill_line():
|
||||
* Cut the entire line and save in cut buffer
|
||||
* [^U]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_kill_line(EditLine *el, int c __unused)
|
||||
{
|
||||
char *kp, *cp;
|
||||
|
||||
cp = el->el_line.buffer;
|
||||
kp = el->el_chared.c_kill.buf;
|
||||
while (cp < el->el_line.lastchar)
|
||||
*kp++ = *cp++; /* copy it */
|
||||
el->el_chared.c_kill.last = kp;
|
||||
/* zap! -- delete all of it */
|
||||
el->el_line.lastchar = el->el_line.buffer;
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_kill_region():
|
||||
* Cut area between mark and cursor and save in cut buffer
|
||||
* [^W]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_kill_region(EditLine *el, int c __unused)
|
||||
{
|
||||
char *kp, *cp;
|
||||
|
||||
if (!el->el_chared.c_kill.mark)
|
||||
return (CC_ERROR);
|
||||
|
||||
if (el->el_chared.c_kill.mark > el->el_line.cursor) {
|
||||
cp = el->el_line.cursor;
|
||||
kp = el->el_chared.c_kill.buf;
|
||||
while (cp < el->el_chared.c_kill.mark)
|
||||
*kp++ = *cp++; /* copy it */
|
||||
el->el_chared.c_kill.last = kp;
|
||||
c_delafter(el, cp - el->el_line.cursor);
|
||||
} else { /* mark is before cursor */
|
||||
cp = el->el_chared.c_kill.mark;
|
||||
kp = el->el_chared.c_kill.buf;
|
||||
while (cp < el->el_line.cursor)
|
||||
*kp++ = *cp++; /* copy it */
|
||||
el->el_chared.c_kill.last = kp;
|
||||
c_delbefore(el, cp - el->el_chared.c_kill.mark);
|
||||
el->el_line.cursor = el->el_chared.c_kill.mark;
|
||||
}
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_copy_region():
|
||||
* Copy area between mark and cursor to cut buffer
|
||||
* [M-W]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_copy_region(EditLine *el, int c __unused)
|
||||
{
|
||||
char *kp, *cp;
|
||||
|
||||
if (!el->el_chared.c_kill.mark)
|
||||
return (CC_ERROR);
|
||||
|
||||
if (el->el_chared.c_kill.mark > el->el_line.cursor) {
|
||||
cp = el->el_line.cursor;
|
||||
kp = el->el_chared.c_kill.buf;
|
||||
while (cp < el->el_chared.c_kill.mark)
|
||||
*kp++ = *cp++; /* copy it */
|
||||
el->el_chared.c_kill.last = kp;
|
||||
} else {
|
||||
cp = el->el_chared.c_kill.mark;
|
||||
kp = el->el_chared.c_kill.buf;
|
||||
while (cp < el->el_line.cursor)
|
||||
*kp++ = *cp++; /* copy it */
|
||||
el->el_chared.c_kill.last = kp;
|
||||
}
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* em_gosmacs_transpose():
|
||||
* Exchange the two characters before the cursor
|
||||
* Gosling emacs transpose chars [^T]
|
||||
*/
|
||||
protected el_action_t
|
||||
em_gosmacs_transpose(EditLine *el, int c)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor > &el->el_line.buffer[1]) {
|
||||
/* must have at least two chars entered */
|
||||
c = el->el_line.cursor[-2];
|
||||
el->el_line.cursor[-2] = el->el_line.cursor[-1];
|
||||
el->el_line.cursor[-1] = c;
|
||||
return (CC_REFRESH);
|
||||
} else
|
||||
return (CC_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/* em_next_word():
|
||||
* Move next to end of current word
|
||||
* [M-f]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_next_word(EditLine *el, int c __unused)
|
||||
{
|
||||
if (el->el_line.cursor == el->el_line.lastchar)
|
||||
return (CC_ERROR);
|
||||
|
||||
el->el_line.cursor = c__next_word(el->el_line.cursor,
|
||||
el->el_line.lastchar,
|
||||
el->el_state.argument,
|
||||
ce__isword);
|
||||
|
||||
if (el->el_map.type == MAP_VI)
|
||||
if (el->el_chared.c_vcmd.action != NOP) {
|
||||
cv_delfini(el);
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* em_upper_case():
|
||||
* Uppercase the characters from cursor to end of current word
|
||||
* [M-u]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_upper_case(EditLine *el, int c __unused)
|
||||
{
|
||||
char *cp, *ep;
|
||||
|
||||
ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
|
||||
el->el_state.argument, ce__isword);
|
||||
|
||||
for (cp = el->el_line.cursor; cp < ep; cp++)
|
||||
if (islower((unsigned char)*cp))
|
||||
*cp = toupper((unsigned char)*cp);
|
||||
|
||||
el->el_line.cursor = ep;
|
||||
if (el->el_line.cursor > el->el_line.lastchar)
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_capitol_case():
|
||||
* Capitalize the characters from cursor to end of current word
|
||||
* [M-c]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_capitol_case(EditLine *el, int c __unused)
|
||||
{
|
||||
char *cp, *ep;
|
||||
|
||||
ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
|
||||
el->el_state.argument, ce__isword);
|
||||
|
||||
for (cp = el->el_line.cursor; cp < ep; cp++) {
|
||||
if (isalpha((unsigned char)*cp)) {
|
||||
if (islower((unsigned char)*cp))
|
||||
*cp = toupper((unsigned char)*cp);
|
||||
cp++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; cp < ep; cp++)
|
||||
if (isupper((unsigned char)*cp))
|
||||
*cp = tolower((unsigned char)*cp);
|
||||
|
||||
el->el_line.cursor = ep;
|
||||
if (el->el_line.cursor > el->el_line.lastchar)
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_lower_case():
|
||||
* Lowercase the characters from cursor to end of current word
|
||||
* [M-l]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_lower_case(EditLine *el, int c __unused)
|
||||
{
|
||||
char *cp, *ep;
|
||||
|
||||
ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
|
||||
el->el_state.argument, ce__isword);
|
||||
|
||||
for (cp = el->el_line.cursor; cp < ep; cp++)
|
||||
if (isupper((unsigned char)*cp))
|
||||
*cp = tolower((unsigned char)*cp);
|
||||
|
||||
el->el_line.cursor = ep;
|
||||
if (el->el_line.cursor > el->el_line.lastchar)
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_set_mark():
|
||||
* Set the mark at cursor
|
||||
* [^@]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_set_mark(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
el->el_chared.c_kill.mark = el->el_line.cursor;
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* em_exchange_mark():
|
||||
* Exchange the cursor and mark
|
||||
* [^X^X]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_exchange_mark(EditLine *el, int c __unused)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
cp = el->el_line.cursor;
|
||||
el->el_line.cursor = el->el_chared.c_kill.mark;
|
||||
el->el_chared.c_kill.mark = cp;
|
||||
return (CC_CURSOR);
|
||||
}
|
||||
|
||||
|
||||
/* em_universal_argument():
|
||||
* Universal argument (argument times 4)
|
||||
* [^U]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_universal_argument(EditLine *el, int c __unused)
|
||||
{ /* multiply current argument by 4 */
|
||||
|
||||
if (el->el_state.argument > 1000000)
|
||||
return (CC_ERROR);
|
||||
el->el_state.doingarg = 1;
|
||||
el->el_state.argument *= 4;
|
||||
return (CC_ARGHACK);
|
||||
}
|
||||
|
||||
|
||||
/* em_meta_next():
|
||||
* Add 8th bit to next character typed
|
||||
* [<ESC>]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_meta_next(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
el->el_state.metanext = 1;
|
||||
return (CC_ARGHACK);
|
||||
}
|
||||
|
||||
|
||||
/* em_toggle_overwrite():
|
||||
* Switch from insert to overwrite mode or vice versa
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_toggle_overwrite(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
|
||||
MODE_REPLACE : MODE_INSERT;
|
||||
return (CC_NORM);
|
||||
}
|
||||
|
||||
|
||||
/* em_copy_prev_word():
|
||||
* Copy current word to cursor
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_copy_prev_word(EditLine *el, int c __unused)
|
||||
{
|
||||
char *cp, *oldc, *dp;
|
||||
|
||||
if (el->el_line.cursor == el->el_line.buffer)
|
||||
return (CC_ERROR);
|
||||
|
||||
oldc = el->el_line.cursor;
|
||||
/* does a bounds check */
|
||||
cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
|
||||
el->el_state.argument, ce__isword);
|
||||
|
||||
c_insert(el, oldc - cp);
|
||||
for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
|
||||
*dp++ = *cp;
|
||||
|
||||
el->el_line.cursor = dp;/* put cursor at end */
|
||||
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* em_inc_search_next():
|
||||
* Emacs incremental next search
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_inc_search_next(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
el->el_search.patlen = 0;
|
||||
return (ce_inc_search(el, ED_SEARCH_NEXT_HISTORY));
|
||||
}
|
||||
|
||||
|
||||
/* em_inc_search_prev():
|
||||
* Emacs incremental reverse search
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_inc_search_prev(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
el->el_search.patlen = 0;
|
||||
return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY));
|
||||
}
|
||||
|
||||
|
||||
/* em_delete_prev_char():
|
||||
* Delete the character to the left of the cursor
|
||||
* [^?]
|
||||
*/
|
||||
protected el_action_t
|
||||
/*ARGSUSED*/
|
||||
em_delete_prev_char(EditLine *el, int c __unused)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor <= el->el_line.buffer)
|
||||
return (CC_ERROR);
|
||||
|
||||
if (el->el_state.doingarg)
|
||||
c_delbefore(el, el->el_state.argument);
|
||||
else
|
||||
c_delbefore1(el);
|
||||
el->el_line.cursor -= el->el_state.argument;
|
||||
if (el->el_line.cursor < el->el_line.buffer)
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Automatically generated file, do not edit */
|
||||
#ifndef _h_emacs_c
|
||||
#define _h_emacs_c
|
||||
protected el_action_t em_delete_or_list (EditLine *, int);
|
||||
protected el_action_t em_delete_next_word (EditLine *, int);
|
||||
protected el_action_t em_yank (EditLine *, int);
|
||||
protected el_action_t em_kill_line (EditLine *, int);
|
||||
protected el_action_t em_kill_region (EditLine *, int);
|
||||
protected el_action_t em_copy_region (EditLine *, int);
|
||||
protected el_action_t em_gosmacs_transpose (EditLine *, int);
|
||||
protected el_action_t em_next_word (EditLine *, int);
|
||||
protected el_action_t em_upper_case (EditLine *, int);
|
||||
protected el_action_t em_capitol_case (EditLine *, int);
|
||||
protected el_action_t em_lower_case (EditLine *, int);
|
||||
protected el_action_t em_set_mark (EditLine *, int);
|
||||
protected el_action_t em_exchange_mark (EditLine *, int);
|
||||
protected el_action_t em_universal_argument (EditLine *, int);
|
||||
protected el_action_t em_meta_next (EditLine *, int);
|
||||
protected el_action_t em_toggle_overwrite (EditLine *, int);
|
||||
protected el_action_t em_copy_prev_word (EditLine *, int);
|
||||
protected el_action_t em_inc_search_next (EditLine *, int);
|
||||
protected el_action_t em_inc_search_prev (EditLine *, int);
|
||||
protected el_action_t em_delete_prev_char (EditLine *, int);
|
||||
#endif /* _h_emacs_c */
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Automatically generated file, do not edit */
|
||||
#include "sys.h"
|
||||
#include "el.h"
|
||||
private const el_func_t el_func[] = {
|
||||
ed_argument_digit, ed_clear_screen,
|
||||
ed_command, ed_delete_next_char,
|
||||
ed_delete_prev_char, ed_delete_prev_word,
|
||||
ed_digit, ed_end_of_file,
|
||||
ed_insert, ed_kill_line,
|
||||
ed_move_to_beg, ed_move_to_end,
|
||||
ed_newline, ed_next_char,
|
||||
ed_next_history, ed_next_line,
|
||||
ed_prev_char, ed_prev_history,
|
||||
ed_prev_line, ed_prev_word,
|
||||
ed_quoted_insert, ed_redisplay,
|
||||
ed_search_next_history, ed_search_prev_history,
|
||||
ed_sequence_lead_in, ed_start_over,
|
||||
ed_transpose_chars, ed_tty_dsusp,
|
||||
ed_tty_flush_output, ed_tty_sigint,
|
||||
ed_tty_sigquit, ed_tty_sigtstp,
|
||||
ed_tty_start_output, ed_tty_stop_output,
|
||||
ed_unassigned, em_capitol_case,
|
||||
em_copy_prev_word, em_copy_region,
|
||||
em_delete_next_word, em_delete_or_list,
|
||||
em_delete_prev_char, em_exchange_mark,
|
||||
em_gosmacs_transpose, em_inc_search_next,
|
||||
em_inc_search_prev, em_kill_line,
|
||||
em_kill_region, em_lower_case,
|
||||
em_meta_next, em_next_word,
|
||||
em_set_mark, em_toggle_overwrite,
|
||||
em_universal_argument, em_upper_case,
|
||||
em_yank, vi_add,
|
||||
vi_add_at_eol, vi_alias,
|
||||
vi_change_case, vi_change_meta,
|
||||
vi_change_to_eol, vi_command_mode,
|
||||
vi_comment_out, vi_delete_meta,
|
||||
vi_delete_prev_char, vi_end_big_word,
|
||||
vi_end_word, vi_histedit,
|
||||
vi_history_word, vi_insert,
|
||||
vi_insert_at_bol, vi_kill_line_prev,
|
||||
vi_list_or_eof, vi_match,
|
||||
vi_next_big_word, vi_next_char,
|
||||
vi_next_word, vi_paste_next,
|
||||
vi_paste_prev, vi_prev_big_word,
|
||||
vi_prev_char, vi_prev_word,
|
||||
vi_redo, vi_repeat_next_char,
|
||||
vi_repeat_prev_char, vi_repeat_search_next,
|
||||
vi_repeat_search_prev, vi_replace_char,
|
||||
vi_replace_mode, vi_search_next,
|
||||
vi_search_prev, vi_substitute_char,
|
||||
vi_substitute_line, vi_to_column,
|
||||
vi_to_history_line, vi_to_next_char,
|
||||
vi_to_prev_char, vi_undo,
|
||||
vi_undo_line, vi_yank,
|
||||
vi_yank_end, vi_zero,
|
||||
};
|
||||
|
||||
protected const el_func_t* func__get() { return el_func; }
|
||||
@@ -0,0 +1,109 @@
|
||||
/* Automatically generated file, do not edit */
|
||||
#ifndef _h_fcns_c
|
||||
#define _h_fcns_c
|
||||
#define ED_ARGUMENT_DIGIT 0
|
||||
#define ED_CLEAR_SCREEN 1
|
||||
#define ED_COMMAND 2
|
||||
#define ED_DELETE_NEXT_CHAR 3
|
||||
#define ED_DELETE_PREV_CHAR 4
|
||||
#define ED_DELETE_PREV_WORD 5
|
||||
#define ED_DIGIT 6
|
||||
#define ED_END_OF_FILE 7
|
||||
#define ED_INSERT 8
|
||||
#define ED_KILL_LINE 9
|
||||
#define ED_MOVE_TO_BEG 10
|
||||
#define ED_MOVE_TO_END 11
|
||||
#define ED_NEWLINE 12
|
||||
#define ED_NEXT_CHAR 13
|
||||
#define ED_NEXT_HISTORY 14
|
||||
#define ED_NEXT_LINE 15
|
||||
#define ED_PREV_CHAR 16
|
||||
#define ED_PREV_HISTORY 17
|
||||
#define ED_PREV_LINE 18
|
||||
#define ED_PREV_WORD 19
|
||||
#define ED_QUOTED_INSERT 20
|
||||
#define ED_REDISPLAY 21
|
||||
#define ED_SEARCH_NEXT_HISTORY 22
|
||||
#define ED_SEARCH_PREV_HISTORY 23
|
||||
#define ED_SEQUENCE_LEAD_IN 24
|
||||
#define ED_START_OVER 25
|
||||
#define ED_TRANSPOSE_CHARS 26
|
||||
#define ED_TTY_DSUSP 27
|
||||
#define ED_TTY_FLUSH_OUTPUT 28
|
||||
#define ED_TTY_SIGINT 29
|
||||
#define ED_TTY_SIGQUIT 30
|
||||
#define ED_TTY_SIGTSTP 31
|
||||
#define ED_TTY_START_OUTPUT 32
|
||||
#define ED_TTY_STOP_OUTPUT 33
|
||||
#define ED_UNASSIGNED 34
|
||||
#define EM_CAPITOL_CASE 35
|
||||
#define EM_COPY_PREV_WORD 36
|
||||
#define EM_COPY_REGION 37
|
||||
#define EM_DELETE_NEXT_WORD 38
|
||||
#define EM_DELETE_OR_LIST 39
|
||||
#define EM_DELETE_PREV_CHAR 40
|
||||
#define EM_EXCHANGE_MARK 41
|
||||
#define EM_GOSMACS_TRANSPOSE 42
|
||||
#define EM_INC_SEARCH_NEXT 43
|
||||
#define EM_INC_SEARCH_PREV 44
|
||||
#define EM_KILL_LINE 45
|
||||
#define EM_KILL_REGION 46
|
||||
#define EM_LOWER_CASE 47
|
||||
#define EM_META_NEXT 48
|
||||
#define EM_NEXT_WORD 49
|
||||
#define EM_SET_MARK 50
|
||||
#define EM_TOGGLE_OVERWRITE 51
|
||||
#define EM_UNIVERSAL_ARGUMENT 52
|
||||
#define EM_UPPER_CASE 53
|
||||
#define EM_YANK 54
|
||||
#define VI_ADD 55
|
||||
#define VI_ADD_AT_EOL 56
|
||||
#define VI_ALIAS 57
|
||||
#define VI_CHANGE_CASE 58
|
||||
#define VI_CHANGE_META 59
|
||||
#define VI_CHANGE_TO_EOL 60
|
||||
#define VI_COMMAND_MODE 61
|
||||
#define VI_COMMENT_OUT 62
|
||||
#define VI_DELETE_META 63
|
||||
#define VI_DELETE_PREV_CHAR 64
|
||||
#define VI_END_BIG_WORD 65
|
||||
#define VI_END_WORD 66
|
||||
#define VI_HISTEDIT 67
|
||||
#define VI_HISTORY_WORD 68
|
||||
#define VI_INSERT 69
|
||||
#define VI_INSERT_AT_BOL 70
|
||||
#define VI_KILL_LINE_PREV 71
|
||||
#define VI_LIST_OR_EOF 72
|
||||
#define VI_MATCH 73
|
||||
#define VI_NEXT_BIG_WORD 74
|
||||
#define VI_NEXT_CHAR 75
|
||||
#define VI_NEXT_WORD 76
|
||||
#define VI_PASTE_NEXT 77
|
||||
#define VI_PASTE_PREV 78
|
||||
#define VI_PREV_BIG_WORD 79
|
||||
#define VI_PREV_CHAR 80
|
||||
#define VI_PREV_WORD 81
|
||||
#define VI_REDO 82
|
||||
#define VI_REPEAT_NEXT_CHAR 83
|
||||
#define VI_REPEAT_PREV_CHAR 84
|
||||
#define VI_REPEAT_SEARCH_NEXT 85
|
||||
#define VI_REPEAT_SEARCH_PREV 86
|
||||
#define VI_REPLACE_CHAR 87
|
||||
#define VI_REPLACE_MODE 88
|
||||
#define VI_SEARCH_NEXT 89
|
||||
#define VI_SEARCH_PREV 90
|
||||
#define VI_SUBSTITUTE_CHAR 91
|
||||
#define VI_SUBSTITUTE_LINE 92
|
||||
#define VI_TO_COLUMN 93
|
||||
#define VI_TO_HISTORY_LINE 94
|
||||
#define VI_TO_NEXT_CHAR 95
|
||||
#define VI_TO_PREV_CHAR 96
|
||||
#define VI_UNDO 97
|
||||
#define VI_UNDO_LINE 98
|
||||
#define VI_YANK 99
|
||||
#define VI_YANK_END 100
|
||||
#define VI_ZERO 101
|
||||
#define EL_NUM_FCNS 102
|
||||
typedef el_action_t (*el_func_t)(EditLine *, int);
|
||||
protected const el_func_t* func__get(void);
|
||||
#endif /* _h_fcns_c */
|
||||
@@ -0,0 +1,211 @@
|
||||
/* Automatically generated file, do not edit */
|
||||
#include "sys.h"
|
||||
#include "el.h"
|
||||
private const struct el_bindings_t el_func_help[] = {
|
||||
{ "vi-paste-next", VI_PASTE_NEXT,
|
||||
"Vi paste previous deletion to the right of the cursor" },
|
||||
{ "vi-paste-prev", VI_PASTE_PREV,
|
||||
"Vi paste previous deletion to the left of the cursor" },
|
||||
{ "vi-prev-big-word", VI_PREV_BIG_WORD,
|
||||
"Vi move to the previous space delimited word" },
|
||||
{ "vi-prev-word", VI_PREV_WORD,
|
||||
"Vi move to the previous word" },
|
||||
{ "vi-next-big-word", VI_NEXT_BIG_WORD,
|
||||
"Vi move to the next space delimited word" },
|
||||
{ "vi-next-word", VI_NEXT_WORD,
|
||||
"Vi move to the next word" },
|
||||
{ "vi-change-case", VI_CHANGE_CASE,
|
||||
"Vi change case of character under the cursor and advance one character" },
|
||||
{ "vi-change-meta", VI_CHANGE_META,
|
||||
"Vi change prefix command" },
|
||||
{ "vi-insert-at-bol", VI_INSERT_AT_BOL,
|
||||
"Vi enter insert mode at the beginning of line" },
|
||||
{ "vi-replace-char", VI_REPLACE_CHAR,
|
||||
"Vi replace character under the cursor with the next character typed" },
|
||||
{ "vi-replace-mode", VI_REPLACE_MODE,
|
||||
"Vi enter replace mode" },
|
||||
{ "vi-substitute-char", VI_SUBSTITUTE_CHAR,
|
||||
"Vi replace character under the cursor and enter insert mode" },
|
||||
{ "vi-substitute-line", VI_SUBSTITUTE_LINE,
|
||||
"Vi substitute entire line" },
|
||||
{ "vi-change-to-eol", VI_CHANGE_TO_EOL,
|
||||
"Vi change to end of line" },
|
||||
{ "vi-insert", VI_INSERT,
|
||||
"Vi enter insert mode" },
|
||||
{ "vi-add", VI_ADD,
|
||||
"Vi enter insert mode after the cursor" },
|
||||
{ "vi-add-at-eol", VI_ADD_AT_EOL,
|
||||
"Vi enter insert mode at end of line" },
|
||||
{ "vi-delete-meta", VI_DELETE_META,
|
||||
"Vi delete prefix command" },
|
||||
{ "vi-end-big-word", VI_END_BIG_WORD,
|
||||
"Vi move to the end of the current space delimited word" },
|
||||
{ "vi-end-word", VI_END_WORD,
|
||||
"Vi move to the end of the current word" },
|
||||
{ "vi-undo", VI_UNDO,
|
||||
"Vi undo last change" },
|
||||
{ "vi-command-mode", VI_COMMAND_MODE,
|
||||
"Vi enter command mode (use alternative key bindings)" },
|
||||
{ "vi-zero", VI_ZERO,
|
||||
"Vi move to the beginning of line" },
|
||||
{ "vi-delete-prev-char", VI_DELETE_PREV_CHAR,
|
||||
"Vi move to previous character (backspace)" },
|
||||
{ "vi-list-or-eof", VI_LIST_OR_EOF,
|
||||
"Vi list choices for completion or indicate end of file if empty line" },
|
||||
{ "vi-kill-line-prev", VI_KILL_LINE_PREV,
|
||||
"Vi cut from beginning of line to cursor" },
|
||||
{ "vi-search-prev", VI_SEARCH_PREV,
|
||||
"Vi search history previous" },
|
||||
{ "vi-search-next", VI_SEARCH_NEXT,
|
||||
"Vi search history next" },
|
||||
{ "vi-repeat-search-next", VI_REPEAT_SEARCH_NEXT,
|
||||
"Vi repeat current search in the same search direction" },
|
||||
{ "vi-repeat-search-prev", VI_REPEAT_SEARCH_PREV,
|
||||
"Vi repeat current search in the opposite search direction" },
|
||||
{ "vi-next-char", VI_NEXT_CHAR,
|
||||
"Vi move to the character specified next" },
|
||||
{ "vi-prev-char", VI_PREV_CHAR,
|
||||
"Vi move to the character specified previous" },
|
||||
{ "vi-to-next-char", VI_TO_NEXT_CHAR,
|
||||
"Vi move up to the character specified next" },
|
||||
{ "vi-to-prev-char", VI_TO_PREV_CHAR,
|
||||
"Vi move up to the character specified previous" },
|
||||
{ "vi-repeat-next-char", VI_REPEAT_NEXT_CHAR,
|
||||
"Vi repeat current character search in the same search direction" },
|
||||
{ "vi-repeat-prev-char", VI_REPEAT_PREV_CHAR,
|
||||
"Vi repeat current character search in the opposite search direction" },
|
||||
{ "vi-match", VI_MATCH,
|
||||
"Vi go to matching () {} or []" },
|
||||
{ "vi-undo-line", VI_UNDO_LINE,
|
||||
"Vi undo all changes to line" },
|
||||
{ "vi-to-column", VI_TO_COLUMN,
|
||||
"Vi go to specified column" },
|
||||
{ "vi-yank-end", VI_YANK_END,
|
||||
"Vi yank to end of line" },
|
||||
{ "vi-yank", VI_YANK,
|
||||
"Vi yank" },
|
||||
{ "vi-comment-out", VI_COMMENT_OUT,
|
||||
"Vi comment out current command" },
|
||||
{ "vi-alias", VI_ALIAS,
|
||||
"Vi include shell alias" },
|
||||
{ "vi-to-history-line", VI_TO_HISTORY_LINE,
|
||||
"Vi go to specified history file line." },
|
||||
{ "vi-histedit", VI_HISTEDIT,
|
||||
"Vi edit history line with vi" },
|
||||
{ "vi-history-word", VI_HISTORY_WORD,
|
||||
"Vi append word from previous input line" },
|
||||
{ "vi-redo", VI_REDO,
|
||||
"Vi redo last non-motion command" },
|
||||
{ "em-delete-or-list", EM_DELETE_OR_LIST,
|
||||
"Delete character under cursor or list completions if at end of line" },
|
||||
{ "em-delete-next-word", EM_DELETE_NEXT_WORD,
|
||||
"Cut from cursor to end of current word" },
|
||||
{ "em-yank", EM_YANK,
|
||||
"Paste cut buffer at cursor position" },
|
||||
{ "em-kill-line", EM_KILL_LINE,
|
||||
"Cut the entire line and save in cut buffer" },
|
||||
{ "em-kill-region", EM_KILL_REGION,
|
||||
"Cut area between mark and cursor and save in cut buffer" },
|
||||
{ "em-copy-region", EM_COPY_REGION,
|
||||
"Copy area between mark and cursor to cut buffer" },
|
||||
{ "em-gosmacs-transpose", EM_GOSMACS_TRANSPOSE,
|
||||
"Exchange the two characters before the cursor" },
|
||||
{ "em-next-word", EM_NEXT_WORD,
|
||||
"Move next to end of current word" },
|
||||
{ "em-upper-case", EM_UPPER_CASE,
|
||||
"Uppercase the characters from cursor to end of current word" },
|
||||
{ "em-capitol-case", EM_CAPITOL_CASE,
|
||||
"Capitalize the characters from cursor to end of current word" },
|
||||
{ "em-lower-case", EM_LOWER_CASE,
|
||||
"Lowercase the characters from cursor to end of current word" },
|
||||
{ "em-set-mark", EM_SET_MARK,
|
||||
"Set the mark at cursor" },
|
||||
{ "em-exchange-mark", EM_EXCHANGE_MARK,
|
||||
"Exchange the cursor and mark" },
|
||||
{ "em-universal-argument", EM_UNIVERSAL_ARGUMENT,
|
||||
"Universal argument (argument times 4)" },
|
||||
{ "em-meta-next", EM_META_NEXT,
|
||||
"Add 8th bit to next character typed" },
|
||||
{ "em-toggle-overwrite", EM_TOGGLE_OVERWRITE,
|
||||
"Switch from insert to overwrite mode or vice versa" },
|
||||
{ "em-copy-prev-word", EM_COPY_PREV_WORD,
|
||||
"Copy current word to cursor" },
|
||||
{ "em-inc-search-next", EM_INC_SEARCH_NEXT,
|
||||
"Emacs incremental next search" },
|
||||
{ "em-inc-search-prev", EM_INC_SEARCH_PREV,
|
||||
"Emacs incremental reverse search" },
|
||||
{ "em-delete-prev-char", EM_DELETE_PREV_CHAR,
|
||||
"Delete the character to the left of the cursor" },
|
||||
{ "ed-end-of-file", ED_END_OF_FILE,
|
||||
"Indicate end of file" },
|
||||
{ "ed-insert", ED_INSERT,
|
||||
"Add character to the line" },
|
||||
{ "ed-delete-prev-word", ED_DELETE_PREV_WORD,
|
||||
"Delete from beginning of current word to cursor" },
|
||||
{ "ed-delete-next-char", ED_DELETE_NEXT_CHAR,
|
||||
"Delete character under cursor" },
|
||||
{ "ed-kill-line", ED_KILL_LINE,
|
||||
"Cut to the end of line" },
|
||||
{ "ed-move-to-end", ED_MOVE_TO_END,
|
||||
"Move cursor to the end of line" },
|
||||
{ "ed-move-to-beg", ED_MOVE_TO_BEG,
|
||||
"Move cursor to the beginning of line" },
|
||||
{ "ed-transpose-chars", ED_TRANSPOSE_CHARS,
|
||||
"Exchange the character to the left of the cursor with the one under it" },
|
||||
{ "ed-next-char", ED_NEXT_CHAR,
|
||||
"Move to the right one character" },
|
||||
{ "ed-prev-word", ED_PREV_WORD,
|
||||
"Move to the beginning of the current word" },
|
||||
{ "ed-prev-char", ED_PREV_CHAR,
|
||||
"Move to the left one character" },
|
||||
{ "ed-quoted-insert", ED_QUOTED_INSERT,
|
||||
"Add the next character typed verbatim" },
|
||||
{ "ed-digit", ED_DIGIT,
|
||||
"Adds to argument or enters a digit" },
|
||||
{ "ed-argument-digit", ED_ARGUMENT_DIGIT,
|
||||
"Digit that starts argument" },
|
||||
{ "ed-unassigned", ED_UNASSIGNED,
|
||||
"Indicates unbound character" },
|
||||
{ "ed-tty-sigint", ED_TTY_SIGINT,
|
||||
"Tty interrupt character" },
|
||||
{ "ed-tty-dsusp", ED_TTY_DSUSP,
|
||||
"Tty delayed suspend character" },
|
||||
{ "ed-tty-flush-output", ED_TTY_FLUSH_OUTPUT,
|
||||
"Tty flush output characters" },
|
||||
{ "ed-tty-sigquit", ED_TTY_SIGQUIT,
|
||||
"Tty quit character" },
|
||||
{ "ed-tty-sigtstp", ED_TTY_SIGTSTP,
|
||||
"Tty suspend character" },
|
||||
{ "ed-tty-stop-output", ED_TTY_STOP_OUTPUT,
|
||||
"Tty disallow output characters" },
|
||||
{ "ed-tty-start-output", ED_TTY_START_OUTPUT,
|
||||
"Tty allow output characters" },
|
||||
{ "ed-newline", ED_NEWLINE,
|
||||
"Execute command" },
|
||||
{ "ed-delete-prev-char", ED_DELETE_PREV_CHAR,
|
||||
"Delete the character to the left of the cursor" },
|
||||
{ "ed-clear-screen", ED_CLEAR_SCREEN,
|
||||
"Clear screen leaving current line at the top" },
|
||||
{ "ed-redisplay", ED_REDISPLAY,
|
||||
"Redisplay everything" },
|
||||
{ "ed-start-over", ED_START_OVER,
|
||||
"Erase current line and start from scratch" },
|
||||
{ "ed-sequence-lead-in", ED_SEQUENCE_LEAD_IN,
|
||||
"First character in a bound sequence" },
|
||||
{ "ed-prev-history", ED_PREV_HISTORY,
|
||||
"Move to the previous history line" },
|
||||
{ "ed-next-history", ED_NEXT_HISTORY,
|
||||
"Move to the next history line" },
|
||||
{ "ed-search-prev-history", ED_SEARCH_PREV_HISTORY,
|
||||
"Search previous in history for a line matching the current" },
|
||||
{ "ed-search-next-history", ED_SEARCH_NEXT_HISTORY,
|
||||
"Search next in history for a line matching the current" },
|
||||
{ "ed-prev-line", ED_PREV_LINE,
|
||||
"Move up one line" },
|
||||
{ "ed-next-line", ED_NEXT_LINE,
|
||||
"Move down one line" },
|
||||
{ "ed-command", ED_COMMAND,
|
||||
"Editline extended command" },
|
||||
};
|
||||
|
||||
protected const el_bindings_t* help__get(){ return el_func_help; }
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Automatically generated file, do not edit */
|
||||
#ifndef _h_help_c
|
||||
#define _h_help_c
|
||||
protected const el_bindings_t *help__get(void);
|
||||
#endif /* _h_help_c */
|
||||
@@ -0,0 +1,202 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: hist.c,v 1.15 2003/11/01 23:36:39 christos Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* hist.c: History access functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include <stdlib.h>
|
||||
#include "el.h"
|
||||
|
||||
/* hist_init():
|
||||
* Initialization function.
|
||||
*/
|
||||
protected int
|
||||
hist_init(EditLine *el)
|
||||
{
|
||||
|
||||
el->el_history.fun = NULL;
|
||||
el->el_history.ref = NULL;
|
||||
el->el_history.buf = (char *) el_malloc(EL_BUFSIZ);
|
||||
el->el_history.sz = EL_BUFSIZ;
|
||||
if (el->el_history.buf == NULL)
|
||||
return (-1);
|
||||
el->el_history.last = el->el_history.buf;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* hist_end():
|
||||
* clean up history;
|
||||
*/
|
||||
protected void
|
||||
hist_end(EditLine *el)
|
||||
{
|
||||
|
||||
el_free((ptr_t) el->el_history.buf);
|
||||
el->el_history.buf = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* hist_set():
|
||||
* Set new history interface
|
||||
*/
|
||||
protected int
|
||||
hist_set(EditLine *el, hist_fun_t fun, ptr_t ptr)
|
||||
{
|
||||
|
||||
el->el_history.ref = ptr;
|
||||
el->el_history.fun = fun;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* hist_get():
|
||||
* Get a history line and update it in the buffer.
|
||||
* eventno tells us the event to get.
|
||||
*/
|
||||
protected el_action_t
|
||||
hist_get(EditLine *el)
|
||||
{
|
||||
const char *hp;
|
||||
int h;
|
||||
|
||||
if (el->el_history.eventno == 0) { /* if really the current line */
|
||||
(void) strncpy(el->el_line.buffer, el->el_history.buf,
|
||||
el->el_history.sz);
|
||||
el->el_line.lastchar = el->el_line.buffer +
|
||||
(el->el_history.last - el->el_history.buf);
|
||||
|
||||
#ifdef KSHVI
|
||||
if (el->el_map.type == MAP_VI)
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
else
|
||||
#endif /* KSHVI */
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
if (el->el_history.ref == NULL)
|
||||
return (CC_ERROR);
|
||||
|
||||
hp = HIST_FIRST(el);
|
||||
|
||||
if (hp == NULL)
|
||||
return (CC_ERROR);
|
||||
|
||||
for (h = 1; h < el->el_history.eventno; h++)
|
||||
if ((hp = HIST_NEXT(el)) == NULL) {
|
||||
el->el_history.eventno = h;
|
||||
return (CC_ERROR);
|
||||
}
|
||||
(void) strlcpy(el->el_line.buffer, hp,
|
||||
(size_t)(el->el_line.limit - el->el_line.buffer));
|
||||
el->el_line.lastchar = el->el_line.buffer + strlen(el->el_line.buffer);
|
||||
|
||||
if (el->el_line.lastchar > el->el_line.buffer
|
||||
&& el->el_line.lastchar[-1] == '\n')
|
||||
el->el_line.lastchar--;
|
||||
if (el->el_line.lastchar > el->el_line.buffer
|
||||
&& el->el_line.lastchar[-1] == ' ')
|
||||
el->el_line.lastchar--;
|
||||
#ifdef KSHVI
|
||||
if (el->el_map.type == MAP_VI)
|
||||
el->el_line.cursor = el->el_line.buffer;
|
||||
else
|
||||
#endif /* KSHVI */
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* hist_command()
|
||||
* process a history command
|
||||
*/
|
||||
protected int
|
||||
hist_command(EditLine *el, int argc, const char **argv)
|
||||
{
|
||||
const char *str;
|
||||
int num;
|
||||
HistEvent ev;
|
||||
|
||||
if (el->el_history.ref == NULL)
|
||||
return (-1);
|
||||
|
||||
if (argc == 1 || strcmp(argv[1], "list") == 0) {
|
||||
/* List history entries */
|
||||
|
||||
for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el))
|
||||
(void) fprintf(el->el_outfile, "%d %s",
|
||||
el->el_history.ev.num, str);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (argc != 3)
|
||||
return (-1);
|
||||
|
||||
num = (int)strtol(argv[2], NULL, 0);
|
||||
|
||||
if (strcmp(argv[1], "size") == 0)
|
||||
return history(el->el_history.ref, &ev, H_SETSIZE, num);
|
||||
|
||||
if (strcmp(argv[1], "unique") == 0)
|
||||
return history(el->el_history.ref, &ev, H_SETUNIQUE, num);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* hist_enlargebuf()
|
||||
* Enlarge history buffer to specified value. Called from el_enlargebufs().
|
||||
* Return 0 for failure, 1 for success.
|
||||
*/
|
||||
protected int
|
||||
/*ARGSUSED*/
|
||||
hist_enlargebuf(EditLine *el, size_t oldsz, size_t newsz)
|
||||
{
|
||||
char *newbuf;
|
||||
|
||||
newbuf = realloc(el->el_history.buf, newsz);
|
||||
if (!newbuf)
|
||||
return 0;
|
||||
|
||||
(void) memset(&newbuf[oldsz], '\0', newsz - oldsz);
|
||||
|
||||
el->el_history.last = newbuf +
|
||||
(el->el_history.last - el->el_history.buf);
|
||||
el->el_history.buf = newbuf;
|
||||
el->el_history.sz = newsz;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)hist.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: hist.h,v 1.10 2003/08/07 16:44:31 agc Exp $
|
||||
* $FreeBSD: src/lib/libedit/hist.h,v 1.4 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.hist.c: History functions
|
||||
*/
|
||||
#ifndef _h_el_hist
|
||||
#define _h_el_hist
|
||||
|
||||
#include "histedit.h"
|
||||
#include "sys.h"
|
||||
|
||||
typedef int (*hist_fun_t)(ptr_t, HistEvent *, int, ...);
|
||||
|
||||
typedef struct el_history_t {
|
||||
char *buf; /* The history buffer */
|
||||
size_t sz; /* Size of history buffer */
|
||||
char *last; /* The last character */
|
||||
int eventno; /* Event we are looking for */
|
||||
ptr_t ref; /* Argument for history fcns */
|
||||
hist_fun_t fun; /* Event access */
|
||||
HistEvent ev; /* Event cookie */
|
||||
} el_history_t;
|
||||
|
||||
#define HIST_FUN(el, fn, arg) \
|
||||
((((*(el)->el_history.fun) ((el)->el_history.ref, &(el)->el_history.ev, \
|
||||
fn, arg)) == -1) ? NULL : (el)->el_history.ev.str)
|
||||
|
||||
#define HIST_NEXT(el) HIST_FUN(el, H_NEXT, NULL)
|
||||
#define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL)
|
||||
#define HIST_LAST(el) HIST_FUN(el, H_LAST, NULL)
|
||||
#define HIST_PREV(el) HIST_FUN(el, H_PREV, NULL)
|
||||
#define HIST_SET(el, num) HIST_FUN(el, H_SET, num)
|
||||
#define HIST_LOAD(el, fname) HIST_FUN(el, H_LOAD fname)
|
||||
#define HIST_SAVE(el, fname) HIST_FUN(el, H_SAVE fname)
|
||||
|
||||
protected int hist_init(EditLine *);
|
||||
protected void hist_end(EditLine *);
|
||||
protected el_action_t hist_get(EditLine *);
|
||||
protected int hist_set(EditLine *, hist_fun_t, ptr_t);
|
||||
protected int hist_command(EditLine *, int, const char **);
|
||||
protected int hist_enlargebuf(EditLine *, size_t, size_t);
|
||||
|
||||
#endif /* _h_el_hist */
|
||||
@@ -0,0 +1,979 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: history.c,v 1.31 2005/08/01 14:34:06 christos Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* hist.c: History access functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <vis.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static const char hist_cookie[] = "_HiStOrY_V2_\n";
|
||||
|
||||
#include "histedit.h"
|
||||
|
||||
typedef int (*history_gfun_t)(ptr_t, HistEvent *);
|
||||
typedef int (*history_efun_t)(ptr_t, HistEvent *, const char *);
|
||||
typedef void (*history_vfun_t)(ptr_t, HistEvent *);
|
||||
typedef int (*history_sfun_t)(ptr_t, HistEvent *, const int);
|
||||
|
||||
struct 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 */
|
||||
history_gfun_t h_next; /* Get the next element */
|
||||
history_gfun_t h_last; /* Get the last element */
|
||||
history_gfun_t h_prev; /* Get the previous element */
|
||||
history_gfun_t h_curr; /* Get the current element */
|
||||
history_sfun_t h_set; /* Set the current element */
|
||||
history_sfun_t h_del; /* Set the given element */
|
||||
history_vfun_t h_clear; /* Clear the history list */
|
||||
history_efun_t h_enter; /* Add an element */
|
||||
history_efun_t h_add; /* Append to an element */
|
||||
};
|
||||
|
||||
#define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
|
||||
#define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
|
||||
#define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
|
||||
#define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
|
||||
#define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
|
||||
#define HSET(h, ev, n) (*(h)->h_set)((h)->h_ref, ev, n)
|
||||
#define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
|
||||
#define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
|
||||
#define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
|
||||
#define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
|
||||
|
||||
#define h_strdup(a) strdup(a)
|
||||
#define h_malloc(a) malloc(a)
|
||||
#define h_realloc(a, b) realloc((a), (b))
|
||||
#define h_free(a) free(a)
|
||||
|
||||
typedef struct {
|
||||
int num;
|
||||
char *str;
|
||||
} HistEventPrivate;
|
||||
|
||||
|
||||
|
||||
private int history_setsize(History *, HistEvent *, int);
|
||||
private int history_getsize(History *, HistEvent *);
|
||||
private int history_setunique(History *, HistEvent *, int);
|
||||
private int history_getunique(History *, HistEvent *);
|
||||
private int history_set_fun(History *, History *);
|
||||
private int history_load(History *, const char *);
|
||||
private int history_save(History *, const char *);
|
||||
private int history_prev_event(History *, HistEvent *, int);
|
||||
private int history_next_event(History *, HistEvent *, int);
|
||||
private int history_next_string(History *, HistEvent *, const char *);
|
||||
private int history_prev_string(History *, HistEvent *, const char *);
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
/*
|
||||
* Builtin- history implementation
|
||||
*/
|
||||
typedef struct hentry_t {
|
||||
HistEvent ev; /* What we return */
|
||||
struct hentry_t *next; /* Next entry */
|
||||
struct hentry_t *prev; /* Previous entry */
|
||||
} hentry_t;
|
||||
|
||||
typedef struct history_t {
|
||||
hentry_t list; /* Fake list header element */
|
||||
hentry_t *cursor; /* Current element in the list */
|
||||
int max; /* Maximum number of events */
|
||||
int cur; /* Current number of events */
|
||||
int eventid; /* For generation of unique event id */
|
||||
int flags; /* History flags */
|
||||
#define H_UNIQUE 1 /* Store only unique elements */
|
||||
} history_t;
|
||||
|
||||
private int history_def_next(ptr_t, HistEvent *);
|
||||
private int history_def_first(ptr_t, HistEvent *);
|
||||
private int history_def_prev(ptr_t, HistEvent *);
|
||||
private int history_def_last(ptr_t, HistEvent *);
|
||||
private int history_def_curr(ptr_t, HistEvent *);
|
||||
private int history_def_set(ptr_t, HistEvent *, const int);
|
||||
private void history_def_clear(ptr_t, HistEvent *);
|
||||
private int history_def_enter(ptr_t, HistEvent *, const char *);
|
||||
private int history_def_add(ptr_t, HistEvent *, const char *);
|
||||
private int history_def_del(ptr_t, HistEvent *, const int);
|
||||
|
||||
private int history_def_init(ptr_t *, HistEvent *, int);
|
||||
private int history_def_insert(history_t *, HistEvent *, const char *);
|
||||
private void history_def_delete(history_t *, HistEvent *, hentry_t *);
|
||||
|
||||
#define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
|
||||
#define history_def_getsize(p) (((history_t *)p)->cur)
|
||||
#define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
|
||||
#define history_def_setunique(p, uni) \
|
||||
if (uni) \
|
||||
(((history_t *)p)->flags) |= H_UNIQUE; \
|
||||
else \
|
||||
(((history_t *)p)->flags) &= ~H_UNIQUE
|
||||
|
||||
#define he_strerror(code) he_errlist[code]
|
||||
#define he_seterrev(evp, code) {\
|
||||
evp->num = code;\
|
||||
evp->str = he_strerror(code);\
|
||||
}
|
||||
|
||||
/* error messages */
|
||||
static const char *const he_errlist[] = {
|
||||
"OK",
|
||||
"unknown error",
|
||||
"malloc() failed",
|
||||
"first event not found",
|
||||
"last event not found",
|
||||
"empty list",
|
||||
"no next event",
|
||||
"no previous event",
|
||||
"current event is invalid",
|
||||
"event not found",
|
||||
"can't read history from file",
|
||||
"can't write history",
|
||||
"required parameter(s) not supplied",
|
||||
"history size negative",
|
||||
"function not allowed with other history-functions-set the default",
|
||||
"bad parameters"
|
||||
};
|
||||
/* error codes */
|
||||
#define _HE_OK 0
|
||||
#define _HE_UNKNOWN 1
|
||||
#define _HE_MALLOC_FAILED 2
|
||||
#define _HE_FIRST_NOTFOUND 3
|
||||
#define _HE_LAST_NOTFOUND 4
|
||||
#define _HE_EMPTY_LIST 5
|
||||
#define _HE_END_REACHED 6
|
||||
#define _HE_START_REACHED 7
|
||||
#define _HE_CURR_INVALID 8
|
||||
#define _HE_NOT_FOUND 9
|
||||
#define _HE_HIST_READ 10
|
||||
#define _HE_HIST_WRITE 11
|
||||
#define _HE_PARAM_MISSING 12
|
||||
#define _HE_SIZE_NEGATIVE 13
|
||||
#define _HE_NOT_ALLOWED 14
|
||||
#define _HE_BAD_PARAM 15
|
||||
|
||||
/* history_def_first():
|
||||
* Default function to return the first event in the history.
|
||||
*/
|
||||
private int
|
||||
history_def_first(ptr_t p, HistEvent *ev)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
h->cursor = h->list.next;
|
||||
if (h->cursor != &h->list)
|
||||
*ev = h->cursor->ev;
|
||||
else {
|
||||
he_seterrev(ev, _HE_FIRST_NOTFOUND);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_last():
|
||||
* Default function to return the last event in the history.
|
||||
*/
|
||||
private int
|
||||
history_def_last(ptr_t p, HistEvent *ev)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
h->cursor = h->list.prev;
|
||||
if (h->cursor != &h->list)
|
||||
*ev = h->cursor->ev;
|
||||
else {
|
||||
he_seterrev(ev, _HE_LAST_NOTFOUND);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_next():
|
||||
* Default function to return the next event in the history.
|
||||
*/
|
||||
private int
|
||||
history_def_next(ptr_t p, HistEvent *ev)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
if (h->cursor == &h->list) {
|
||||
he_seterrev(ev, _HE_EMPTY_LIST);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (h->cursor->next == &h->list) {
|
||||
he_seterrev(ev, _HE_END_REACHED);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
h->cursor = h->cursor->next;
|
||||
*ev = h->cursor->ev;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_prev():
|
||||
* Default function to return the previous event in the history.
|
||||
*/
|
||||
private int
|
||||
history_def_prev(ptr_t p, HistEvent *ev)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
if (h->cursor == &h->list) {
|
||||
he_seterrev(ev,
|
||||
(h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (h->cursor->prev == &h->list) {
|
||||
he_seterrev(ev, _HE_START_REACHED);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
h->cursor = h->cursor->prev;
|
||||
*ev = h->cursor->ev;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_curr():
|
||||
* Default function to return the current event in the history.
|
||||
*/
|
||||
private int
|
||||
history_def_curr(ptr_t p, HistEvent *ev)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
if (h->cursor != &h->list)
|
||||
*ev = h->cursor->ev;
|
||||
else {
|
||||
he_seterrev(ev,
|
||||
(h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_set():
|
||||
* Default function to set the current event in the history to the
|
||||
* given one.
|
||||
*/
|
||||
private int
|
||||
history_def_set(ptr_t p, HistEvent *ev, const int n)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
if (h->cur == 0) {
|
||||
he_seterrev(ev, _HE_EMPTY_LIST);
|
||||
return (-1);
|
||||
}
|
||||
if (h->cursor == &h->list || h->cursor->ev.num != n) {
|
||||
for (h->cursor = h->list.next; h->cursor != &h->list;
|
||||
h->cursor = h->cursor->next)
|
||||
if (h->cursor->ev.num == n)
|
||||
break;
|
||||
}
|
||||
if (h->cursor == &h->list) {
|
||||
he_seterrev(ev, _HE_NOT_FOUND);
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_add():
|
||||
* Append string to element
|
||||
*/
|
||||
private int
|
||||
history_def_add(ptr_t p, HistEvent *ev, const char *str)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
size_t len;
|
||||
char *s;
|
||||
HistEventPrivate *evp = (void *)&h->cursor->ev;
|
||||
|
||||
if (h->cursor == &h->list)
|
||||
return (history_def_enter(p, ev, str));
|
||||
len = strlen(evp->str) + strlen(str) + 1;
|
||||
s = (char *) h_malloc(len);
|
||||
if (s == NULL) {
|
||||
he_seterrev(ev, _HE_MALLOC_FAILED);
|
||||
return (-1);
|
||||
}
|
||||
(void) strlcpy(s, h->cursor->ev.str, len);
|
||||
(void) strlcat(s, str, len);
|
||||
h_free((ptr_t)evp->str);
|
||||
evp->str = s;
|
||||
*ev = h->cursor->ev;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_del():
|
||||
* Delete element hp of the h list
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
private int
|
||||
history_def_del(ptr_t p, HistEvent *ev __unused,
|
||||
const int num)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
if (history_def_set(h, ev, num) != 0)
|
||||
return (-1);
|
||||
ev->str = strdup(h->cursor->ev.str);
|
||||
ev->num = h->cursor->ev.num;
|
||||
history_def_delete(h, ev, h->cursor);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_delete():
|
||||
* Delete element hp of the h list
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
private void
|
||||
history_def_delete(history_t *h,
|
||||
HistEvent *ev __unused, hentry_t *hp)
|
||||
{
|
||||
HistEventPrivate *evp = (void *)&hp->ev;
|
||||
if (hp == &h->list)
|
||||
abort();
|
||||
if (h->cursor == hp)
|
||||
h->cursor = hp->prev;
|
||||
hp->prev->next = hp->next;
|
||||
hp->next->prev = hp->prev;
|
||||
h_free((ptr_t) evp->str);
|
||||
h_free(hp);
|
||||
h->cur--;
|
||||
}
|
||||
|
||||
|
||||
/* history_def_insert():
|
||||
* Insert element with string str in the h list
|
||||
*/
|
||||
private int
|
||||
history_def_insert(history_t *h, HistEvent *ev, const char *str)
|
||||
{
|
||||
|
||||
h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
|
||||
if (h->cursor == NULL)
|
||||
goto oomem;
|
||||
if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
|
||||
h_free((ptr_t)h->cursor);
|
||||
goto oomem;
|
||||
}
|
||||
h->cursor->ev.num = ++h->eventid;
|
||||
h->cursor->next = h->list.next;
|
||||
h->cursor->prev = &h->list;
|
||||
h->list.next->prev = h->cursor;
|
||||
h->list.next = h->cursor;
|
||||
h->cur++;
|
||||
|
||||
*ev = h->cursor->ev;
|
||||
return (0);
|
||||
oomem:
|
||||
he_seterrev(ev, _HE_MALLOC_FAILED);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_enter():
|
||||
* Default function to enter an item in the history
|
||||
*/
|
||||
private int
|
||||
history_def_enter(ptr_t p, HistEvent *ev, const char *str)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
|
||||
strcmp(h->list.next->ev.str, str) == 0)
|
||||
return (0);
|
||||
|
||||
if (history_def_insert(h, ev, str) == -1)
|
||||
return (-1); /* error, keep error message */
|
||||
|
||||
/*
|
||||
* Always keep at least one entry.
|
||||
* This way we don't have to check for the empty list.
|
||||
*/
|
||||
while (h->cur > h->max && h->cur > 0)
|
||||
history_def_delete(h, ev, h->list.prev);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* history_def_init():
|
||||
* Default history initialization function
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
private int
|
||||
history_def_init(ptr_t *p, HistEvent *ev __unused, int n)
|
||||
{
|
||||
history_t *h = (history_t *) h_malloc(sizeof(history_t));
|
||||
if (h == NULL)
|
||||
return -1;
|
||||
|
||||
if (n <= 0)
|
||||
n = 0;
|
||||
h->eventid = 0;
|
||||
h->cur = 0;
|
||||
h->max = n;
|
||||
h->list.next = h->list.prev = &h->list;
|
||||
h->list.ev.str = NULL;
|
||||
h->list.ev.num = 0;
|
||||
h->cursor = &h->list;
|
||||
h->flags = 0;
|
||||
*p = (ptr_t) h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* history_def_clear():
|
||||
* Default history cleanup function
|
||||
*/
|
||||
private void
|
||||
history_def_clear(ptr_t p, HistEvent *ev)
|
||||
{
|
||||
history_t *h = (history_t *) p;
|
||||
|
||||
while (h->list.prev != &h->list)
|
||||
history_def_delete(h, ev, h->list.prev);
|
||||
h->eventid = 0;
|
||||
h->cur = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/* history_init():
|
||||
* Initialization function.
|
||||
*/
|
||||
public History *
|
||||
history_init(void)
|
||||
{
|
||||
HistEvent ev;
|
||||
History *h = (History *) h_malloc(sizeof(History));
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
if (history_def_init(&h->h_ref, &ev, 0) == -1) {
|
||||
h_free((ptr_t)h);
|
||||
return NULL;
|
||||
}
|
||||
h->h_ent = -1;
|
||||
h->h_next = history_def_next;
|
||||
h->h_first = history_def_first;
|
||||
h->h_last = history_def_last;
|
||||
h->h_prev = history_def_prev;
|
||||
h->h_curr = history_def_curr;
|
||||
h->h_set = history_def_set;
|
||||
h->h_clear = history_def_clear;
|
||||
h->h_enter = history_def_enter;
|
||||
h->h_add = history_def_add;
|
||||
h->h_del = history_def_del;
|
||||
|
||||
return (h);
|
||||
}
|
||||
|
||||
|
||||
/* history_end():
|
||||
* clean up history;
|
||||
*/
|
||||
public void
|
||||
history_end(History *h)
|
||||
{
|
||||
HistEvent ev;
|
||||
|
||||
if (h->h_next == history_def_next)
|
||||
history_def_clear(h->h_ref, &ev);
|
||||
h_free(h);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* history_setsize():
|
||||
* Set history number of events
|
||||
*/
|
||||
private int
|
||||
history_setsize(History *h, HistEvent *ev, int num)
|
||||
{
|
||||
|
||||
if (h->h_next != history_def_next) {
|
||||
he_seterrev(ev, _HE_NOT_ALLOWED);
|
||||
return (-1);
|
||||
}
|
||||
if (num < 0) {
|
||||
he_seterrev(ev, _HE_BAD_PARAM);
|
||||
return (-1);
|
||||
}
|
||||
history_def_setsize(h->h_ref, num);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_getsize():
|
||||
* Get number of events currently in history
|
||||
*/
|
||||
private int
|
||||
history_getsize(History *h, HistEvent *ev)
|
||||
{
|
||||
if (h->h_next != history_def_next) {
|
||||
he_seterrev(ev, _HE_NOT_ALLOWED);
|
||||
return (-1);
|
||||
}
|
||||
ev->num = history_def_getsize(h->h_ref);
|
||||
if (ev->num < -1) {
|
||||
he_seterrev(ev, _HE_SIZE_NEGATIVE);
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_setunique():
|
||||
* Set if adjacent equal events should not be entered in history.
|
||||
*/
|
||||
private int
|
||||
history_setunique(History *h, HistEvent *ev, int uni)
|
||||
{
|
||||
|
||||
if (h->h_next != history_def_next) {
|
||||
he_seterrev(ev, _HE_NOT_ALLOWED);
|
||||
return (-1);
|
||||
}
|
||||
history_def_setunique(h->h_ref, uni);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_getunique():
|
||||
* Get if adjacent equal events should not be entered in history.
|
||||
*/
|
||||
private int
|
||||
history_getunique(History *h, HistEvent *ev)
|
||||
{
|
||||
if (h->h_next != history_def_next) {
|
||||
he_seterrev(ev, _HE_NOT_ALLOWED);
|
||||
return (-1);
|
||||
}
|
||||
ev->num = history_def_getunique(h->h_ref);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_set_fun():
|
||||
* Set history functions
|
||||
*/
|
||||
private int
|
||||
history_set_fun(History *h, History *nh)
|
||||
{
|
||||
HistEvent ev;
|
||||
|
||||
if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
|
||||
nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
|
||||
nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
|
||||
nh->h_del == NULL || nh->h_ref == NULL) {
|
||||
if (h->h_next != history_def_next) {
|
||||
history_def_init(&h->h_ref, &ev, 0);
|
||||
h->h_first = history_def_first;
|
||||
h->h_next = history_def_next;
|
||||
h->h_last = history_def_last;
|
||||
h->h_prev = history_def_prev;
|
||||
h->h_curr = history_def_curr;
|
||||
h->h_set = history_def_set;
|
||||
h->h_clear = history_def_clear;
|
||||
h->h_enter = history_def_enter;
|
||||
h->h_add = history_def_add;
|
||||
h->h_del = history_def_del;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
if (h->h_next == history_def_next)
|
||||
history_def_clear(h->h_ref, &ev);
|
||||
|
||||
h->h_ent = -1;
|
||||
h->h_first = nh->h_first;
|
||||
h->h_next = nh->h_next;
|
||||
h->h_last = nh->h_last;
|
||||
h->h_prev = nh->h_prev;
|
||||
h->h_curr = nh->h_curr;
|
||||
h->h_set = nh->h_set;
|
||||
h->h_clear = nh->h_clear;
|
||||
h->h_enter = nh->h_enter;
|
||||
h->h_add = nh->h_add;
|
||||
h->h_del = nh->h_del;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* history_load():
|
||||
* History load function
|
||||
*/
|
||||
private int
|
||||
history_load(History *h, const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
char *line;
|
||||
size_t sz, max_size;
|
||||
char *ptr;
|
||||
int i = -1;
|
||||
HistEvent ev;
|
||||
|
||||
if ((fp = fopen(fname, "r")) == NULL)
|
||||
return (i);
|
||||
|
||||
if ((line = fgetln(fp, &sz)) == NULL)
|
||||
goto done;
|
||||
|
||||
if (strncmp(line, hist_cookie, sz) != 0)
|
||||
goto done;
|
||||
|
||||
ptr = h_malloc(max_size = 1024);
|
||||
if (ptr == NULL)
|
||||
goto done;
|
||||
for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
|
||||
char c = line[sz];
|
||||
|
||||
if (sz != 0 && line[sz - 1] == '\n')
|
||||
line[--sz] = '\0';
|
||||
else
|
||||
line[sz] = '\0';
|
||||
|
||||
if (max_size < sz) {
|
||||
char *nptr;
|
||||
max_size = (sz + 1024) & ~1023;
|
||||
nptr = h_realloc(ptr, max_size);
|
||||
if (nptr == NULL) {
|
||||
i = -1;
|
||||
goto oomem;
|
||||
}
|
||||
ptr = nptr;
|
||||
}
|
||||
(void) strunvis(ptr, line);
|
||||
line[sz] = c;
|
||||
if (HENTER(h, &ev, ptr) == -1) {
|
||||
h_free((ptr_t)ptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
oomem:
|
||||
h_free((ptr_t)ptr);
|
||||
done:
|
||||
(void) fclose(fp);
|
||||
return (i);
|
||||
}
|
||||
|
||||
|
||||
/* history_save():
|
||||
* History save function
|
||||
*/
|
||||
private int
|
||||
history_save(History *h, const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
HistEvent ev;
|
||||
int i = -1, retval;
|
||||
size_t len, max_size;
|
||||
char *ptr;
|
||||
|
||||
if ((fp = fopen(fname, "w")) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
|
||||
goto done;
|
||||
if (fputs(hist_cookie, fp) == EOF)
|
||||
goto done;
|
||||
ptr = h_malloc(max_size = 1024);
|
||||
if (ptr == NULL)
|
||||
goto done;
|
||||
for (i = 0, retval = HLAST(h, &ev);
|
||||
retval != -1;
|
||||
retval = HPREV(h, &ev), i++) {
|
||||
len = strlen(ev.str) * 4;
|
||||
if (len >= max_size) {
|
||||
char *nptr;
|
||||
max_size = (len + 1024) & ~1023;
|
||||
nptr = h_realloc(ptr, max_size);
|
||||
if (nptr == NULL) {
|
||||
i = -1;
|
||||
goto oomem;
|
||||
}
|
||||
ptr = nptr;
|
||||
}
|
||||
(void) strvis(ptr, ev.str, VIS_WHITE);
|
||||
(void) fprintf(fp, "%s\n", ptr);
|
||||
}
|
||||
oomem:
|
||||
h_free((ptr_t)ptr);
|
||||
done:
|
||||
(void) fclose(fp);
|
||||
return (i);
|
||||
}
|
||||
|
||||
|
||||
/* history_prev_event():
|
||||
* Find the previous event, with number given
|
||||
*/
|
||||
private int
|
||||
history_prev_event(History *h, HistEvent *ev, int num)
|
||||
{
|
||||
int retval;
|
||||
|
||||
for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
|
||||
if (ev->num == num)
|
||||
return (0);
|
||||
|
||||
he_seterrev(ev, _HE_NOT_FOUND);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* history_next_event():
|
||||
* Find the next event, with number given
|
||||
*/
|
||||
private int
|
||||
history_next_event(History *h, HistEvent *ev, int num)
|
||||
{
|
||||
int retval;
|
||||
|
||||
for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
|
||||
if (ev->num == num)
|
||||
return (0);
|
||||
|
||||
he_seterrev(ev, _HE_NOT_FOUND);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* history_prev_string():
|
||||
* Find the previous event beginning with string
|
||||
*/
|
||||
private int
|
||||
history_prev_string(History *h, HistEvent *ev, const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
int retval;
|
||||
|
||||
for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
|
||||
if (strncmp(str, ev->str, len) == 0)
|
||||
return (0);
|
||||
|
||||
he_seterrev(ev, _HE_NOT_FOUND);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* history_next_string():
|
||||
* Find the next event beginning with string
|
||||
*/
|
||||
private int
|
||||
history_next_string(History *h, HistEvent *ev, const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
int retval;
|
||||
|
||||
for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
|
||||
if (strncmp(str, ev->str, len) == 0)
|
||||
return (0);
|
||||
|
||||
he_seterrev(ev, _HE_NOT_FOUND);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* history():
|
||||
* User interface to history functions.
|
||||
*/
|
||||
int
|
||||
history(History *h, HistEvent *ev, int fun, ...)
|
||||
{
|
||||
va_list va;
|
||||
const char *str;
|
||||
int retval;
|
||||
|
||||
va_start(va, fun);
|
||||
|
||||
he_seterrev(ev, _HE_OK);
|
||||
|
||||
switch (fun) {
|
||||
case H_GETSIZE:
|
||||
retval = history_getsize(h, ev);
|
||||
break;
|
||||
|
||||
case H_SETSIZE:
|
||||
retval = history_setsize(h, ev, va_arg(va, int));
|
||||
break;
|
||||
|
||||
case H_GETUNIQUE:
|
||||
retval = history_getunique(h, ev);
|
||||
break;
|
||||
|
||||
case H_SETUNIQUE:
|
||||
retval = history_setunique(h, ev, va_arg(va, int));
|
||||
break;
|
||||
|
||||
case H_ADD:
|
||||
str = va_arg(va, const char *);
|
||||
retval = HADD(h, ev, str);
|
||||
break;
|
||||
|
||||
case H_DEL:
|
||||
retval = HDEL(h, ev, va_arg(va, const int));
|
||||
break;
|
||||
|
||||
case H_ENTER:
|
||||
str = va_arg(va, const char *);
|
||||
if ((retval = HENTER(h, ev, str)) != -1)
|
||||
h->h_ent = ev->num;
|
||||
break;
|
||||
|
||||
case H_APPEND:
|
||||
str = va_arg(va, const char *);
|
||||
if ((retval = HSET(h, ev, h->h_ent)) != -1)
|
||||
retval = HADD(h, ev, str);
|
||||
break;
|
||||
|
||||
case H_FIRST:
|
||||
retval = HFIRST(h, ev);
|
||||
break;
|
||||
|
||||
case H_NEXT:
|
||||
retval = HNEXT(h, ev);
|
||||
break;
|
||||
|
||||
case H_LAST:
|
||||
retval = HLAST(h, ev);
|
||||
break;
|
||||
|
||||
case H_PREV:
|
||||
retval = HPREV(h, ev);
|
||||
break;
|
||||
|
||||
case H_CURR:
|
||||
retval = HCURR(h, ev);
|
||||
break;
|
||||
|
||||
case H_SET:
|
||||
retval = HSET(h, ev, va_arg(va, const int));
|
||||
break;
|
||||
|
||||
case H_CLEAR:
|
||||
HCLEAR(h, ev);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
case H_LOAD:
|
||||
retval = history_load(h, va_arg(va, const char *));
|
||||
if (retval == -1)
|
||||
he_seterrev(ev, _HE_HIST_READ);
|
||||
break;
|
||||
|
||||
case H_SAVE:
|
||||
retval = history_save(h, va_arg(va, const char *));
|
||||
if (retval == -1)
|
||||
he_seterrev(ev, _HE_HIST_WRITE);
|
||||
break;
|
||||
|
||||
case H_PREV_EVENT:
|
||||
retval = history_prev_event(h, ev, va_arg(va, int));
|
||||
break;
|
||||
|
||||
case H_NEXT_EVENT:
|
||||
retval = history_next_event(h, ev, va_arg(va, int));
|
||||
break;
|
||||
|
||||
case H_PREV_STR:
|
||||
retval = history_prev_string(h, ev, va_arg(va, const char *));
|
||||
break;
|
||||
|
||||
case H_NEXT_STR:
|
||||
retval = history_next_string(h, ev, va_arg(va, const char *));
|
||||
break;
|
||||
|
||||
case H_FUNC:
|
||||
{
|
||||
History hf;
|
||||
|
||||
hf.h_ref = va_arg(va, ptr_t);
|
||||
h->h_ent = -1;
|
||||
hf.h_first = va_arg(va, history_gfun_t);
|
||||
hf.h_next = va_arg(va, history_gfun_t);
|
||||
hf.h_last = va_arg(va, history_gfun_t);
|
||||
hf.h_prev = va_arg(va, history_gfun_t);
|
||||
hf.h_curr = va_arg(va, history_gfun_t);
|
||||
hf.h_set = va_arg(va, history_sfun_t);
|
||||
hf.h_clear = va_arg(va, history_vfun_t);
|
||||
hf.h_enter = va_arg(va, history_efun_t);
|
||||
hf.h_add = va_arg(va, history_efun_t);
|
||||
hf.h_del = va_arg(va, history_sfun_t);
|
||||
|
||||
if ((retval = history_set_fun(h, &hf)) == -1)
|
||||
he_seterrev(ev, _HE_PARAM_MISSING);
|
||||
break;
|
||||
}
|
||||
|
||||
case H_END:
|
||||
history_end(h);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -1;
|
||||
he_seterrev(ev, _HE_UNKNOWN);
|
||||
break;
|
||||
}
|
||||
va_end(va);
|
||||
return (retval);
|
||||
}
|
||||
@@ -0,0 +1,687 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: key.c,v 1.17 2005/08/08 14:05:37 christos Exp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/key.c,v 1.11 2005/08/09 13:37:59 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* key.c: This module contains the procedures for maintaining
|
||||
* the extended-key map.
|
||||
*
|
||||
* An extended-key (key) is a sequence of keystrokes introduced
|
||||
* with a sequence introducer and consisting of an arbitrary
|
||||
* number of characters. This module maintains a map (the el->el_key.map)
|
||||
* to convert these extended-key sequences into input strs
|
||||
* (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"
|
||||
* are in el->el_key.map, adding the key "abc" will cause the first two
|
||||
* definitions to be lost.
|
||||
*
|
||||
* Restrictions:
|
||||
* -------------
|
||||
* 1) It is not possible to have one key that is a
|
||||
* substr of another.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "el.h"
|
||||
|
||||
/*
|
||||
* The Nodes of the el->el_key.map. The el->el_key.map is a linked list
|
||||
* of these node elements
|
||||
*/
|
||||
struct key_node_t {
|
||||
char ch; /* single character of key */
|
||||
int type; /* node type */
|
||||
key_value_t val; /* command code or pointer to str, */
|
||||
/* if this is a leaf */
|
||||
struct key_node_t *next; /* ptr to next char of this key */
|
||||
struct key_node_t *sibling; /* ptr to another key with same prefix*/
|
||||
};
|
||||
|
||||
private int node_trav(EditLine *, key_node_t *, char *,
|
||||
key_value_t *);
|
||||
private int node__try(EditLine *, key_node_t *, const char *,
|
||||
key_value_t *, int);
|
||||
private key_node_t *node__get(int);
|
||||
private void node__free(key_node_t *);
|
||||
private void node__put(EditLine *, key_node_t *);
|
||||
private int node__delete(EditLine *, key_node_t **, const char *);
|
||||
private int node_lookup(EditLine *, const char *, key_node_t *,
|
||||
int);
|
||||
private int node_enum(EditLine *, key_node_t *, int);
|
||||
private int key__decode_char(char *, int, int);
|
||||
|
||||
#define KEY_BUFSIZ EL_BUFSIZ
|
||||
|
||||
|
||||
/* key_init():
|
||||
* Initialize the key maps
|
||||
*/
|
||||
protected int
|
||||
key_init(EditLine *el)
|
||||
{
|
||||
|
||||
el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ);
|
||||
if (el->el_key.buf == NULL)
|
||||
return (-1);
|
||||
el->el_key.map = NULL;
|
||||
key_reset(el);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* key_end():
|
||||
* Free the key maps
|
||||
*/
|
||||
protected void
|
||||
key_end(EditLine *el)
|
||||
{
|
||||
|
||||
el_free((ptr_t) el->el_key.buf);
|
||||
el->el_key.buf = NULL;
|
||||
node__free(el->el_key.map);
|
||||
}
|
||||
|
||||
|
||||
/* key_map_cmd():
|
||||
* Associate cmd with a key value
|
||||
*/
|
||||
protected key_value_t *
|
||||
key_map_cmd(EditLine *el, int cmd)
|
||||
{
|
||||
|
||||
el->el_key.val.cmd = (el_action_t) cmd;
|
||||
return (&el->el_key.val);
|
||||
}
|
||||
|
||||
|
||||
/* key_map_str():
|
||||
* Associate str with a key value
|
||||
*/
|
||||
protected key_value_t *
|
||||
key_map_str(EditLine *el, char *str)
|
||||
{
|
||||
|
||||
el->el_key.val.str = str;
|
||||
return (&el->el_key.val);
|
||||
}
|
||||
|
||||
|
||||
/* key_reset():
|
||||
* Takes all nodes on el->el_key.map and puts them on free list. Then
|
||||
* initializes el->el_key.map with arrow keys
|
||||
* [Always bind the ansi arrow keys?]
|
||||
*/
|
||||
protected void
|
||||
key_reset(EditLine *el)
|
||||
{
|
||||
|
||||
node__put(el, el->el_key.map);
|
||||
el->el_key.map = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* key_get():
|
||||
* Calls the recursive function with entry point el->el_key.map
|
||||
* 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).
|
||||
* Returns NULL in val.str and XK_STR for no match.
|
||||
* The last character read is returned in *ch.
|
||||
*/
|
||||
protected int
|
||||
key_get(EditLine *el, char *ch, key_value_t *val)
|
||||
{
|
||||
|
||||
return (node_trav(el, el->el_key.map, ch, val));
|
||||
}
|
||||
|
||||
|
||||
/* key_add():
|
||||
* Adds key to the el->el_key.map and associates the value in val with it.
|
||||
* If key is already is in el->el_key.map, the new code is applied to the
|
||||
* existing key. Ntype specifies if code is a command, an
|
||||
* out str or a unix command.
|
||||
*/
|
||||
protected void
|
||||
key_add(EditLine *el, const char *key, key_value_t *val, int ntype)
|
||||
{
|
||||
|
||||
if (key[0] == '\0') {
|
||||
(void) fprintf(el->el_errfile,
|
||||
"key_add: Null extended-key not allowed.\n");
|
||||
return;
|
||||
}
|
||||
if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
|
||||
(void) fprintf(el->el_errfile,
|
||||
"key_add: sequence-lead-in command not allowed\n");
|
||||
return;
|
||||
}
|
||||
if (el->el_key.map == NULL)
|
||||
/* tree is initially empty. Set up new node to match key[0] */
|
||||
el->el_key.map = node__get(key[0]);
|
||||
/* it is properly initialized */
|
||||
|
||||
/* Now recurse through el->el_key.map */
|
||||
(void) node__try(el, el->el_key.map, key, val, ntype);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* key_clear():
|
||||
*
|
||||
*/
|
||||
protected void
|
||||
key_clear(EditLine *el, el_action_t *map, const char *in)
|
||||
{
|
||||
|
||||
if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
|
||||
((map == el->el_map.key &&
|
||||
el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
|
||||
(map == el->el_map.alt &&
|
||||
el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
|
||||
(void) key_delete(el, in);
|
||||
}
|
||||
|
||||
|
||||
/* key_delete():
|
||||
* Delete the key and all longer keys staring with key, if
|
||||
* they exists.
|
||||
*/
|
||||
protected int
|
||||
key_delete(EditLine *el, const char *key)
|
||||
{
|
||||
|
||||
if (key[0] == '\0') {
|
||||
(void) fprintf(el->el_errfile,
|
||||
"key_delete: Null extended-key not allowed.\n");
|
||||
return (-1);
|
||||
}
|
||||
if (el->el_key.map == NULL)
|
||||
return (0);
|
||||
|
||||
(void) node__delete(el, &el->el_key.map, key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* key_print():
|
||||
* Print the binding associated with key key.
|
||||
* Print entire el->el_key.map if null
|
||||
*/
|
||||
protected void
|
||||
key_print(EditLine *el, const char *key)
|
||||
{
|
||||
|
||||
/* do nothing if el->el_key.map is empty and null key specified */
|
||||
if (el->el_key.map == NULL && *key == 0)
|
||||
return;
|
||||
|
||||
el->el_key.buf[0] = '"';
|
||||
if (node_lookup(el, key, el->el_key.map, 1) <= -1)
|
||||
/* key is not bound */
|
||||
(void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n",
|
||||
key);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* node_trav():
|
||||
* recursively traverses node in tree until match or mismatch is
|
||||
* found. May read in more characters.
|
||||
*/
|
||||
private int
|
||||
node_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val)
|
||||
{
|
||||
|
||||
if (ptr->ch == *ch) {
|
||||
/* match found */
|
||||
if (ptr->next) {
|
||||
/* key not complete so get next char */
|
||||
if (el_getc(el, ch) != 1) { /* if EOF or error */
|
||||
val->cmd = ED_END_OF_FILE;
|
||||
return (XK_CMD);
|
||||
/* PWP: Pretend we just read an end-of-file */
|
||||
}
|
||||
return (node_trav(el, ptr->next, ch, val));
|
||||
} else {
|
||||
*val = ptr->val;
|
||||
if (ptr->type != XK_CMD)
|
||||
*ch = '\0';
|
||||
return (ptr->type);
|
||||
}
|
||||
} else {
|
||||
/* no match found here */
|
||||
if (ptr->sibling) {
|
||||
/* try next sibling */
|
||||
return (node_trav(el, ptr->sibling, ch, val));
|
||||
} else {
|
||||
/* no next sibling -- mismatch */
|
||||
val->str = NULL;
|
||||
return (XK_STR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* node__try():
|
||||
* Find a node that matches *str or allocate a new one
|
||||
*/
|
||||
private int
|
||||
node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ntype)
|
||||
{
|
||||
|
||||
if (ptr->ch != *str) {
|
||||
key_node_t *xm;
|
||||
|
||||
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;
|
||||
}
|
||||
if (*++str == '\0') {
|
||||
/* we're there */
|
||||
if (ptr->next != NULL) {
|
||||
node__put(el, ptr->next);
|
||||
/* 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)
|
||||
el_free((ptr_t) ptr->val.str);
|
||||
break;
|
||||
default:
|
||||
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
|
||||
ptr->type));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ptr->type = ntype) {
|
||||
case XK_CMD:
|
||||
ptr->val = *val;
|
||||
break;
|
||||
case XK_STR:
|
||||
case XK_EXE:
|
||||
if ((ptr->val.str = el_strdup(val->str)) == NULL)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* still more chars to go */
|
||||
if (ptr->next == NULL)
|
||||
ptr->next = node__get(*str); /* setup new node */
|
||||
(void) node__try(el, ptr->next, str, val, ntype);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* node__delete():
|
||||
* Delete node that matches str
|
||||
*/
|
||||
private int
|
||||
node__delete(EditLine *el, key_node_t **inptr, const char *str)
|
||||
{
|
||||
key_node_t *ptr;
|
||||
key_node_t *prev_ptr = NULL;
|
||||
|
||||
ptr = *inptr;
|
||||
|
||||
if (ptr->ch != *str) {
|
||||
key_node_t *xm;
|
||||
|
||||
for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
|
||||
if (xm->sibling->ch == *str)
|
||||
break;
|
||||
if (xm->sibling == NULL)
|
||||
return (0);
|
||||
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;
|
||||
node__put(el, ptr);
|
||||
return (1);
|
||||
} else if (ptr->next != NULL &&
|
||||
node__delete(el, &ptr->next, str) == 1) {
|
||||
if (ptr->next != NULL)
|
||||
return (0);
|
||||
if (prev_ptr == NULL)
|
||||
*inptr = ptr->sibling;
|
||||
else
|
||||
prev_ptr->sibling = ptr->sibling;
|
||||
ptr->sibling = NULL;
|
||||
node__put(el, ptr);
|
||||
return (1);
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* node__put():
|
||||
* Puts a tree of nodes onto free list using free(3).
|
||||
*/
|
||||
private void
|
||||
node__put(EditLine *el, key_node_t *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
if (ptr->next != NULL) {
|
||||
node__put(el, ptr->next);
|
||||
ptr->next = NULL;
|
||||
}
|
||||
node__put(el, ptr->sibling);
|
||||
|
||||
switch (ptr->type) {
|
||||
case XK_CMD:
|
||||
case XK_NOD:
|
||||
break;
|
||||
case XK_EXE:
|
||||
case XK_STR:
|
||||
if (ptr->val.str != NULL)
|
||||
el_free((ptr_t) ptr->val.str);
|
||||
break;
|
||||
default:
|
||||
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
|
||||
break;
|
||||
}
|
||||
el_free((ptr_t) ptr);
|
||||
}
|
||||
|
||||
|
||||
/* node__get():
|
||||
* Returns pointer to a key_node_t for ch.
|
||||
*/
|
||||
private key_node_t *
|
||||
node__get(int ch)
|
||||
{
|
||||
key_node_t *ptr;
|
||||
|
||||
ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
|
||||
if (ptr == NULL)
|
||||
return NULL;
|
||||
ptr->ch = ch;
|
||||
ptr->type = XK_NOD;
|
||||
ptr->val.str = NULL;
|
||||
ptr->next = NULL;
|
||||
ptr->sibling = NULL;
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
private void
|
||||
node__free(key_node_t *k)
|
||||
{
|
||||
if (k == NULL)
|
||||
return;
|
||||
node__free(k->sibling);
|
||||
node__free(k->next);
|
||||
el_free((ptr_t) k);
|
||||
}
|
||||
|
||||
/* node_lookup():
|
||||
* look for the str starting at node ptr.
|
||||
* Print if last node
|
||||
*/
|
||||
private int
|
||||
node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt)
|
||||
{
|
||||
int ncnt;
|
||||
|
||||
if (ptr == NULL)
|
||||
return (-1); /* cannot have null ptr */
|
||||
|
||||
if (*str == 0) {
|
||||
/* no more chars in str. node_enum from here. */
|
||||
(void) node_enum(el, ptr, cnt);
|
||||
return (0);
|
||||
} else {
|
||||
/* If match put this char into el->el_key.buf. Recurse */
|
||||
if (ptr->ch == *str) {
|
||||
/* match found */
|
||||
ncnt = key__decode_char(el->el_key.buf, cnt,
|
||||
(unsigned char) ptr->ch);
|
||||
if (ptr->next != NULL)
|
||||
/* not yet at leaf */
|
||||
return (node_lookup(el, str + 1, ptr->next,
|
||||
ncnt + 1));
|
||||
else {
|
||||
/* next node is null so key should be complete */
|
||||
if (str[1] == 0) {
|
||||
el->el_key.buf[ncnt + 1] = '"';
|
||||
el->el_key.buf[ncnt + 2] = '\0';
|
||||
key_kprint(el, el->el_key.buf,
|
||||
&ptr->val, ptr->type);
|
||||
return (0);
|
||||
} else
|
||||
return (-1);
|
||||
/* mismatch -- str still has chars */
|
||||
}
|
||||
} else {
|
||||
/* no match found try sibling */
|
||||
if (ptr->sibling)
|
||||
return (node_lookup(el, str, ptr->sibling,
|
||||
cnt));
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* node_enum():
|
||||
* Traverse the node printing the characters it is bound in buffer
|
||||
*/
|
||||
private int
|
||||
node_enum(EditLine *el, key_node_t *ptr, int cnt)
|
||||
{
|
||||
int ncnt;
|
||||
|
||||
if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */
|
||||
el->el_key.buf[++cnt] = '"';
|
||||
el->el_key.buf[++cnt] = '\0';
|
||||
(void) fprintf(el->el_errfile,
|
||||
"Some extended keys too long for internal print buffer");
|
||||
(void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
|
||||
return (0);
|
||||
}
|
||||
if (ptr == NULL) {
|
||||
#ifdef DEBUG_EDIT
|
||||
(void) fprintf(el->el_errfile,
|
||||
"node_enum: BUG!! Null ptr passed\n!");
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
/* put this char at end of str */
|
||||
ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch);
|
||||
if (ptr->next == NULL) {
|
||||
/* print this key and function */
|
||||
el->el_key.buf[ncnt + 1] = '"';
|
||||
el->el_key.buf[ncnt + 2] = '\0';
|
||||
key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
|
||||
} else
|
||||
(void) node_enum(el, ptr->next, ncnt + 1);
|
||||
|
||||
/* go to sibling if there is one */
|
||||
if (ptr->sibling)
|
||||
(void) node_enum(el, ptr->sibling, cnt);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* key_kprint():
|
||||
* Print the specified key and its associated
|
||||
* function specified by val
|
||||
*/
|
||||
protected void
|
||||
key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype)
|
||||
{
|
||||
el_bindings_t *fp;
|
||||
char unparsbuf[EL_BUFSIZ];
|
||||
static const char fmt[] = "%-15s-> %s\n";
|
||||
|
||||
if (val != NULL)
|
||||
switch (ntype) {
|
||||
case XK_STR:
|
||||
case XK_EXE:
|
||||
(void) fprintf(el->el_outfile, fmt, key,
|
||||
key__decode_str(val->str, unparsbuf,
|
||||
ntype == XK_STR ? "\"\"" : "[]"));
|
||||
break;
|
||||
case XK_CMD:
|
||||
for (fp = el->el_map.help; fp->name; fp++)
|
||||
if (val->cmd == fp->func) {
|
||||
(void) fprintf(el->el_outfile, fmt,
|
||||
key, fp->name);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_KEY
|
||||
if (fp->name == NULL)
|
||||
(void) fprintf(el->el_outfile,
|
||||
"BUG! Command not found.\n");
|
||||
#endif
|
||||
|
||||
break;
|
||||
default:
|
||||
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
|
||||
break;
|
||||
}
|
||||
else
|
||||
(void) fprintf(el->el_outfile, fmt, key, "no input");
|
||||
}
|
||||
|
||||
|
||||
/* key__decode_char():
|
||||
* Put a printable form of char in buf.
|
||||
*/
|
||||
private int
|
||||
key__decode_char(char *buf, int cnt, int ch)
|
||||
{
|
||||
ch = (unsigned char)ch;
|
||||
|
||||
if (ch == 0) {
|
||||
buf[cnt++] = '^';
|
||||
buf[cnt] = '@';
|
||||
return (cnt);
|
||||
}
|
||||
if (iscntrl(ch)) {
|
||||
buf[cnt++] = '^';
|
||||
if (ch == 0177)
|
||||
buf[cnt] = '?';
|
||||
else
|
||||
buf[cnt] = toascii(ch) | 0100;
|
||||
} else if (ch == '^') {
|
||||
buf[cnt++] = '\\';
|
||||
buf[cnt] = '^';
|
||||
} else if (ch == '\\') {
|
||||
buf[cnt++] = '\\';
|
||||
buf[cnt] = '\\';
|
||||
} else if (ch == ' ' || (isprint(ch) && !isspace(ch))) {
|
||||
buf[cnt] = ch;
|
||||
} else {
|
||||
buf[cnt++] = '\\';
|
||||
buf[cnt++] = (((unsigned int) ch >> 6) & 7) + '0';
|
||||
buf[cnt++] = (((unsigned int) ch >> 3) & 7) + '0';
|
||||
buf[cnt] = (ch & 7) + '0';
|
||||
}
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
|
||||
/* key__decode_str():
|
||||
* Make a printable version of the ey
|
||||
*/
|
||||
protected char *
|
||||
key__decode_str(const char *str, char *buf, const char *sep)
|
||||
{
|
||||
char *b;
|
||||
const char *p;
|
||||
|
||||
b = buf;
|
||||
if (sep[0] != '\0')
|
||||
*b++ = sep[0];
|
||||
if (*str == 0) {
|
||||
*b++ = '^';
|
||||
*b++ = '@';
|
||||
if (sep[0] != '\0' && sep[1] != '\0')
|
||||
*b++ = sep[1];
|
||||
*b++ = 0;
|
||||
return (buf);
|
||||
}
|
||||
for (p = str; *p != 0; p++) {
|
||||
if (iscntrl((unsigned char) *p)) {
|
||||
*b++ = '^';
|
||||
if (*p == '\177')
|
||||
*b++ = '?';
|
||||
else
|
||||
*b++ = toascii(*p) | 0100;
|
||||
} else if (*p == '^' || *p == '\\') {
|
||||
*b++ = '\\';
|
||||
*b++ = *p;
|
||||
} else if (*p == ' ' || (isprint((unsigned char) *p) &&
|
||||
!isspace((unsigned char) *p))) {
|
||||
*b++ = *p;
|
||||
} else {
|
||||
*b++ = '\\';
|
||||
*b++ = (((unsigned int) *p >> 6) & 7) + '0';
|
||||
*b++ = (((unsigned int) *p >> 3) & 7) + '0';
|
||||
*b++ = (*p & 7) + '0';
|
||||
}
|
||||
}
|
||||
if (sep[0] != '\0' && sep[1] != '\0')
|
||||
*b++ = sep[1];
|
||||
*b++ = 0;
|
||||
return (buf); /* should check for overflow */
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)key.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: key.h,v 1.8 2003/08/07 16:44:32 agc Exp $
|
||||
* $FreeBSD: src/lib/libedit/key.h,v 1.5 2005/08/08 17:17:56 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.key.h: Key macro header
|
||||
*/
|
||||
#ifndef _h_el_key
|
||||
#define _h_el_key
|
||||
|
||||
typedef union key_value_t {
|
||||
el_action_t cmd; /* If it is a command the # */
|
||||
char *str; /* If it is a string... */
|
||||
} key_value_t;
|
||||
|
||||
typedef struct key_node_t key_node_t;
|
||||
|
||||
typedef struct el_key_t {
|
||||
char *buf; /* Key print buffer */
|
||||
key_node_t *map; /* Key map */
|
||||
key_value_t val; /* Local conversion buffer */
|
||||
} el_key_t;
|
||||
|
||||
#define XK_CMD 0
|
||||
#define XK_STR 1
|
||||
#define XK_NOD 2
|
||||
#define XK_EXE 3
|
||||
|
||||
#include <term.h>
|
||||
|
||||
#undef key_end
|
||||
#undef key_clear
|
||||
#undef key_print
|
||||
|
||||
protected int key_init(EditLine *);
|
||||
protected void key_end(EditLine *);
|
||||
protected key_value_t *key_map_cmd(EditLine *, int);
|
||||
protected key_value_t *key_map_str(EditLine *, char *);
|
||||
protected void key_reset(EditLine *);
|
||||
protected int key_get(EditLine *, char *, key_value_t *);
|
||||
protected void key_add(EditLine *, const char *, key_value_t *, int);
|
||||
protected void key_clear(EditLine *, el_action_t *, const char *);
|
||||
protected int key_delete(EditLine *, const char *);
|
||||
protected void key_print(EditLine *, const char *);
|
||||
protected void key_kprint(EditLine *, const char *, key_value_t *,
|
||||
int);
|
||||
protected char *key__decode_str(const char *, char *, const char *);
|
||||
|
||||
#endif /* _h_el_key */
|
||||
@@ -0,0 +1,250 @@
|
||||
#!/bin/sh -
|
||||
# $NetBSD: makelist,v 1.10 2005/08/08 14:04:49 christos Exp $
|
||||
# $FreeBSD: src/lib/libedit/makelist,v 1.10 2005/10/04 21:59:29 stefanf Exp $
|
||||
#
|
||||
# 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.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# 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.
|
||||
#
|
||||
# @(#)makelist 5.3 (Berkeley) 6/4/93
|
||||
|
||||
# makelist.sh: Automatically generate header files...
|
||||
|
||||
AWK=awk
|
||||
USAGE="usage: $0 -h|-e|-fc|-fh|-bc|-bh|-m <filenames>"
|
||||
|
||||
if [ "x$1" = "x" ]
|
||||
then
|
||||
echo $USAGE 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FLAG="$1"
|
||||
shift
|
||||
|
||||
FILES="$@"
|
||||
|
||||
case $FLAG in
|
||||
|
||||
# generate foo.h file from foo.c
|
||||
#
|
||||
-h)
|
||||
set - `echo $FILES | sed -e 's/\\./_/g'`
|
||||
hdr="_h_`basename $1`"
|
||||
cat $FILES | $AWK '
|
||||
BEGIN {
|
||||
printf("/* Automatically generated file, do not edit */\n");
|
||||
printf("#ifndef %s\n#define %s\n", "'$hdr'", "'$hdr'");
|
||||
}
|
||||
/\(\):/ {
|
||||
pr = substr($2, 1, 2);
|
||||
if (pr == "vi" || pr == "em" || pr == "ed") {
|
||||
name = substr($2, 1, length($2) - 3);
|
||||
#
|
||||
# XXX: need a space between name and prototype so that -fc and -fh
|
||||
# parsing is much easier
|
||||
#
|
||||
printf("protected el_action_t\t%s (EditLine *, int);\n", name);
|
||||
}
|
||||
}
|
||||
END {
|
||||
printf("#endif /* %s */\n", "'$hdr'");
|
||||
}'
|
||||
;;
|
||||
|
||||
# generate help.c from various .c files
|
||||
#
|
||||
-bc)
|
||||
cat $FILES | $AWK '
|
||||
BEGIN {
|
||||
printf("/* Automatically generated file, do not edit */\n");
|
||||
printf("#include \"sys.h\"\n#include \"el.h\"\n");
|
||||
printf("private const struct el_bindings_t el_func_help[] = {\n");
|
||||
low = "abcdefghijklmnopqrstuvwxyz_";
|
||||
high = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_";
|
||||
for (i = 1; i <= length(low); i++)
|
||||
tr[substr(low, i, 1)] = substr(high, i, 1);
|
||||
}
|
||||
/\(\):/ {
|
||||
pr = substr($2, 1, 2);
|
||||
if (pr == "vi" || pr == "em" || pr == "ed") {
|
||||
name = substr($2, 1, length($2) - 3);
|
||||
uname = "";
|
||||
fname = "";
|
||||
for (i = 1; i <= length(name); i++) {
|
||||
s = substr(name, i, 1);
|
||||
uname = uname tr[s];
|
||||
if (s == "_")
|
||||
s = "-";
|
||||
fname = fname s;
|
||||
}
|
||||
|
||||
printf(" { %-30.30s %-30.30s\n","\"" fname "\",", uname ",");
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
/^ \*/ {
|
||||
if (ok) {
|
||||
printf(" \"");
|
||||
for (i = 2; i < NF; i++)
|
||||
printf("%s ", $i);
|
||||
printf("%s\" },\n", $i);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
END {
|
||||
printf("};\n");
|
||||
printf("\nprotected const el_bindings_t* help__get()");
|
||||
printf("{ return el_func_help; }\n");
|
||||
}'
|
||||
;;
|
||||
|
||||
# generate help.h from various .c files
|
||||
#
|
||||
-bh)
|
||||
$AWK '
|
||||
BEGIN {
|
||||
printf("/* Automatically generated file, do not edit */\n");
|
||||
printf("#ifndef _h_help_c\n#define _h_help_c\n");
|
||||
printf("protected const el_bindings_t *help__get(void);\n");
|
||||
printf("#endif /* _h_help_c */\n");
|
||||
}' /dev/null
|
||||
;;
|
||||
|
||||
# generate fcns.h from various .h files
|
||||
#
|
||||
-fh)
|
||||
cat $FILES | $AWK '/el_action_t/ { print $3 }' | \
|
||||
sort | LC_ALL=C tr 'a-z' 'A-Z' | $AWK '
|
||||
BEGIN {
|
||||
printf("/* Automatically generated file, do not edit */\n");
|
||||
printf("#ifndef _h_fcns_c\n#define _h_fcns_c\n");
|
||||
count = 0;
|
||||
}
|
||||
{
|
||||
printf("#define\t%-30.30s\t%3d\n", $1, count++);
|
||||
}
|
||||
END {
|
||||
printf("#define\t%-30.30s\t%3d\n", "EL_NUM_FCNS", count);
|
||||
|
||||
printf("typedef el_action_t (*el_func_t)(EditLine *, int);");
|
||||
printf("\nprotected const el_func_t* func__get(void);\n");
|
||||
printf("#endif /* _h_fcns_c */\n");
|
||||
}'
|
||||
;;
|
||||
|
||||
# generate fcns.c from various .h files
|
||||
#
|
||||
-fc)
|
||||
cat $FILES | $AWK '/el_action_t/ { print $3 }' | sort | $AWK '
|
||||
BEGIN {
|
||||
printf("/* Automatically generated file, do not edit */\n");
|
||||
printf("#include \"sys.h\"\n#include \"el.h\"\n");
|
||||
printf("private const el_func_t el_func[] = {");
|
||||
maxlen = 80;
|
||||
needn = 1;
|
||||
len = 0;
|
||||
}
|
||||
{
|
||||
clen = 25 + 2;
|
||||
len += clen;
|
||||
if (len >= maxlen)
|
||||
needn = 1;
|
||||
if (needn) {
|
||||
printf("\n ");
|
||||
needn = 0;
|
||||
len = 4 + clen;
|
||||
}
|
||||
s = $1 ",";
|
||||
printf("%-26.26s ", s);
|
||||
}
|
||||
END {
|
||||
printf("\n};\n");
|
||||
printf("\nprotected const el_func_t* func__get() { return el_func; }\n");
|
||||
}'
|
||||
;;
|
||||
|
||||
# generate editline.c from various .c files
|
||||
#
|
||||
-e)
|
||||
echo "$FILES" | tr ' ' '\012' | $AWK '
|
||||
BEGIN {
|
||||
printf("/* Automatically generated file, do not edit */\n");
|
||||
printf("#define protected static\n");
|
||||
printf("#define SCCSID\n");
|
||||
}
|
||||
{
|
||||
printf("#include \"%s\"\n", $1);
|
||||
}'
|
||||
;;
|
||||
|
||||
# generate man page fragment from various .c files
|
||||
#
|
||||
-m)
|
||||
cat $FILES | $AWK '
|
||||
BEGIN {
|
||||
printf(".\\\" Section automatically generated with makelist\n");
|
||||
printf(".Bl -tag -width 4n\n");
|
||||
}
|
||||
/\(\):/ {
|
||||
pr = substr($2, 1, 2);
|
||||
if (pr == "vi" || pr == "em" || pr == "ed") {
|
||||
name = substr($2, 1, length($2) - 3);
|
||||
fname = "";
|
||||
for (i = 1; i <= length(name); i++) {
|
||||
s = substr(name, i, 1);
|
||||
if (s == "_")
|
||||
s = "-";
|
||||
fname = fname s;
|
||||
}
|
||||
|
||||
printf(".It Ic %s\n", fname);
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
/^ \*/ {
|
||||
if (ok) {
|
||||
for (i = 2; i < NF; i++)
|
||||
printf("%s ", $i);
|
||||
printf("%s.\n", $i);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
END {
|
||||
printf(".El\n");
|
||||
printf(".\\\" End of section automatically generated with makelist\n");
|
||||
}'
|
||||
;;
|
||||
|
||||
*)
|
||||
echo $USAGE 1>&2
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
+1410
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)map.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: map.h,v 1.8 2003/08/07 16:44:32 agc Exp $
|
||||
* $FreeBSD: src/lib/libedit/map.h,v 1.4 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.map.h: Editor maps
|
||||
*/
|
||||
#ifndef _h_el_map
|
||||
#define _h_el_map
|
||||
|
||||
typedef struct el_bindings_t { /* for the "bind" shell command */
|
||||
const char *name; /* function name for bind command */
|
||||
int func; /* function numeric value */
|
||||
const char *description; /* description of function */
|
||||
} el_bindings_t;
|
||||
|
||||
|
||||
typedef struct el_map_t {
|
||||
el_action_t *alt; /* The current alternate key map */
|
||||
el_action_t *key; /* The current normal key map */
|
||||
el_action_t *current; /* The keymap we are using */
|
||||
const el_action_t *emacs; /* The default emacs key map */
|
||||
const el_action_t *vic; /* The vi command mode key map */
|
||||
const el_action_t *vii; /* The vi insert mode key map */
|
||||
int type; /* Emacs or vi */
|
||||
el_bindings_t *help; /* The help for the editor functions */
|
||||
el_func_t *func; /* List of available functions */
|
||||
int nfunc; /* The number of functions/help items */
|
||||
} el_map_t;
|
||||
|
||||
#define MAP_EMACS 0
|
||||
#define MAP_VI 1
|
||||
|
||||
protected int map_bind(EditLine *, int, const char **);
|
||||
protected int map_init(EditLine *);
|
||||
protected void map_end(EditLine *);
|
||||
protected void map_init_vi(EditLine *);
|
||||
protected void map_init_emacs(EditLine *);
|
||||
protected int map_set_editor(EditLine *, char *);
|
||||
protected int map_get_editor(EditLine *, const char **);
|
||||
protected int map_addfunc(EditLine *, const char *, const char *, el_func_t);
|
||||
|
||||
#endif /* _h_el_map */
|
||||
@@ -0,0 +1,261 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: parse.c,v 1.22 2005/05/29 04:58:15 lukem Exp $
|
||||
*/
|
||||
|
||||
#if !defined(lint) && !defined(SCCSID)
|
||||
static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* not lint && not SCCSID */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/parse.c,v 1.10 2005/08/07 20:51:52 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* parse.c: parse an editline extended command
|
||||
*
|
||||
* commands are:
|
||||
*
|
||||
* bind
|
||||
* echotc
|
||||
* edit
|
||||
* gettc
|
||||
* history
|
||||
* settc
|
||||
* setty
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include "el.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
private const struct {
|
||||
const char *name;
|
||||
int (*func)(EditLine *, int, const char **);
|
||||
} cmds[] = {
|
||||
{ "bind", map_bind },
|
||||
{ "echotc", term_echotc },
|
||||
{ "edit", el_editmode },
|
||||
{ "history", hist_command },
|
||||
{ "telltc", term_telltc },
|
||||
{ "settc", term_settc },
|
||||
{ "setty", tty_stty },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
/* parse_line():
|
||||
* Parse a line and dispatch it
|
||||
*/
|
||||
protected int
|
||||
parse_line(EditLine *el, const char *line)
|
||||
{
|
||||
const char **argv;
|
||||
int argc;
|
||||
Tokenizer *tok;
|
||||
|
||||
tok = tok_init(NULL);
|
||||
tok_str(tok, line, &argc, &argv);
|
||||
argc = el_parse(el, argc, argv);
|
||||
tok_end(tok);
|
||||
return (argc);
|
||||
}
|
||||
|
||||
|
||||
/* el_parse():
|
||||
* Command dispatcher
|
||||
*/
|
||||
public int
|
||||
el_parse(EditLine *el, int argc, const char *argv[])
|
||||
{
|
||||
const char *ptr;
|
||||
int i;
|
||||
|
||||
if (argc < 1)
|
||||
return (-1);
|
||||
ptr = strchr(argv[0], ':');
|
||||
if (ptr != NULL) {
|
||||
char *tprog;
|
||||
size_t l;
|
||||
|
||||
if (ptr == argv[0])
|
||||
return (0);
|
||||
l = ptr - argv[0] - 1;
|
||||
tprog = (char *) el_malloc(l + 1);
|
||||
if (tprog == NULL)
|
||||
return (0);
|
||||
(void) strncpy(tprog, argv[0], l);
|
||||
tprog[l] = '\0';
|
||||
ptr++;
|
||||
l = el_match(el->el_prog, tprog);
|
||||
el_free(tprog);
|
||||
if (!l)
|
||||
return (0);
|
||||
} else
|
||||
ptr = argv[0];
|
||||
|
||||
for (i = 0; cmds[i].name != NULL; i++)
|
||||
if (strcmp(cmds[i].name, ptr) == 0) {
|
||||
i = (*cmds[i].func) (el, argc, argv);
|
||||
return (-i);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* parse__escape():
|
||||
* Parse a string of the form ^<char> \<odigit> \<char> and return
|
||||
* the appropriate character or -1 if the escape is not valid
|
||||
*/
|
||||
protected int
|
||||
parse__escape(const char **ptr)
|
||||
{
|
||||
const char *p;
|
||||
int c;
|
||||
|
||||
p = *ptr;
|
||||
|
||||
if (p[1] == 0)
|
||||
return (-1);
|
||||
|
||||
if (*p == '\\') {
|
||||
p++;
|
||||
switch (*p) {
|
||||
case 'a':
|
||||
c = '\007'; /* Bell */
|
||||
break;
|
||||
case 'b':
|
||||
c = '\010'; /* Backspace */
|
||||
break;
|
||||
case 't':
|
||||
c = '\011'; /* Horizontal Tab */
|
||||
break;
|
||||
case 'n':
|
||||
c = '\012'; /* New Line */
|
||||
break;
|
||||
case 'v':
|
||||
c = '\013'; /* Vertical Tab */
|
||||
break;
|
||||
case 'f':
|
||||
c = '\014'; /* Form Feed */
|
||||
break;
|
||||
case 'r':
|
||||
c = '\015'; /* Carriage Return */
|
||||
break;
|
||||
case 'e':
|
||||
c = '\033'; /* Escape */
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
int cnt, ch;
|
||||
|
||||
for (cnt = 0, c = 0; cnt < 3; cnt++) {
|
||||
ch = *p++;
|
||||
if (ch < '0' || ch > '7') {
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
c = (c << 3) | (ch - '0');
|
||||
}
|
||||
if ((c & 0xffffff00) != 0)
|
||||
return (-1);
|
||||
--p;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
c = *p;
|
||||
break;
|
||||
}
|
||||
} else if (*p == '^') {
|
||||
p++;
|
||||
c = (*p == '?') ? '\177' : (*p & 0237);
|
||||
} else
|
||||
c = *p;
|
||||
*ptr = ++p;
|
||||
return ((unsigned char)c);
|
||||
}
|
||||
|
||||
/* parse__string():
|
||||
* Parse the escapes from in and put the raw string out
|
||||
*/
|
||||
protected char *
|
||||
parse__string(char *out, const char *in)
|
||||
{
|
||||
char *rv = out;
|
||||
int n;
|
||||
|
||||
for (;;)
|
||||
switch (*in) {
|
||||
case '\0':
|
||||
*out = '\0';
|
||||
return (rv);
|
||||
|
||||
case '\\':
|
||||
case '^':
|
||||
if ((n = parse__escape(&in)) == -1)
|
||||
return (NULL);
|
||||
*out++ = n;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (in[1] == '-' && in[2] != '\0') {
|
||||
*out++ = '\033';
|
||||
in += 2;
|
||||
break;
|
||||
}
|
||||
/*FALLTHROUGH*/
|
||||
|
||||
default:
|
||||
*out++ = *in++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* parse_cmd():
|
||||
* Return the command number for the command string given
|
||||
* or -1 if one is not found
|
||||
*/
|
||||
protected int
|
||||
parse_cmd(EditLine *el, const char *cmd)
|
||||
{
|
||||
el_bindings_t *b;
|
||||
|
||||
for (b = el->el_map.help; b->name != NULL; b++)
|
||||
if (strcmp(b->name, cmd) == 0)
|
||||
return (b->func);
|
||||
return (-1);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)parse.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: parse.h,v 1.6 2005/05/29 04:58:15 lukem Exp $
|
||||
* $FreeBSD: src/lib/libedit/parse.h,v 1.4 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.parse.h: Parser functions
|
||||
*/
|
||||
#ifndef _h_el_parse
|
||||
#define _h_el_parse
|
||||
|
||||
protected int parse_line(EditLine *, const char *);
|
||||
protected int parse__escape(const char **);
|
||||
protected char *parse__string(char *, const char *);
|
||||
protected int parse_cmd(EditLine *, const char *);
|
||||
|
||||
#endif /* _h_el_parse */
|
||||
@@ -0,0 +1,165 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: prompt.c,v 1.11 2003/08/07 16:44:32 agc Exp $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/prompt.c,v 1.6 2005/08/07 20:51:52 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* prompt.c: Prompt printing functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include <stdio.h>
|
||||
#include "el.h"
|
||||
|
||||
private char *prompt_default(EditLine *);
|
||||
private char *prompt_default_r(EditLine *);
|
||||
|
||||
/* prompt_default():
|
||||
* Just a default prompt, in case the user did not provide one
|
||||
*/
|
||||
private char *
|
||||
/*ARGSUSED*/
|
||||
prompt_default(EditLine *el __unused)
|
||||
{
|
||||
static char a[3] = {'?', ' ', '\0'};
|
||||
|
||||
return (a);
|
||||
}
|
||||
|
||||
|
||||
/* prompt_default_r():
|
||||
* Just a default rprompt, in case the user did not provide one
|
||||
*/
|
||||
private char *
|
||||
/*ARGSUSED*/
|
||||
prompt_default_r(EditLine *el __unused)
|
||||
{
|
||||
static char a[1] = {'\0'};
|
||||
|
||||
return (a);
|
||||
}
|
||||
|
||||
|
||||
/* prompt_print():
|
||||
* Print the prompt and update the prompt position.
|
||||
* We use an array of integers in case we want to pass
|
||||
* literal escape sequences in the prompt and we want a
|
||||
* bit to flag them
|
||||
*/
|
||||
protected void
|
||||
prompt_print(EditLine *el, int op)
|
||||
{
|
||||
el_prompt_t *elp;
|
||||
char *p;
|
||||
|
||||
if (op == EL_PROMPT)
|
||||
elp = &el->el_prompt;
|
||||
else
|
||||
elp = &el->el_rprompt;
|
||||
p = (elp->p_func) (el);
|
||||
while (*p)
|
||||
re_putc(el, *p++, 1);
|
||||
|
||||
elp->p_pos.v = el->el_refresh.r_cursor.v;
|
||||
elp->p_pos.h = el->el_refresh.r_cursor.h;
|
||||
}
|
||||
|
||||
|
||||
/* prompt_init():
|
||||
* Initialize the prompt stuff
|
||||
*/
|
||||
protected int
|
||||
prompt_init(EditLine *el)
|
||||
{
|
||||
|
||||
el->el_prompt.p_func = prompt_default;
|
||||
el->el_prompt.p_pos.v = 0;
|
||||
el->el_prompt.p_pos.h = 0;
|
||||
el->el_rprompt.p_func = prompt_default_r;
|
||||
el->el_rprompt.p_pos.v = 0;
|
||||
el->el_rprompt.p_pos.h = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* prompt_end():
|
||||
* Clean up the prompt stuff
|
||||
*/
|
||||
protected void
|
||||
/*ARGSUSED*/
|
||||
prompt_end(EditLine *el __unused)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* prompt_set():
|
||||
* Install a prompt printing function
|
||||
*/
|
||||
protected int
|
||||
prompt_set(EditLine *el, el_pfunc_t prf, int op)
|
||||
{
|
||||
el_prompt_t *p;
|
||||
|
||||
if (op == EL_PROMPT)
|
||||
p = &el->el_prompt;
|
||||
else
|
||||
p = &el->el_rprompt;
|
||||
if (prf == NULL) {
|
||||
if (op == EL_PROMPT)
|
||||
p->p_func = prompt_default;
|
||||
else
|
||||
p->p_func = prompt_default_r;
|
||||
} else
|
||||
p->p_func = prf;
|
||||
p->p_pos.v = 0;
|
||||
p->p_pos.h = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* prompt_get():
|
||||
* Retrieve the prompt printing function
|
||||
*/
|
||||
protected int
|
||||
prompt_get(EditLine *el, el_pfunc_t *prf, int op)
|
||||
{
|
||||
|
||||
if (prf == NULL)
|
||||
return (-1);
|
||||
if (op == EL_PROMPT)
|
||||
*prf = el->el_prompt.p_func;
|
||||
else
|
||||
*prf = el->el_rprompt.p_func;
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)prompt.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: prompt.h,v 1.6 2003/08/07 16:44:32 agc Exp $
|
||||
* $FreeBSD: src/lib/libedit/prompt.h,v 1.3 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.prompt.h: Prompt printing stuff
|
||||
*/
|
||||
#ifndef _h_el_prompt
|
||||
#define _h_el_prompt
|
||||
|
||||
#include "histedit.h"
|
||||
|
||||
typedef char * (*el_pfunc_t)(EditLine*);
|
||||
|
||||
typedef struct el_prompt_t {
|
||||
el_pfunc_t p_func; /* Function to return the prompt */
|
||||
coord_t p_pos; /* position in the line after prompt */
|
||||
} el_prompt_t;
|
||||
|
||||
protected void prompt_print(EditLine *, int);
|
||||
protected int prompt_set(EditLine *, el_pfunc_t, int);
|
||||
protected int prompt_get(EditLine *, el_pfunc_t *, int);
|
||||
protected int prompt_init(EditLine *);
|
||||
protected void prompt_end(EditLine *);
|
||||
|
||||
#endif /* _h_el_prompt */
|
||||
@@ -0,0 +1,610 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: read.c,v 1.39 2005/08/02 12:11:14 christos Exp $
|
||||
*/
|
||||
|
||||
#if !defined(lint) && !defined(SCCSID)
|
||||
static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* not lint && not SCCSID */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/read.c,v 1.12 2005/08/07 20:51:52 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* read.c: Clean this junk up! This is horrible code.
|
||||
* Terminal read functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "el.h"
|
||||
|
||||
#define OKCMD -1
|
||||
|
||||
private int read__fixio(int, int);
|
||||
private int read_preread(EditLine *);
|
||||
private int read_char(EditLine *, char *);
|
||||
private int read_getcmd(EditLine *, el_action_t *, char *);
|
||||
|
||||
/* read_init():
|
||||
* Initialize the read stuff
|
||||
*/
|
||||
protected int
|
||||
read_init(EditLine *el)
|
||||
{
|
||||
/* builtin read_char */
|
||||
el->el_read.read_char = read_char;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* el_read_setfn():
|
||||
* Set the read char function to the one provided.
|
||||
* If it is set to EL_BUILTIN_GETCFN, then reset to the builtin one.
|
||||
*/
|
||||
protected int
|
||||
el_read_setfn(EditLine *el, el_rfunc_t rc)
|
||||
{
|
||||
el->el_read.read_char = (rc == EL_BUILTIN_GETCFN) ? read_char : rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* el_read_getfn():
|
||||
* return the current read char function, or EL_BUILTIN_GETCFN
|
||||
* if it is the default one
|
||||
*/
|
||||
protected el_rfunc_t
|
||||
el_read_getfn(EditLine *el)
|
||||
{
|
||||
return (el->el_read.read_char == read_char) ?
|
||||
EL_BUILTIN_GETCFN : el->el_read.read_char;
|
||||
}
|
||||
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(A,B) ((A) < (B) ? (A) : (B))
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_EDIT
|
||||
private void
|
||||
read_debug(EditLine *el)
|
||||
{
|
||||
|
||||
if (el->el_line.cursor > el->el_line.lastchar)
|
||||
(void) fprintf(el->el_errfile, "cursor > lastchar\r\n");
|
||||
if (el->el_line.cursor < el->el_line.buffer)
|
||||
(void) fprintf(el->el_errfile, "cursor < buffer\r\n");
|
||||
if (el->el_line.cursor > el->el_line.limit)
|
||||
(void) fprintf(el->el_errfile, "cursor > limit\r\n");
|
||||
if (el->el_line.lastchar > el->el_line.limit)
|
||||
(void) fprintf(el->el_errfile, "lastchar > limit\r\n");
|
||||
if (el->el_line.limit != &el->el_line.buffer[EL_BUFSIZ - 2])
|
||||
(void) fprintf(el->el_errfile, "limit != &buffer[EL_BUFSIZ-2]\r\n");
|
||||
}
|
||||
#endif /* DEBUG_EDIT */
|
||||
|
||||
|
||||
/* read__fixio():
|
||||
* Try to recover from a read error
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
private int
|
||||
read__fixio(int fd __unused, int e)
|
||||
{
|
||||
|
||||
switch (e) {
|
||||
case -1: /* Make sure that the code is reachable */
|
||||
|
||||
#ifdef EWOULDBLOCK
|
||||
case EWOULDBLOCK:
|
||||
#ifndef TRY_AGAIN
|
||||
#define TRY_AGAIN
|
||||
#endif
|
||||
#endif /* EWOULDBLOCK */
|
||||
|
||||
#if defined(POSIX) && defined(EAGAIN)
|
||||
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||||
case EAGAIN:
|
||||
#ifndef TRY_AGAIN
|
||||
#define TRY_AGAIN
|
||||
#endif
|
||||
#endif /* EWOULDBLOCK && EWOULDBLOCK != EAGAIN */
|
||||
#endif /* POSIX && EAGAIN */
|
||||
|
||||
e = 0;
|
||||
#ifdef TRY_AGAIN
|
||||
#if defined(F_SETFL) && defined(O_NDELAY)
|
||||
if ((e = fcntl(fd, F_GETFL, 0)) == -1)
|
||||
return (-1);
|
||||
|
||||
if (fcntl(fd, F_SETFL, e & ~O_NDELAY) == -1)
|
||||
return (-1);
|
||||
else
|
||||
e = 1;
|
||||
#endif /* F_SETFL && O_NDELAY */
|
||||
|
||||
#ifdef FIONBIO
|
||||
{
|
||||
int zero = 0;
|
||||
|
||||
if (ioctl(fd, FIONBIO, (ioctl_t) & zero) == -1)
|
||||
return (-1);
|
||||
else
|
||||
e = 1;
|
||||
}
|
||||
#endif /* FIONBIO */
|
||||
|
||||
#endif /* TRY_AGAIN */
|
||||
return (e ? 0 : -1);
|
||||
|
||||
case EINTR:
|
||||
return (0);
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* read_preread():
|
||||
* Try to read the stuff in the input queue;
|
||||
*/
|
||||
private int
|
||||
read_preread(EditLine *el)
|
||||
{
|
||||
int chrs = 0;
|
||||
|
||||
if (el->el_tty.t_mode == ED_IO)
|
||||
return (0);
|
||||
|
||||
#ifdef FIONREAD
|
||||
(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
|
||||
if (chrs > 0) {
|
||||
char buf[EL_BUFSIZ];
|
||||
|
||||
chrs = read(el->el_infd, buf,
|
||||
(size_t) MIN(chrs, EL_BUFSIZ - 1));
|
||||
if (chrs > 0) {
|
||||
buf[chrs] = '\0';
|
||||
el_push(el, buf);
|
||||
}
|
||||
}
|
||||
#endif /* FIONREAD */
|
||||
|
||||
return (chrs > 0);
|
||||
}
|
||||
|
||||
|
||||
/* el_push():
|
||||
* Push a macro
|
||||
*/
|
||||
public void
|
||||
el_push(EditLine *el, char *str)
|
||||
{
|
||||
c_macro_t *ma = &el->el_chared.c_macro;
|
||||
|
||||
if (str != NULL && ma->level + 1 < EL_MAXMACRO) {
|
||||
ma->level++;
|
||||
if ((ma->macro[ma->level] = el_strdup(str)) != NULL)
|
||||
return;
|
||||
ma->level--;
|
||||
}
|
||||
term_beep(el);
|
||||
term__flush();
|
||||
}
|
||||
|
||||
|
||||
/* read_getcmd():
|
||||
* Return next command from the input stream.
|
||||
*/
|
||||
private int
|
||||
read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch)
|
||||
{
|
||||
el_action_t cmd;
|
||||
int num;
|
||||
|
||||
do {
|
||||
if ((num = el_getc(el, ch)) != 1) /* if EOF or error */
|
||||
return (num);
|
||||
|
||||
#ifdef KANJI
|
||||
if ((*ch & 0200)) {
|
||||
el->el_state.metanext = 0;
|
||||
cmd = CcViMap[' '];
|
||||
break;
|
||||
} else
|
||||
#endif /* KANJI */
|
||||
|
||||
if (el->el_state.metanext) {
|
||||
el->el_state.metanext = 0;
|
||||
*ch |= 0200;
|
||||
}
|
||||
cmd = el->el_map.current[(unsigned char) *ch];
|
||||
if (cmd == ED_SEQUENCE_LEAD_IN) {
|
||||
key_value_t val;
|
||||
switch (key_get(el, ch, &val)) {
|
||||
case XK_CMD:
|
||||
cmd = val.cmd;
|
||||
break;
|
||||
case XK_STR:
|
||||
el_push(el, val.str);
|
||||
break;
|
||||
#ifdef notyet
|
||||
case XK_EXE:
|
||||
/* XXX: In the future to run a user function */
|
||||
RunCommand(val.str);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
EL_ABORT((el->el_errfile, "Bad XK_ type \n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (el->el_map.alt == NULL)
|
||||
el->el_map.current = el->el_map.key;
|
||||
} while (cmd == ED_SEQUENCE_LEAD_IN);
|
||||
*cmdnum = cmd;
|
||||
return (OKCMD);
|
||||
}
|
||||
|
||||
|
||||
/* read_char():
|
||||
* Read a character from the tty.
|
||||
*/
|
||||
private int
|
||||
read_char(EditLine *el, char *cp)
|
||||
{
|
||||
int num_read;
|
||||
int tried = 0;
|
||||
|
||||
while ((num_read = read(el->el_infd, cp, 1)) == -1)
|
||||
if (!tried && read__fixio(el->el_infd, errno) == 0)
|
||||
tried = 1;
|
||||
else {
|
||||
*cp = '\0';
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (num_read);
|
||||
}
|
||||
|
||||
|
||||
/* el_getc():
|
||||
* Read a character
|
||||
*/
|
||||
public int
|
||||
el_getc(EditLine *el, char *cp)
|
||||
{
|
||||
int num_read;
|
||||
c_macro_t *ma = &el->el_chared.c_macro;
|
||||
|
||||
term__flush();
|
||||
for (;;) {
|
||||
if (ma->level < 0) {
|
||||
if (!read_preread(el))
|
||||
break;
|
||||
}
|
||||
if (ma->level < 0)
|
||||
break;
|
||||
|
||||
if (ma->macro[ma->level][ma->offset] == '\0') {
|
||||
el_free(ma->macro[ma->level--]);
|
||||
ma->offset = 0;
|
||||
continue;
|
||||
}
|
||||
*cp = ma->macro[ma->level][ma->offset++] & 0377;
|
||||
if (ma->macro[ma->level][ma->offset] == '\0') {
|
||||
/* Needed for QuoteMode On */
|
||||
el_free(ma->macro[ma->level--]);
|
||||
ma->offset = 0;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_READ
|
||||
(void) fprintf(el->el_errfile, "Turning raw mode on\n");
|
||||
#endif /* DEBUG_READ */
|
||||
if (tty_rawmode(el) < 0)/* make sure the tty is set up correctly */
|
||||
return (0);
|
||||
|
||||
#ifdef DEBUG_READ
|
||||
(void) fprintf(el->el_errfile, "Reading a character\n");
|
||||
#endif /* DEBUG_READ */
|
||||
num_read = (*el->el_read.read_char)(el, cp);
|
||||
#ifdef DEBUG_READ
|
||||
(void) fprintf(el->el_errfile, "Got it %c\n", *cp);
|
||||
#endif /* DEBUG_READ */
|
||||
return (num_read);
|
||||
}
|
||||
|
||||
protected void
|
||||
read_prepare(EditLine *el)
|
||||
{
|
||||
if (el->el_flags & HANDLE_SIGNALS)
|
||||
sig_set(el);
|
||||
if (el->el_flags & NO_TTY)
|
||||
return;
|
||||
if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED)
|
||||
tty_rawmode(el);
|
||||
|
||||
/* This is relatively cheap, and things go terribly wrong if
|
||||
we have the wrong size. */
|
||||
el_resize(el);
|
||||
re_clear_display(el); /* reset the display stuff */
|
||||
ch_reset(el, 0);
|
||||
re_refresh(el); /* print the prompt */
|
||||
|
||||
if (el->el_flags & UNBUFFERED)
|
||||
term__flush();
|
||||
}
|
||||
|
||||
protected void
|
||||
read_finish(EditLine *el)
|
||||
{
|
||||
if ((el->el_flags & UNBUFFERED) == 0)
|
||||
(void) tty_cookedmode(el);
|
||||
if (el->el_flags & HANDLE_SIGNALS)
|
||||
sig_clr(el);
|
||||
}
|
||||
|
||||
public const char *
|
||||
el_gets(EditLine *el, int *nread)
|
||||
{
|
||||
int retval;
|
||||
el_action_t cmdnum = 0;
|
||||
int num; /* how many chars we have read at NL */
|
||||
char ch;
|
||||
int crlf = 0;
|
||||
#ifdef FIONREAD
|
||||
c_macro_t *ma = &el->el_chared.c_macro;
|
||||
#endif /* FIONREAD */
|
||||
|
||||
if (el->el_flags & NO_TTY) {
|
||||
char *cp = el->el_line.buffer;
|
||||
size_t idx;
|
||||
|
||||
while ((*el->el_read.read_char)(el, cp) == 1) {
|
||||
/* make sure there is space for next character */
|
||||
if (cp + 1 >= el->el_line.limit) {
|
||||
idx = (cp - el->el_line.buffer);
|
||||
if (!ch_enlargebufs(el, 2))
|
||||
break;
|
||||
cp = &el->el_line.buffer[idx];
|
||||
}
|
||||
cp++;
|
||||
if (el->el_flags & UNBUFFERED)
|
||||
break;
|
||||
if (cp[-1] == '\r' || cp[-1] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
el->el_line.cursor = el->el_line.lastchar = cp;
|
||||
*cp = '\0';
|
||||
if (nread)
|
||||
*nread = el->el_line.cursor - el->el_line.buffer;
|
||||
return (el->el_line.buffer);
|
||||
}
|
||||
|
||||
|
||||
#ifdef FIONREAD
|
||||
if (el->el_tty.t_mode == EX_IO && ma->level < 0) {
|
||||
long chrs = 0;
|
||||
|
||||
(void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs);
|
||||
if (chrs == 0) {
|
||||
if (tty_rawmode(el) < 0) {
|
||||
if (nread)
|
||||
*nread = 0;
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* FIONREAD */
|
||||
|
||||
if ((el->el_flags & UNBUFFERED) == 0)
|
||||
read_prepare(el);
|
||||
|
||||
if (el->el_flags & EDIT_DISABLED) {
|
||||
char *cp;
|
||||
size_t idx;
|
||||
if ((el->el_flags & UNBUFFERED) == 0)
|
||||
cp = el->el_line.buffer;
|
||||
else
|
||||
cp = el->el_line.lastchar;
|
||||
|
||||
term__flush();
|
||||
|
||||
while ((*el->el_read.read_char)(el, cp) == 1) {
|
||||
/* make sure there is space next character */
|
||||
if (cp + 1 >= el->el_line.limit) {
|
||||
idx = (cp - el->el_line.buffer);
|
||||
if (!ch_enlargebufs(el, 2))
|
||||
break;
|
||||
cp = &el->el_line.buffer[idx];
|
||||
}
|
||||
if (*cp == 4) /* ought to be stty eof */
|
||||
break;
|
||||
cp++;
|
||||
crlf = cp[-1] == '\r' || cp[-1] == '\n';
|
||||
if (el->el_flags & UNBUFFERED)
|
||||
break;
|
||||
if (crlf)
|
||||
break;
|
||||
}
|
||||
|
||||
el->el_line.cursor = el->el_line.lastchar = cp;
|
||||
*cp = '\0';
|
||||
if (nread)
|
||||
*nread = el->el_line.cursor - el->el_line.buffer;
|
||||
return (el->el_line.buffer);
|
||||
}
|
||||
|
||||
for (num = OKCMD; num == OKCMD;) { /* while still editing this
|
||||
* line */
|
||||
#ifdef DEBUG_EDIT
|
||||
read_debug(el);
|
||||
#endif /* DEBUG_EDIT */
|
||||
/* if EOF or error */
|
||||
if ((num = read_getcmd(el, &cmdnum, &ch)) != OKCMD) {
|
||||
#ifdef DEBUG_READ
|
||||
(void) fprintf(el->el_errfile,
|
||||
"Returning from el_gets %d\n", num);
|
||||
#endif /* DEBUG_READ */
|
||||
break;
|
||||
}
|
||||
if ((unsigned int)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */
|
||||
#ifdef DEBUG_EDIT
|
||||
(void) fprintf(el->el_errfile,
|
||||
"ERROR: illegal command from key 0%o\r\n", ch);
|
||||
#endif /* DEBUG_EDIT */
|
||||
continue; /* try again */
|
||||
}
|
||||
/* now do the real command */
|
||||
#ifdef DEBUG_READ
|
||||
{
|
||||
el_bindings_t *b;
|
||||
for (b = el->el_map.help; b->name; b++)
|
||||
if (b->func == cmdnum)
|
||||
break;
|
||||
if (b->name)
|
||||
(void) fprintf(el->el_errfile,
|
||||
"Executing %s\n", b->name);
|
||||
else
|
||||
(void) fprintf(el->el_errfile,
|
||||
"Error command = %d\n", cmdnum);
|
||||
}
|
||||
#endif /* DEBUG_READ */
|
||||
/* vi redo needs these way down the levels... */
|
||||
el->el_state.thiscmd = cmdnum;
|
||||
el->el_state.thisch = ch;
|
||||
if (el->el_map.type == MAP_VI &&
|
||||
el->el_map.current == el->el_map.key &&
|
||||
el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) {
|
||||
if (cmdnum == VI_DELETE_PREV_CHAR &&
|
||||
el->el_chared.c_redo.pos != el->el_chared.c_redo.buf
|
||||
&& isprint((unsigned char)el->el_chared.c_redo.pos[-1]))
|
||||
el->el_chared.c_redo.pos--;
|
||||
else
|
||||
*el->el_chared.c_redo.pos++ = ch;
|
||||
}
|
||||
retval = (*el->el_map.func[cmdnum]) (el, ch);
|
||||
#ifdef DEBUG_READ
|
||||
(void) fprintf(el->el_errfile,
|
||||
"Returned state %d\n", retval );
|
||||
#endif /* DEBUG_READ */
|
||||
|
||||
/* save the last command here */
|
||||
el->el_state.lastcmd = cmdnum;
|
||||
|
||||
/* use any return value */
|
||||
switch (retval) {
|
||||
case CC_CURSOR:
|
||||
re_refresh_cursor(el);
|
||||
break;
|
||||
|
||||
case CC_REDISPLAY:
|
||||
re_clear_lines(el);
|
||||
re_clear_display(el);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case CC_REFRESH:
|
||||
re_refresh(el);
|
||||
break;
|
||||
|
||||
case CC_REFRESH_BEEP:
|
||||
re_refresh(el);
|
||||
term_beep(el);
|
||||
break;
|
||||
|
||||
case CC_NORM: /* normal char */
|
||||
break;
|
||||
|
||||
case CC_ARGHACK: /* Suggested by Rich Salz */
|
||||
/* <[email protected]> */
|
||||
continue; /* keep going... */
|
||||
|
||||
case CC_EOF: /* end of file typed */
|
||||
if ((el->el_flags & UNBUFFERED) == 0)
|
||||
num = 0;
|
||||
else if (num == -1) {
|
||||
*el->el_line.lastchar++ = CONTROL('d');
|
||||
el->el_line.cursor = el->el_line.lastchar;
|
||||
num = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case CC_NEWLINE: /* normal end of line */
|
||||
num = el->el_line.lastchar - el->el_line.buffer;
|
||||
break;
|
||||
|
||||
case CC_FATAL: /* fatal error, reset to known state */
|
||||
#ifdef DEBUG_READ
|
||||
(void) fprintf(el->el_errfile,
|
||||
"*** editor fatal ERROR ***\r\n\n");
|
||||
#endif /* DEBUG_READ */
|
||||
/* put (real) cursor in a known place */
|
||||
re_clear_display(el); /* reset the display stuff */
|
||||
ch_reset(el, 1); /* reset the input pointers */
|
||||
re_refresh(el); /* print the prompt again */
|
||||
break;
|
||||
|
||||
case CC_ERROR:
|
||||
default: /* functions we don't know about */
|
||||
#ifdef DEBUG_READ
|
||||
(void) fprintf(el->el_errfile,
|
||||
"*** editor ERROR ***\r\n\n");
|
||||
#endif /* DEBUG_READ */
|
||||
term_beep(el);
|
||||
term__flush();
|
||||
break;
|
||||
}
|
||||
el->el_state.argument = 1;
|
||||
el->el_state.doingarg = 0;
|
||||
el->el_chared.c_vcmd.action = NOP;
|
||||
if (el->el_flags & UNBUFFERED)
|
||||
break;
|
||||
}
|
||||
|
||||
term__flush(); /* flush any buffered output */
|
||||
/* make sure the tty is set up correctly */
|
||||
if ((el->el_flags & UNBUFFERED) == 0) {
|
||||
read_finish(el);
|
||||
if (nread)
|
||||
*nread = num;
|
||||
} else {
|
||||
if (nread)
|
||||
*nread = el->el_line.lastchar - el->el_line.buffer;
|
||||
}
|
||||
return (num ? el->el_line.buffer : NULL);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Anthony Mallet.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*
|
||||
* $NetBSD: read.h,v 1.4 2004/02/27 14:52:18 christos Exp $
|
||||
* $FreeBSD: src/lib/libedit/read.h,v 1.1 2005/08/07 20:55:59 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.read.h: Character reading functions
|
||||
*/
|
||||
#ifndef _h_el_read
|
||||
#define _h_el_read
|
||||
|
||||
typedef int (*el_rfunc_t)(EditLine *, char *);
|
||||
|
||||
typedef struct el_read_t {
|
||||
el_rfunc_t read_char; /* Function to read a character */
|
||||
} el_read_t;
|
||||
|
||||
protected int read_init(EditLine *);
|
||||
protected void read_prepare(EditLine *);
|
||||
protected void read_finish(EditLine *);
|
||||
protected int el_read_setfn(EditLine *, el_rfunc_t);
|
||||
protected el_rfunc_t el_read_getfn(EditLine *);
|
||||
|
||||
#endif /* _h_el_read */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)refresh.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: refresh.h,v 1.5 2003/08/07 16:44:33 agc Exp $
|
||||
* $FreeBSD: src/lib/libedit/refresh.h,v 1.3 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.refresh.h: Screen refresh functions
|
||||
*/
|
||||
#ifndef _h_el_refresh
|
||||
#define _h_el_refresh
|
||||
|
||||
#include "histedit.h"
|
||||
|
||||
typedef struct {
|
||||
coord_t r_cursor; /* Refresh cursor position */
|
||||
int r_oldcv; /* Vertical locations */
|
||||
int r_newcv;
|
||||
} el_refresh_t;
|
||||
|
||||
protected void re_putc(EditLine *, int, int);
|
||||
protected void re_clear_lines(EditLine *);
|
||||
protected void re_clear_display(EditLine *);
|
||||
protected void re_refresh(EditLine *);
|
||||
protected void re_refresh_cursor(EditLine *);
|
||||
protected void re_fastaddc(EditLine *);
|
||||
protected void re_goto_bottom(EditLine *);
|
||||
|
||||
#endif /* _h_el_refresh */
|
||||
@@ -0,0 +1,631 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: search.c,v 1.20 2004/11/04 01:16:03 christos Exp $
|
||||
*/
|
||||
|
||||
#if !defined(lint) && !defined(SCCSID)
|
||||
static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* not lint && not SCCSID */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/search.c,v 1.10 2005/08/07 20:51:52 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* search.c: History and character search functions
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include <stdlib.h>
|
||||
#if defined(REGEX)
|
||||
#include <regex.h>
|
||||
#elif defined(REGEXP)
|
||||
#include <regexp.h>
|
||||
#endif
|
||||
#include "el.h"
|
||||
|
||||
/*
|
||||
* Adjust cursor in vi mode to include the character under it
|
||||
*/
|
||||
#define EL_CURSOR(el) \
|
||||
((el)->el_line.cursor + (((el)->el_map.type == MAP_VI) && \
|
||||
((el)->el_map.current == (el)->el_map.alt)))
|
||||
|
||||
/* search_init():
|
||||
* Initialize the search stuff
|
||||
*/
|
||||
protected int
|
||||
search_init(EditLine *el)
|
||||
{
|
||||
|
||||
el->el_search.patbuf = (char *) el_malloc(EL_BUFSIZ);
|
||||
if (el->el_search.patbuf == NULL)
|
||||
return (-1);
|
||||
el->el_search.patlen = 0;
|
||||
el->el_search.patdir = -1;
|
||||
el->el_search.chacha = '\0';
|
||||
el->el_search.chadir = CHAR_FWD;
|
||||
el->el_search.chatflg = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* search_end():
|
||||
* Initialize the search stuff
|
||||
*/
|
||||
protected void
|
||||
search_end(EditLine *el)
|
||||
{
|
||||
|
||||
el_free((ptr_t) el->el_search.patbuf);
|
||||
el->el_search.patbuf = NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef REGEXP
|
||||
/* regerror():
|
||||
* Handle regular expression errors
|
||||
*/
|
||||
public void
|
||||
/*ARGSUSED*/
|
||||
regerror(const char *msg)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* el_match():
|
||||
* Return if string matches pattern
|
||||
*/
|
||||
protected int
|
||||
el_match(const char *str, const char *pat)
|
||||
{
|
||||
#if defined (REGEX)
|
||||
regex_t re;
|
||||
int rv;
|
||||
#elif defined (REGEXP)
|
||||
regexp *rp;
|
||||
int rv;
|
||||
#else
|
||||
extern char *re_comp(const char *);
|
||||
extern int re_exec(const char *);
|
||||
#endif
|
||||
|
||||
if (strstr(str, pat) != NULL)
|
||||
return (1);
|
||||
|
||||
#if defined(REGEX)
|
||||
if (regcomp(&re, pat, 0) == 0) {
|
||||
rv = regexec(&re, str, 0, NULL, 0) == 0;
|
||||
regfree(&re);
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
return (rv);
|
||||
#elif defined(REGEXP)
|
||||
if ((re = regcomp(pat)) != NULL) {
|
||||
rv = regexec(re, str);
|
||||
free((ptr_t) re);
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
return (rv);
|
||||
#else
|
||||
if (re_comp(pat) != NULL)
|
||||
return (0);
|
||||
else
|
||||
return (re_exec(str) == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* c_hmatch():
|
||||
* return True if the pattern matches the prefix
|
||||
*/
|
||||
protected int
|
||||
c_hmatch(EditLine *el, const char *str)
|
||||
{
|
||||
#ifdef SDEBUG
|
||||
(void) fprintf(el->el_errfile, "match `%s' with `%s'\n",
|
||||
el->el_search.patbuf, str);
|
||||
#endif /* SDEBUG */
|
||||
|
||||
return (el_match(str, el->el_search.patbuf));
|
||||
}
|
||||
|
||||
|
||||
/* c_setpat():
|
||||
* Set the history seatch pattern
|
||||
*/
|
||||
protected void
|
||||
c_setpat(EditLine *el)
|
||||
{
|
||||
if (el->el_state.lastcmd != ED_SEARCH_PREV_HISTORY &&
|
||||
el->el_state.lastcmd != ED_SEARCH_NEXT_HISTORY) {
|
||||
el->el_search.patlen = EL_CURSOR(el) - el->el_line.buffer;
|
||||
if (el->el_search.patlen >= EL_BUFSIZ)
|
||||
el->el_search.patlen = EL_BUFSIZ - 1;
|
||||
if (el->el_search.patlen != 0) {
|
||||
(void) strncpy(el->el_search.patbuf, el->el_line.buffer,
|
||||
el->el_search.patlen);
|
||||
el->el_search.patbuf[el->el_search.patlen] = '\0';
|
||||
} else
|
||||
el->el_search.patlen = strlen(el->el_search.patbuf);
|
||||
}
|
||||
#ifdef SDEBUG
|
||||
(void) fprintf(el->el_errfile, "\neventno = %d\n",
|
||||
el->el_history.eventno);
|
||||
(void) fprintf(el->el_errfile, "patlen = %d\n", el->el_search.patlen);
|
||||
(void) fprintf(el->el_errfile, "patbuf = \"%s\"\n",
|
||||
el->el_search.patbuf);
|
||||
(void) fprintf(el->el_errfile, "cursor %d lastchar %d\n",
|
||||
EL_CURSOR(el) - el->el_line.buffer,
|
||||
el->el_line.lastchar - el->el_line.buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* ce_inc_search():
|
||||
* Emacs incremental search
|
||||
*/
|
||||
protected el_action_t
|
||||
ce_inc_search(EditLine *el, int dir)
|
||||
{
|
||||
static const char STRfwd[] = {'f', 'w', 'd', '\0'},
|
||||
STRbck[] = {'b', 'c', 'k', '\0'};
|
||||
static char pchar = ':';/* ':' = normal, '?' = failed */
|
||||
static char endcmd[2] = {'\0', '\0'};
|
||||
char ch, *ocursor = el->el_line.cursor, oldpchar = pchar;
|
||||
const char *cp;
|
||||
|
||||
el_action_t ret = CC_NORM;
|
||||
|
||||
int ohisteventno = el->el_history.eventno;
|
||||
int oldpatlen = el->el_search.patlen;
|
||||
int newdir = dir;
|
||||
int done, redo;
|
||||
|
||||
if (el->el_line.lastchar + sizeof(STRfwd) / sizeof(char) + 2 +
|
||||
el->el_search.patlen >= el->el_line.limit)
|
||||
return (CC_ERROR);
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (el->el_search.patlen == 0) { /* first round */
|
||||
pchar = ':';
|
||||
#ifdef ANCHOR
|
||||
#define LEN 2
|
||||
el->el_search.patbuf[el->el_search.patlen++] = '.';
|
||||
el->el_search.patbuf[el->el_search.patlen++] = '*';
|
||||
#else
|
||||
#define LEN 0
|
||||
#endif
|
||||
}
|
||||
done = redo = 0;
|
||||
*el->el_line.lastchar++ = '\n';
|
||||
for (cp = (newdir == ED_SEARCH_PREV_HISTORY) ? STRbck : STRfwd;
|
||||
*cp; *el->el_line.lastchar++ = *cp++)
|
||||
continue;
|
||||
*el->el_line.lastchar++ = pchar;
|
||||
for (cp = &el->el_search.patbuf[LEN];
|
||||
cp < &el->el_search.patbuf[el->el_search.patlen];
|
||||
*el->el_line.lastchar++ = *cp++)
|
||||
continue;
|
||||
*el->el_line.lastchar = '\0';
|
||||
re_refresh(el);
|
||||
|
||||
if (el_getc(el, &ch) != 1)
|
||||
return (ed_end_of_file(el, 0));
|
||||
|
||||
switch (el->el_map.current[(unsigned char) ch]) {
|
||||
case ED_INSERT:
|
||||
case ED_DIGIT:
|
||||
if (el->el_search.patlen >= EL_BUFSIZ - LEN)
|
||||
term_beep(el);
|
||||
else {
|
||||
el->el_search.patbuf[el->el_search.patlen++] =
|
||||
ch;
|
||||
*el->el_line.lastchar++ = ch;
|
||||
*el->el_line.lastchar = '\0';
|
||||
re_refresh(el);
|
||||
}
|
||||
break;
|
||||
|
||||
case EM_INC_SEARCH_NEXT:
|
||||
newdir = ED_SEARCH_NEXT_HISTORY;
|
||||
redo++;
|
||||
break;
|
||||
|
||||
case EM_INC_SEARCH_PREV:
|
||||
newdir = ED_SEARCH_PREV_HISTORY;
|
||||
redo++;
|
||||
break;
|
||||
|
||||
case EM_DELETE_PREV_CHAR:
|
||||
case ED_DELETE_PREV_CHAR:
|
||||
if (el->el_search.patlen > LEN)
|
||||
done++;
|
||||
else
|
||||
term_beep(el);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (ch) {
|
||||
case 0007: /* ^G: Abort */
|
||||
ret = CC_ERROR;
|
||||
done++;
|
||||
break;
|
||||
|
||||
case 0027: /* ^W: Append word */
|
||||
/* No can do if globbing characters in pattern */
|
||||
for (cp = &el->el_search.patbuf[LEN];; cp++)
|
||||
if (cp >= &el->el_search.patbuf[
|
||||
el->el_search.patlen]) {
|
||||
el->el_line.cursor +=
|
||||
el->el_search.patlen - LEN - 1;
|
||||
cp = c__next_word(el->el_line.cursor,
|
||||
el->el_line.lastchar, 1,
|
||||
ce__isword);
|
||||
while (el->el_line.cursor < cp &&
|
||||
*el->el_line.cursor != '\n') {
|
||||
if (el->el_search.patlen >=
|
||||
EL_BUFSIZ - LEN) {
|
||||
term_beep(el);
|
||||
break;
|
||||
}
|
||||
el->el_search.patbuf[el->el_search.patlen++] =
|
||||
*el->el_line.cursor;
|
||||
*el->el_line.lastchar++ =
|
||||
*el->el_line.cursor++;
|
||||
}
|
||||
el->el_line.cursor = ocursor;
|
||||
*el->el_line.lastchar = '\0';
|
||||
re_refresh(el);
|
||||
break;
|
||||
} else if (isglob(*cp)) {
|
||||
term_beep(el);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* Terminate and execute cmd */
|
||||
endcmd[0] = ch;
|
||||
el_push(el, endcmd);
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case 0033: /* ESC: Terminate */
|
||||
ret = CC_REFRESH;
|
||||
done++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
while (el->el_line.lastchar > el->el_line.buffer &&
|
||||
*el->el_line.lastchar != '\n')
|
||||
*el->el_line.lastchar-- = '\0';
|
||||
*el->el_line.lastchar = '\0';
|
||||
|
||||
if (!done) {
|
||||
|
||||
/* Can't search if unmatched '[' */
|
||||
for (cp = &el->el_search.patbuf[el->el_search.patlen-1],
|
||||
ch = ']';
|
||||
cp >= &el->el_search.patbuf[LEN];
|
||||
cp--)
|
||||
if (*cp == '[' || *cp == ']') {
|
||||
ch = *cp;
|
||||
break;
|
||||
}
|
||||
if (el->el_search.patlen > LEN && ch != '[') {
|
||||
if (redo && newdir == dir) {
|
||||
if (pchar == '?') { /* wrap around */
|
||||
el->el_history.eventno =
|
||||
newdir == ED_SEARCH_PREV_HISTORY ? 0 : 0x7fffffff;
|
||||
if (hist_get(el) == CC_ERROR)
|
||||
/* el->el_history.event
|
||||
* no was fixed by
|
||||
* first call */
|
||||
(void) hist_get(el);
|
||||
el->el_line.cursor = newdir ==
|
||||
ED_SEARCH_PREV_HISTORY ?
|
||||
el->el_line.lastchar :
|
||||
el->el_line.buffer;
|
||||
} else
|
||||
el->el_line.cursor +=
|
||||
newdir ==
|
||||
ED_SEARCH_PREV_HISTORY ?
|
||||
-1 : 1;
|
||||
}
|
||||
#ifdef ANCHOR
|
||||
el->el_search.patbuf[el->el_search.patlen++] =
|
||||
'.';
|
||||
el->el_search.patbuf[el->el_search.patlen++] =
|
||||
'*';
|
||||
#endif
|
||||
el->el_search.patbuf[el->el_search.patlen] =
|
||||
'\0';
|
||||
if (el->el_line.cursor < el->el_line.buffer ||
|
||||
el->el_line.cursor > el->el_line.lastchar ||
|
||||
(ret = ce_search_line(el, newdir))
|
||||
== CC_ERROR) {
|
||||
/* avoid c_setpat */
|
||||
el->el_state.lastcmd =
|
||||
(el_action_t) newdir;
|
||||
ret = newdir == ED_SEARCH_PREV_HISTORY ?
|
||||
ed_search_prev_history(el, 0) :
|
||||
ed_search_next_history(el, 0);
|
||||
if (ret != CC_ERROR) {
|
||||
el->el_line.cursor = newdir ==
|
||||
ED_SEARCH_PREV_HISTORY ?
|
||||
el->el_line.lastchar :
|
||||
el->el_line.buffer;
|
||||
(void) ce_search_line(el,
|
||||
newdir);
|
||||
}
|
||||
}
|
||||
el->el_search.patlen -= LEN;
|
||||
el->el_search.patbuf[el->el_search.patlen] =
|
||||
'\0';
|
||||
if (ret == CC_ERROR) {
|
||||
term_beep(el);
|
||||
if (el->el_history.eventno !=
|
||||
ohisteventno) {
|
||||
el->el_history.eventno =
|
||||
ohisteventno;
|
||||
if (hist_get(el) == CC_ERROR)
|
||||
return (CC_ERROR);
|
||||
}
|
||||
el->el_line.cursor = ocursor;
|
||||
pchar = '?';
|
||||
} else {
|
||||
pchar = ':';
|
||||
}
|
||||
}
|
||||
ret = ce_inc_search(el, newdir);
|
||||
|
||||
if (ret == CC_ERROR && pchar == '?' && oldpchar == ':')
|
||||
/*
|
||||
* break abort of failed search at last
|
||||
* non-failed
|
||||
*/
|
||||
ret = CC_NORM;
|
||||
|
||||
}
|
||||
if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
|
||||
/* restore on normal return or error exit */
|
||||
pchar = oldpchar;
|
||||
el->el_search.patlen = oldpatlen;
|
||||
if (el->el_history.eventno != ohisteventno) {
|
||||
el->el_history.eventno = ohisteventno;
|
||||
if (hist_get(el) == CC_ERROR)
|
||||
return (CC_ERROR);
|
||||
}
|
||||
el->el_line.cursor = ocursor;
|
||||
if (ret == CC_ERROR)
|
||||
re_refresh(el);
|
||||
}
|
||||
if (done || ret != CC_NORM)
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* cv_search():
|
||||
* Vi search.
|
||||
*/
|
||||
protected el_action_t
|
||||
cv_search(EditLine *el, int dir)
|
||||
{
|
||||
char ch;
|
||||
char tmpbuf[EL_BUFSIZ];
|
||||
int tmplen;
|
||||
|
||||
#ifdef ANCHOR
|
||||
tmpbuf[0] = '.';
|
||||
tmpbuf[1] = '*';
|
||||
#endif
|
||||
tmplen = LEN;
|
||||
|
||||
el->el_search.patdir = dir;
|
||||
|
||||
tmplen = c_gets(el, &tmpbuf[LEN],
|
||||
dir == ED_SEARCH_PREV_HISTORY ? "\n/" : "\n?" );
|
||||
if (tmplen == -1)
|
||||
return CC_REFRESH;
|
||||
|
||||
tmplen += LEN;
|
||||
ch = tmpbuf[tmplen];
|
||||
tmpbuf[tmplen] = '\0';
|
||||
|
||||
if (tmplen == LEN) {
|
||||
/*
|
||||
* Use the old pattern, but wild-card it.
|
||||
*/
|
||||
if (el->el_search.patlen == 0) {
|
||||
re_refresh(el);
|
||||
return (CC_ERROR);
|
||||
}
|
||||
#ifdef ANCHOR
|
||||
if (el->el_search.patbuf[0] != '.' &&
|
||||
el->el_search.patbuf[0] != '*') {
|
||||
(void) strncpy(tmpbuf, el->el_search.patbuf,
|
||||
sizeof(tmpbuf) - 1);
|
||||
el->el_search.patbuf[0] = '.';
|
||||
el->el_search.patbuf[1] = '*';
|
||||
(void) strncpy(&el->el_search.patbuf[2], tmpbuf,
|
||||
EL_BUFSIZ - 3);
|
||||
el->el_search.patlen++;
|
||||
el->el_search.patbuf[el->el_search.patlen++] = '.';
|
||||
el->el_search.patbuf[el->el_search.patlen++] = '*';
|
||||
el->el_search.patbuf[el->el_search.patlen] = '\0';
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#ifdef ANCHOR
|
||||
tmpbuf[tmplen++] = '.';
|
||||
tmpbuf[tmplen++] = '*';
|
||||
#endif
|
||||
tmpbuf[tmplen] = '\0';
|
||||
(void) strncpy(el->el_search.patbuf, tmpbuf, EL_BUFSIZ - 1);
|
||||
el->el_search.patlen = tmplen;
|
||||
}
|
||||
el->el_state.lastcmd = (el_action_t) dir; /* avoid c_setpat */
|
||||
el->el_line.cursor = el->el_line.lastchar = el->el_line.buffer;
|
||||
if ((dir == ED_SEARCH_PREV_HISTORY ? ed_search_prev_history(el, 0) :
|
||||
ed_search_next_history(el, 0)) == CC_ERROR) {
|
||||
re_refresh(el);
|
||||
return (CC_ERROR);
|
||||
}
|
||||
if (ch == 0033) {
|
||||
re_refresh(el);
|
||||
return ed_newline(el, 0);
|
||||
}
|
||||
return (CC_REFRESH);
|
||||
}
|
||||
|
||||
|
||||
/* ce_search_line():
|
||||
* Look for a pattern inside a line
|
||||
*/
|
||||
protected el_action_t
|
||||
ce_search_line(EditLine *el, int dir)
|
||||
{
|
||||
char *cp = el->el_line.cursor;
|
||||
char *pattern = el->el_search.patbuf;
|
||||
char oc, *ocp;
|
||||
#ifdef ANCHOR
|
||||
ocp = &pattern[1];
|
||||
oc = *ocp;
|
||||
*ocp = '^';
|
||||
#else
|
||||
ocp = pattern;
|
||||
oc = *ocp;
|
||||
#endif
|
||||
|
||||
if (dir == ED_SEARCH_PREV_HISTORY) {
|
||||
for (; cp >= el->el_line.buffer; cp--) {
|
||||
if (el_match(cp, ocp)) {
|
||||
*ocp = oc;
|
||||
el->el_line.cursor = cp;
|
||||
return (CC_NORM);
|
||||
}
|
||||
}
|
||||
*ocp = oc;
|
||||
return (CC_ERROR);
|
||||
} else {
|
||||
for (; *cp != '\0' && cp < el->el_line.limit; cp++) {
|
||||
if (el_match(cp, ocp)) {
|
||||
*ocp = oc;
|
||||
el->el_line.cursor = cp;
|
||||
return (CC_NORM);
|
||||
}
|
||||
}
|
||||
*ocp = oc;
|
||||
return (CC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* cv_repeat_srch():
|
||||
* Vi repeat search
|
||||
*/
|
||||
protected el_action_t
|
||||
cv_repeat_srch(EditLine *el, int c)
|
||||
{
|
||||
|
||||
#ifdef SDEBUG
|
||||
(void) fprintf(el->el_errfile, "dir %d patlen %d patbuf %s\n",
|
||||
c, el->el_search.patlen, el->el_search.patbuf);
|
||||
#endif
|
||||
|
||||
el->el_state.lastcmd = (el_action_t) c; /* Hack to stop c_setpat */
|
||||
el->el_line.lastchar = el->el_line.buffer;
|
||||
|
||||
switch (c) {
|
||||
case ED_SEARCH_NEXT_HISTORY:
|
||||
return (ed_search_next_history(el, 0));
|
||||
case ED_SEARCH_PREV_HISTORY:
|
||||
return (ed_search_prev_history(el, 0));
|
||||
default:
|
||||
return (CC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* cv_csearch():
|
||||
* Vi character search
|
||||
*/
|
||||
protected el_action_t
|
||||
cv_csearch(EditLine *el, int direction, int ch, int count, int tflag)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if (ch == 0)
|
||||
return CC_ERROR;
|
||||
|
||||
if (ch == -1) {
|
||||
char c;
|
||||
if (el_getc(el, &c) != 1)
|
||||
return ed_end_of_file(el, 0);
|
||||
ch = c;
|
||||
}
|
||||
|
||||
/* Save for ';' and ',' commands */
|
||||
el->el_search.chacha = ch;
|
||||
el->el_search.chadir = direction;
|
||||
el->el_search.chatflg = tflag;
|
||||
|
||||
cp = el->el_line.cursor;
|
||||
while (count--) {
|
||||
if (*cp == ch)
|
||||
cp += direction;
|
||||
for (;;cp += direction) {
|
||||
if (cp >= el->el_line.lastchar)
|
||||
return CC_ERROR;
|
||||
if (cp < el->el_line.buffer)
|
||||
return CC_ERROR;
|
||||
if (*cp == ch)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tflag)
|
||||
cp -= direction;
|
||||
|
||||
el->el_line.cursor = cp;
|
||||
|
||||
if (el->el_chared.c_vcmd.action != NOP) {
|
||||
if (direction > 0)
|
||||
el->el_line.cursor++;
|
||||
cv_delfini(el);
|
||||
return CC_REFRESH;
|
||||
}
|
||||
return CC_CURSOR;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)search.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: search.h,v 1.8 2003/10/18 23:27:36 christos Exp $
|
||||
* $FreeBSD: src/lib/libedit/search.h,v 1.4 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.search.h: Line and history searching utilities
|
||||
*/
|
||||
#ifndef _h_el_search
|
||||
#define _h_el_search
|
||||
|
||||
#include "histedit.h"
|
||||
|
||||
typedef struct el_search_t {
|
||||
char *patbuf; /* The pattern buffer */
|
||||
size_t patlen; /* Length of the pattern buffer */
|
||||
int patdir; /* Direction of the last search */
|
||||
int chadir; /* Character search direction */
|
||||
char chacha; /* Character we are looking for */
|
||||
char chatflg; /* 0 if f, 1 if t */
|
||||
} el_search_t;
|
||||
|
||||
|
||||
protected int el_match(const char *, const char *);
|
||||
protected int search_init(EditLine *);
|
||||
protected void search_end(EditLine *);
|
||||
protected int c_hmatch(EditLine *, const char *);
|
||||
protected void c_setpat(EditLine *);
|
||||
protected el_action_t ce_inc_search(EditLine *, int);
|
||||
protected el_action_t cv_search(EditLine *, int);
|
||||
protected el_action_t ce_search_line(EditLine *, int);
|
||||
protected el_action_t cv_repeat_srch(EditLine *, int);
|
||||
protected el_action_t cv_csearch(EditLine *, int, int, int, int);
|
||||
|
||||
#endif /* _h_el_search */
|
||||
@@ -0,0 +1,192 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: sig.c,v 1.11 2003/08/07 16:44:33 agc Exp $
|
||||
*/
|
||||
|
||||
#if !defined(lint) && !defined(SCCSID)
|
||||
static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif /* not lint && not SCCSID */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libedit/sig.c,v 1.7 2005/08/07 20:51:52 stefanf Exp $");
|
||||
|
||||
/*
|
||||
* sig.c: Signal handling stuff.
|
||||
* our policy is to trap all signals, set a good state
|
||||
* and pass the ball to our caller.
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include "el.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
private EditLine *sel = NULL;
|
||||
|
||||
private const int sighdl[] = {
|
||||
#define _DO(a) (a),
|
||||
ALLSIGS
|
||||
#undef _DO
|
||||
- 1
|
||||
};
|
||||
|
||||
private void sig_handler(int);
|
||||
|
||||
/* sig_handler():
|
||||
* This is the handler called for all signals
|
||||
* XXX: we cannot pass any data so we just store the old editline
|
||||
* state in a private variable
|
||||
*/
|
||||
private void
|
||||
sig_handler(int signo)
|
||||
{
|
||||
int i;
|
||||
sigset_t nset, oset;
|
||||
|
||||
(void) sigemptyset(&nset);
|
||||
(void) sigaddset(&nset, signo);
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
|
||||
switch (signo) {
|
||||
case SIGCONT:
|
||||
tty_rawmode(sel);
|
||||
if (ed_redisplay(sel, 0) == CC_REFRESH)
|
||||
re_refresh(sel);
|
||||
term__flush();
|
||||
break;
|
||||
|
||||
case SIGWINCH:
|
||||
el_resize(sel);
|
||||
break;
|
||||
|
||||
default:
|
||||
tty_cookedmode(sel);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; sighdl[i] != -1; i++)
|
||||
if (signo == sighdl[i])
|
||||
break;
|
||||
|
||||
(void) signal(signo, sel->el_signal[i]);
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
(void) kill(0, signo);
|
||||
}
|
||||
|
||||
|
||||
/* sig_init():
|
||||
* Initialize all signal stuff
|
||||
*/
|
||||
protected int
|
||||
sig_init(EditLine *el)
|
||||
{
|
||||
int i;
|
||||
sigset_t nset, oset;
|
||||
|
||||
(void) sigemptyset(&nset);
|
||||
#define _DO(a) (void) sigaddset(&nset, a);
|
||||
ALLSIGS
|
||||
#undef _DO
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
|
||||
#define SIGSIZE (sizeof(sighdl) / sizeof(sighdl[0]) * sizeof(el_signalhandler_t))
|
||||
|
||||
el->el_signal = (el_signalhandler_t *) el_malloc(SIGSIZE);
|
||||
if (el->el_signal == NULL)
|
||||
return (-1);
|
||||
for (i = 0; sighdl[i] != -1; i++)
|
||||
el->el_signal[i] = SIG_ERR;
|
||||
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* sig_end():
|
||||
* Clear all signal stuff
|
||||
*/
|
||||
protected void
|
||||
sig_end(EditLine *el)
|
||||
{
|
||||
|
||||
el_free((ptr_t) el->el_signal);
|
||||
el->el_signal = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* sig_set():
|
||||
* set all the signal handlers
|
||||
*/
|
||||
protected void
|
||||
sig_set(EditLine *el)
|
||||
{
|
||||
int i;
|
||||
sigset_t nset, oset;
|
||||
|
||||
(void) sigemptyset(&nset);
|
||||
#define _DO(a) (void) sigaddset(&nset, a);
|
||||
ALLSIGS
|
||||
#undef _DO
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
|
||||
for (i = 0; sighdl[i] != -1; i++) {
|
||||
el_signalhandler_t s;
|
||||
/* This could happen if we get interrupted */
|
||||
if ((s = signal(sighdl[i], sig_handler)) != sig_handler)
|
||||
el->el_signal[i] = s;
|
||||
}
|
||||
sel = el;
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* sig_clr():
|
||||
* clear all the signal handlers
|
||||
*/
|
||||
protected void
|
||||
sig_clr(EditLine *el)
|
||||
{
|
||||
int i;
|
||||
sigset_t nset, oset;
|
||||
|
||||
(void) sigemptyset(&nset);
|
||||
#define _DO(a) (void) sigaddset(&nset, a);
|
||||
ALLSIGS
|
||||
#undef _DO
|
||||
(void) sigprocmask(SIG_BLOCK, &nset, &oset);
|
||||
|
||||
for (i = 0; sighdl[i] != -1; i++)
|
||||
if (el->el_signal[i] != SIG_ERR)
|
||||
(void) signal(sighdl[i], el->el_signal[i]);
|
||||
|
||||
sel = NULL; /* we are going to die if the handler is
|
||||
* called */
|
||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)sig.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: sig.h,v 1.5 2003/08/07 16:44:33 agc Exp $
|
||||
* $FreeBSD: src/lib/libedit/sig.h,v 1.3 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.sig.h: Signal handling functions
|
||||
*/
|
||||
#ifndef _h_el_sig
|
||||
#define _h_el_sig
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "histedit.h"
|
||||
|
||||
/*
|
||||
* Define here all the signals we are going to handle
|
||||
* The _DO macro is used to iterate in the source code
|
||||
*/
|
||||
#define ALLSIGS \
|
||||
_DO(SIGINT) \
|
||||
_DO(SIGTSTP) \
|
||||
_DO(SIGSTOP) \
|
||||
_DO(SIGQUIT) \
|
||||
_DO(SIGHUP) \
|
||||
_DO(SIGTERM) \
|
||||
_DO(SIGCONT) \
|
||||
_DO(SIGWINCH)
|
||||
|
||||
typedef void (*el_signalhandler_t)(int);
|
||||
typedef el_signalhandler_t *el_signal_t;
|
||||
|
||||
protected void sig_end(EditLine*);
|
||||
protected int sig_init(EditLine*);
|
||||
protected void sig_set(EditLine*);
|
||||
protected void sig_clr(EditLine*);
|
||||
|
||||
#endif /* _h_el_sig */
|
||||
@@ -0,0 +1,109 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)sys.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: sys.h,v 1.9 2004/01/17 17:57:40 christos Exp $
|
||||
* $FreeBSD: src/lib/libedit/sys.h,v 1.6 2005/08/10 13:41:31 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* sys.h: Put all the stupid compiler and system dependencies here...
|
||||
*/
|
||||
#ifndef _h_sys
|
||||
#define _h_sys
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifndef public
|
||||
# define public /* Externally visible functions/variables */
|
||||
#endif
|
||||
|
||||
#ifndef private
|
||||
# define private static /* Always hidden internals */
|
||||
#endif
|
||||
|
||||
#ifndef protected
|
||||
# define protected /* Redefined from elsewhere to "static" */
|
||||
/* When we want to hide everything */
|
||||
#endif
|
||||
|
||||
#ifndef _PTR_T
|
||||
# define _PTR_T
|
||||
typedef void *ptr_t;
|
||||
#endif
|
||||
|
||||
#ifndef _IOCTL_T
|
||||
# define _IOCTL_T
|
||||
typedef void *ioctl_t;
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define REGEX /* Use POSIX.2 regular expression functions */
|
||||
#undef REGEXP /* Use UNIX V8 regular expression functions */
|
||||
|
||||
#ifdef notdef
|
||||
# undef REGEX
|
||||
# undef REGEXP
|
||||
# include <malloc.h>
|
||||
# ifdef __GNUC__
|
||||
/*
|
||||
* Broken hdrs.
|
||||
*/
|
||||
extern int tgetent(const char *bp, char *name);
|
||||
extern int tgetflag(const char *id);
|
||||
extern int tgetnum(const char *id);
|
||||
extern char *tgetstr(const char *id, char **area);
|
||||
extern char *tgoto(const char *cap, int col, int row);
|
||||
extern int tputs(const char *str, int affcnt, int (*putc)(int));
|
||||
extern char *getenv(const char *);
|
||||
extern int fprintf(FILE *, const char *, ...);
|
||||
extern int sigsetmask(int);
|
||||
extern int sigblock(int);
|
||||
extern int fputc(int, FILE *);
|
||||
extern int fgetc(FILE *);
|
||||
extern int fflush(FILE *);
|
||||
extern int tolower(int);
|
||||
extern int toupper(int);
|
||||
extern int errno, sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
extern void perror(const char *);
|
||||
# include <string.h>
|
||||
# define strerror(e) sys_errlist[e]
|
||||
# endif
|
||||
# ifdef SABER
|
||||
extern ptr_t memcpy(ptr_t, const ptr_t, size_t);
|
||||
extern ptr_t memset(ptr_t, int, size_t);
|
||||
# endif
|
||||
extern char *fgetline(FILE *, int *);
|
||||
#endif
|
||||
|
||||
#endif /* _h_sys */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,123 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)term.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: term.h,v 1.16 2005/03/15 00:10:40 christos Exp $
|
||||
* $FreeBSD: src/lib/libedit/term.h,v 1.6 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.term.h: Termcap header
|
||||
*/
|
||||
#ifndef _h_el_term
|
||||
#define _h_el_term
|
||||
|
||||
#include "histedit.h"
|
||||
|
||||
typedef struct { /* Symbolic function key bindings */
|
||||
const char *name; /* name of the key */
|
||||
int key; /* Index in termcap table */
|
||||
key_value_t fun; /* Function bound to it */
|
||||
int type; /* Type of function */
|
||||
} fkey_t;
|
||||
|
||||
typedef struct {
|
||||
const char *t_name; /* the terminal name */
|
||||
coord_t t_size; /* # lines and cols */
|
||||
int t_flags;
|
||||
#define TERM_CAN_INSERT 0x001 /* Has insert cap */
|
||||
#define TERM_CAN_DELETE 0x002 /* Has delete cap */
|
||||
#define TERM_CAN_CEOL 0x004 /* Has CEOL cap */
|
||||
#define TERM_CAN_TAB 0x008 /* Can use tabs */
|
||||
#define TERM_CAN_ME 0x010 /* Can turn all attrs. */
|
||||
#define TERM_CAN_UP 0x020 /* Can move up */
|
||||
#define TERM_HAS_META 0x040 /* Has a meta key */
|
||||
#define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */
|
||||
#define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */
|
||||
char *t_buf; /* Termcap buffer */
|
||||
int t_loc; /* location used */
|
||||
char **t_str; /* termcap strings */
|
||||
int *t_val; /* termcap values */
|
||||
char *t_cap; /* Termcap buffer */
|
||||
fkey_t *t_fkey; /* Array of keys */
|
||||
} el_term_t;
|
||||
|
||||
/*
|
||||
* fKey indexes
|
||||
*/
|
||||
#define A_K_DN 0
|
||||
#define A_K_UP 1
|
||||
#define A_K_LT 2
|
||||
#define A_K_RT 3
|
||||
#define A_K_HO 4
|
||||
#define A_K_EN 5
|
||||
#define A_K_NKEYS 6
|
||||
|
||||
protected void term_move_to_line(EditLine *, int);
|
||||
protected void term_move_to_char(EditLine *, int);
|
||||
protected void term_clear_EOL(EditLine *, int);
|
||||
protected void term_overwrite(EditLine *, const char *, int);
|
||||
protected void term_insertwrite(EditLine *, char *, int);
|
||||
protected void term_deletechars(EditLine *, int);
|
||||
protected void term_clear_screen(EditLine *);
|
||||
protected void term_beep(EditLine *);
|
||||
protected int term_change_size(EditLine *, int, int);
|
||||
protected int term_get_size(EditLine *, int *, int *);
|
||||
protected int term_init(EditLine *);
|
||||
protected void term_bind_arrow(EditLine *);
|
||||
protected void term_print_arrow(EditLine *, const char *);
|
||||
protected int term_clear_arrow(EditLine *, const char *);
|
||||
protected int term_set_arrow(EditLine *, const char *, key_value_t *, int);
|
||||
protected void term_end(EditLine *);
|
||||
protected void term_get(EditLine *, const char **);
|
||||
protected int term_set(EditLine *, const char *);
|
||||
protected int term_settc(EditLine *, int, const char **);
|
||||
protected int term_telltc(EditLine *, int, const char **);
|
||||
protected int term_echotc(EditLine *, int, const char **);
|
||||
protected int term__putc(int);
|
||||
protected void term__flush(void);
|
||||
|
||||
/*
|
||||
* Easy access macros
|
||||
*/
|
||||
#define EL_FLAGS (el)->el_term.t_flags
|
||||
|
||||
#define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT)
|
||||
#define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE)
|
||||
#define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL)
|
||||
#define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB)
|
||||
#define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME)
|
||||
#define EL_CAN_UP (EL_FLAGS & TERM_CAN_UP)
|
||||
#define EL_HAS_META (EL_FLAGS & TERM_HAS_META)
|
||||
#define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS)
|
||||
#define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS)
|
||||
|
||||
#endif /* _h_el_term */
|
||||
@@ -0,0 +1,439 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* $NetBSD: tokenizer.c,v 1.14 2003/12/05 13:37:48 lukem Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* tokenize.c: Bourne shell like tokenizer
|
||||
*/
|
||||
#include "sys.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "histedit.h"
|
||||
|
||||
typedef enum {
|
||||
Q_none, Q_single, Q_double, Q_one, Q_doubleone
|
||||
} quote_t;
|
||||
|
||||
#define IFS "\t \n"
|
||||
|
||||
#define TOK_KEEP 1
|
||||
#define TOK_EAT 2
|
||||
|
||||
#define WINCR 20
|
||||
#define AINCR 10
|
||||
|
||||
#define tok_strdup(a) strdup(a)
|
||||
#define tok_malloc(a) malloc(a)
|
||||
#define tok_free(a) free(a)
|
||||
#define tok_realloc(a, b) realloc(a, b)
|
||||
|
||||
|
||||
struct tokenizer {
|
||||
char *ifs; /* In field separator */
|
||||
int argc, amax; /* Current and maximum number of args */
|
||||
char **argv; /* Argument list */
|
||||
char *wptr, *wmax; /* Space and limit on the word buffer */
|
||||
char *wstart; /* Beginning of next word */
|
||||
char *wspace; /* Space of word buffer */
|
||||
quote_t quote; /* Quoting state */
|
||||
int flags; /* flags; */
|
||||
};
|
||||
|
||||
|
||||
private void tok_finish(Tokenizer *);
|
||||
|
||||
|
||||
/* tok_finish():
|
||||
* Finish a word in the tokenizer.
|
||||
*/
|
||||
private void
|
||||
tok_finish(Tokenizer *tok)
|
||||
{
|
||||
|
||||
*tok->wptr = '\0';
|
||||
if ((tok->flags & TOK_KEEP) || tok->wptr != tok->wstart) {
|
||||
tok->argv[tok->argc++] = tok->wstart;
|
||||
tok->argv[tok->argc] = NULL;
|
||||
tok->wstart = ++tok->wptr;
|
||||
}
|
||||
tok->flags &= ~TOK_KEEP;
|
||||
}
|
||||
|
||||
|
||||
/* tok_init():
|
||||
* Initialize the tokenizer
|
||||
*/
|
||||
public Tokenizer *
|
||||
tok_init(const char *ifs)
|
||||
{
|
||||
Tokenizer *tok = (Tokenizer *) tok_malloc(sizeof(Tokenizer));
|
||||
|
||||
if (tok == NULL)
|
||||
return NULL;
|
||||
tok->ifs = tok_strdup(ifs ? ifs : IFS);
|
||||
if (tok->ifs == NULL) {
|
||||
tok_free((ptr_t)tok);
|
||||
return NULL;
|
||||
}
|
||||
tok->argc = 0;
|
||||
tok->amax = AINCR;
|
||||
tok->argv = (char **) tok_malloc(sizeof(char *) * tok->amax);
|
||||
if (tok->argv == NULL) {
|
||||
tok_free((ptr_t)tok->ifs);
|
||||
tok_free((ptr_t)tok);
|
||||
return NULL;
|
||||
}
|
||||
tok->argv[0] = NULL;
|
||||
tok->wspace = (char *) tok_malloc(WINCR);
|
||||
if (tok->wspace == NULL) {
|
||||
tok_free((ptr_t)tok->argv);
|
||||
tok_free((ptr_t)tok->ifs);
|
||||
tok_free((ptr_t)tok);
|
||||
return NULL;
|
||||
}
|
||||
tok->wmax = tok->wspace + WINCR;
|
||||
tok->wstart = tok->wspace;
|
||||
tok->wptr = tok->wspace;
|
||||
tok->flags = 0;
|
||||
tok->quote = Q_none;
|
||||
|
||||
return (tok);
|
||||
}
|
||||
|
||||
|
||||
/* tok_reset():
|
||||
* Reset the tokenizer
|
||||
*/
|
||||
public void
|
||||
tok_reset(Tokenizer *tok)
|
||||
{
|
||||
|
||||
tok->argc = 0;
|
||||
tok->wstart = tok->wspace;
|
||||
tok->wptr = tok->wspace;
|
||||
tok->flags = 0;
|
||||
tok->quote = Q_none;
|
||||
}
|
||||
|
||||
|
||||
/* tok_end():
|
||||
* Clean up
|
||||
*/
|
||||
public void
|
||||
tok_end(Tokenizer *tok)
|
||||
{
|
||||
|
||||
tok_free((ptr_t) tok->ifs);
|
||||
tok_free((ptr_t) tok->wspace);
|
||||
tok_free((ptr_t) tok->argv);
|
||||
tok_free((ptr_t) tok);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* tok_line():
|
||||
* Bourne shell (sh(1)) like tokenizing
|
||||
* Arguments:
|
||||
* tok current tokenizer state (setup with tok_init())
|
||||
* line line to parse
|
||||
* Returns:
|
||||
* -1 Internal error
|
||||
* 3 Quoted return
|
||||
* 2 Unmatched double quote
|
||||
* 1 Unmatched single quote
|
||||
* 0 Ok
|
||||
* Modifies (if return value is 0):
|
||||
* argc number of arguments
|
||||
* argv argument array
|
||||
* cursorc if !NULL, argv element containing cursor
|
||||
* cursorv if !NULL, offset in argv[cursorc] of cursor
|
||||
*/
|
||||
public int
|
||||
tok_line(Tokenizer *tok, const LineInfo *line,
|
||||
int *argc, const char ***argv, int *cursorc, int *cursoro)
|
||||
{
|
||||
const char *ptr;
|
||||
int cc, co;
|
||||
|
||||
cc = co = -1;
|
||||
ptr = line->buffer;
|
||||
for (ptr = line->buffer; ;ptr++) {
|
||||
if (ptr >= line->lastchar)
|
||||
ptr = "";
|
||||
if (ptr == line->cursor) {
|
||||
cc = tok->argc;
|
||||
co = tok->wptr - tok->wstart;
|
||||
}
|
||||
switch (*ptr) {
|
||||
case '\'':
|
||||
tok->flags |= TOK_KEEP;
|
||||
tok->flags &= ~TOK_EAT;
|
||||
switch (tok->quote) {
|
||||
case Q_none:
|
||||
tok->quote = Q_single; /* Enter single quote
|
||||
* mode */
|
||||
break;
|
||||
|
||||
case Q_single: /* Exit single quote mode */
|
||||
tok->quote = Q_none;
|
||||
break;
|
||||
|
||||
case Q_one: /* Quote this ' */
|
||||
tok->quote = Q_none;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_double: /* Stay in double quote mode */
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_doubleone: /* Quote this ' */
|
||||
tok->quote = Q_double;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case '"':
|
||||
tok->flags &= ~TOK_EAT;
|
||||
tok->flags |= TOK_KEEP;
|
||||
switch (tok->quote) {
|
||||
case Q_none: /* Enter double quote mode */
|
||||
tok->quote = Q_double;
|
||||
break;
|
||||
|
||||
case Q_double: /* Exit double quote mode */
|
||||
tok->quote = Q_none;
|
||||
break;
|
||||
|
||||
case Q_one: /* Quote this " */
|
||||
tok->quote = Q_none;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_single: /* Stay in single quote mode */
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_doubleone: /* Quote this " */
|
||||
tok->quote = Q_double;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
tok->flags |= TOK_KEEP;
|
||||
tok->flags &= ~TOK_EAT;
|
||||
switch (tok->quote) {
|
||||
case Q_none: /* Quote next character */
|
||||
tok->quote = Q_one;
|
||||
break;
|
||||
|
||||
case Q_double: /* Quote next character */
|
||||
tok->quote = Q_doubleone;
|
||||
break;
|
||||
|
||||
case Q_one: /* Quote this, restore state */
|
||||
*tok->wptr++ = *ptr;
|
||||
tok->quote = Q_none;
|
||||
break;
|
||||
|
||||
case Q_single: /* Stay in single quote mode */
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_doubleone: /* Quote this \ */
|
||||
tok->quote = Q_double;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
tok->flags &= ~TOK_EAT;
|
||||
switch (tok->quote) {
|
||||
case Q_none:
|
||||
goto tok_line_outok;
|
||||
|
||||
case Q_single:
|
||||
case Q_double:
|
||||
*tok->wptr++ = *ptr; /* Add the return */
|
||||
break;
|
||||
|
||||
case Q_doubleone: /* Back to double, eat the '\n' */
|
||||
tok->flags |= TOK_EAT;
|
||||
tok->quote = Q_double;
|
||||
break;
|
||||
|
||||
case Q_one: /* No quote, more eat the '\n' */
|
||||
tok->flags |= TOK_EAT;
|
||||
tok->quote = Q_none;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
switch (tok->quote) {
|
||||
case Q_none:
|
||||
/* Finish word and return */
|
||||
if (tok->flags & TOK_EAT) {
|
||||
tok->flags &= ~TOK_EAT;
|
||||
return (3);
|
||||
}
|
||||
goto tok_line_outok;
|
||||
|
||||
case Q_single:
|
||||
return (1);
|
||||
|
||||
case Q_double:
|
||||
return (2);
|
||||
|
||||
case Q_doubleone:
|
||||
tok->quote = Q_double;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_one:
|
||||
tok->quote = Q_none;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
tok->flags &= ~TOK_EAT;
|
||||
switch (tok->quote) {
|
||||
case Q_none:
|
||||
if (strchr(tok->ifs, *ptr) != NULL)
|
||||
tok_finish(tok);
|
||||
else
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_single:
|
||||
case Q_double:
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
|
||||
case Q_doubleone:
|
||||
*tok->wptr++ = '\\';
|
||||
tok->quote = Q_double;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
case Q_one:
|
||||
tok->quote = Q_none;
|
||||
*tok->wptr++ = *ptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (-1);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (tok->wptr >= tok->wmax - 4) {
|
||||
size_t size = tok->wmax - tok->wspace + WINCR;
|
||||
char *s = (char *) tok_realloc(tok->wspace, size);
|
||||
if (s == NULL)
|
||||
return (-1);
|
||||
|
||||
if (s != tok->wspace) {
|
||||
int i;
|
||||
for (i = 0; i < tok->argc; i++) {
|
||||
tok->argv[i] =
|
||||
(tok->argv[i] - tok->wspace) + s;
|
||||
}
|
||||
tok->wptr = (tok->wptr - tok->wspace) + s;
|
||||
tok->wstart = (tok->wstart - tok->wspace) + s;
|
||||
tok->wspace = s;
|
||||
}
|
||||
tok->wmax = s + size;
|
||||
}
|
||||
if (tok->argc >= tok->amax - 4) {
|
||||
char **p;
|
||||
tok->amax += AINCR;
|
||||
p = (char **) tok_realloc(tok->argv,
|
||||
tok->amax * sizeof(char *));
|
||||
if (p == NULL)
|
||||
return (-1);
|
||||
tok->argv = p;
|
||||
}
|
||||
}
|
||||
tok_line_outok:
|
||||
if (cc == -1 && co == -1) {
|
||||
cc = tok->argc;
|
||||
co = tok->wptr - tok->wstart;
|
||||
}
|
||||
if (cursorc != NULL)
|
||||
*cursorc = cc;
|
||||
if (cursoro != NULL)
|
||||
*cursoro = co;
|
||||
tok_finish(tok);
|
||||
*argv = (const char **)tok->argv;
|
||||
*argc = tok->argc;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* tok_str():
|
||||
* Simpler version of tok_line, taking a NUL terminated line
|
||||
* and splitting into words, ignoring cursor state.
|
||||
*/
|
||||
public int
|
||||
tok_str(Tokenizer *tok, const char *line, int *argc, const char ***argv)
|
||||
{
|
||||
LineInfo li;
|
||||
|
||||
memset(&li, 0, sizeof(li));
|
||||
li.buffer = line;
|
||||
li.cursor = li.lastchar = strchr(line, '\0');
|
||||
return (tok_line(tok, &li, argc, argv, NULL, NULL));
|
||||
}
|
||||
+1251
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,480 @@
|
||||
/*-
|
||||
* 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.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*
|
||||
* @(#)tty.h 8.1 (Berkeley) 6/4/93
|
||||
* $NetBSD: tty.h,v 1.11 2005/06/01 11:37:52 lukem Exp $
|
||||
* $FreeBSD: src/lib/libedit/tty.h,v 1.5 2005/08/07 20:51:52 stefanf Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* el.tty.h: Local terminal header
|
||||
*/
|
||||
#ifndef _h_el_tty
|
||||
#define _h_el_tty
|
||||
|
||||
#include "histedit.h"
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Define our own since everyone gets it wrong! */
|
||||
#define CONTROL(A) ((A) & 037)
|
||||
|
||||
/*
|
||||
* Aix compatible names
|
||||
*/
|
||||
# if defined(VWERSE) && !defined(VWERASE)
|
||||
# define VWERASE VWERSE
|
||||
# endif /* VWERSE && !VWERASE */
|
||||
|
||||
# if defined(VDISCRD) && !defined(VDISCARD)
|
||||
# define VDISCARD VDISCRD
|
||||
# endif /* VDISCRD && !VDISCARD */
|
||||
|
||||
# if defined(VFLUSHO) && !defined(VDISCARD)
|
||||
# define VDISCARD VFLUSHO
|
||||
# endif /* VFLUSHO && VDISCARD */
|
||||
|
||||
# if defined(VSTRT) && !defined(VSTART)
|
||||
# define VSTART VSTRT
|
||||
# endif /* VSTRT && ! VSTART */
|
||||
|
||||
# if defined(VSTAT) && !defined(VSTATUS)
|
||||
# define VSTATUS VSTAT
|
||||
# endif /* VSTAT && ! VSTATUS */
|
||||
|
||||
# ifndef ONLRET
|
||||
# define ONLRET 0
|
||||
# endif /* ONLRET */
|
||||
|
||||
# ifndef TAB3
|
||||
# ifdef OXTABS
|
||||
# define TAB3 OXTABS
|
||||
# else
|
||||
# define TAB3 0
|
||||
# endif /* OXTABS */
|
||||
# endif /* !TAB3 */
|
||||
|
||||
# if defined(OXTABS) && !defined(XTABS)
|
||||
# define XTABS OXTABS
|
||||
# endif /* OXTABS && !XTABS */
|
||||
|
||||
# ifndef ONLCR
|
||||
# define ONLCR 0
|
||||
# endif /* ONLCR */
|
||||
|
||||
# ifndef IEXTEN
|
||||
# define IEXTEN 0
|
||||
# endif /* IEXTEN */
|
||||
|
||||
# ifndef ECHOCTL
|
||||
# define ECHOCTL 0
|
||||
# endif /* ECHOCTL */
|
||||
|
||||
# ifndef PARENB
|
||||
# define PARENB 0
|
||||
# endif /* PARENB */
|
||||
|
||||
# ifndef EXTPROC
|
||||
# define EXTPROC 0
|
||||
# endif /* EXTPROC */
|
||||
|
||||
# ifndef FLUSHO
|
||||
# define FLUSHO 0
|
||||
# endif /* FLUSHO */
|
||||
|
||||
|
||||
# if defined(VDISABLE) && !defined(_POSIX_VDISABLE)
|
||||
# define _POSIX_VDISABLE VDISABLE
|
||||
# endif /* VDISABLE && ! _POSIX_VDISABLE */
|
||||
|
||||
/*
|
||||
* Work around ISC's definition of IEXTEN which is
|
||||
* XCASE!
|
||||
*/
|
||||
# ifdef ISC
|
||||
# if defined(IEXTEN) && defined(XCASE)
|
||||
# if IEXTEN == XCASE
|
||||
# undef IEXTEN
|
||||
# define IEXTEN 0
|
||||
# endif /* IEXTEN == XCASE */
|
||||
# endif /* IEXTEN && XCASE */
|
||||
# if defined(IEXTEN) && !defined(XCASE)
|
||||
# define XCASE IEXTEN
|
||||
# undef IEXTEN
|
||||
# define IEXTEN 0
|
||||
# endif /* IEXTEN && !XCASE */
|
||||
# endif /* ISC */
|
||||
|
||||
/*
|
||||
* Work around convex weirdness where turning off IEXTEN makes us
|
||||
* lose all postprocessing!
|
||||
*/
|
||||
#if defined(convex) || defined(__convex__)
|
||||
# if defined(IEXTEN) && IEXTEN != 0
|
||||
# undef IEXTEN
|
||||
# define IEXTEN 0
|
||||
# endif /* IEXTEN != 0 */
|
||||
#endif /* convex || __convex__ */
|
||||
|
||||
/*
|
||||
* So that we don't lose job control.
|
||||
*/
|
||||
#ifdef __SVR4
|
||||
# undef CSWTCH
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_VDISABLE
|
||||
# define _POSIX_VDISABLE ((unsigned char) -1)
|
||||
#endif /* _POSIX_VDISABLE */
|
||||
|
||||
#if !defined(CREPRINT) && defined(CRPRNT)
|
||||
# define CREPRINT CRPRNT
|
||||
#endif /* !CREPRINT && CRPRNT */
|
||||
#if !defined(CDISCARD) && defined(CFLUSH)
|
||||
# define CDISCARD CFLUSH
|
||||
#endif /* !CDISCARD && CFLUSH */
|
||||
|
||||
#ifndef CINTR
|
||||
# define CINTR CONTROL('c')
|
||||
#endif /* CINTR */
|
||||
#ifndef CQUIT
|
||||
# define CQUIT 034 /* ^\ */
|
||||
#endif /* CQUIT */
|
||||
#ifndef CERASE
|
||||
# define CERASE 0177 /* ^? */
|
||||
#endif /* CERASE */
|
||||
#ifndef CKILL
|
||||
# define CKILL CONTROL('u')
|
||||
#endif /* CKILL */
|
||||
#ifndef CEOF
|
||||
# define CEOF CONTROL('d')
|
||||
#endif /* CEOF */
|
||||
#ifndef CEOL
|
||||
# define CEOL _POSIX_VDISABLE
|
||||
#endif /* CEOL */
|
||||
#ifndef CEOL2
|
||||
# define CEOL2 _POSIX_VDISABLE
|
||||
#endif /* CEOL2 */
|
||||
#ifndef CSWTCH
|
||||
# define CSWTCH _POSIX_VDISABLE
|
||||
#endif /* CSWTCH */
|
||||
#ifndef CDSWTCH
|
||||
# define CDSWTCH _POSIX_VDISABLE
|
||||
#endif /* CDSWTCH */
|
||||
#ifndef CERASE2
|
||||
# define CERASE2 _POSIX_VDISABLE
|
||||
#endif /* CERASE2 */
|
||||
#ifndef CSTART
|
||||
# define CSTART CONTROL('q')
|
||||
#endif /* CSTART */
|
||||
#ifndef CSTOP
|
||||
# define CSTOP CONTROL('s')
|
||||
#endif /* CSTOP */
|
||||
#ifndef CSUSP
|
||||
# define CSUSP CONTROL('z')
|
||||
#endif /* CSUSP */
|
||||
#ifndef CDSUSP
|
||||
# define CDSUSP CONTROL('y')
|
||||
#endif /* CDSUSP */
|
||||
|
||||
#ifdef hpux
|
||||
|
||||
# ifndef CREPRINT
|
||||
# define CREPRINT _POSIX_VDISABLE
|
||||
# endif /* CREPRINT */
|
||||
# ifndef CDISCARD
|
||||
# define CDISCARD _POSIX_VDISABLE
|
||||
# endif /* CDISCARD */
|
||||
# ifndef CLNEXT
|
||||
# define CLNEXT _POSIX_VDISABLE
|
||||
# endif /* CLNEXT */
|
||||
# ifndef CWERASE
|
||||
# define CWERASE _POSIX_VDISABLE
|
||||
# endif /* CWERASE */
|
||||
|
||||
#else /* !hpux */
|
||||
|
||||
# ifndef CREPRINT
|
||||
# define CREPRINT CONTROL('r')
|
||||
# endif /* CREPRINT */
|
||||
# ifndef CDISCARD
|
||||
# define CDISCARD CONTROL('o')
|
||||
# endif /* CDISCARD */
|
||||
# ifndef CLNEXT
|
||||
# define CLNEXT CONTROL('v')
|
||||
# endif /* CLNEXT */
|
||||
# ifndef CWERASE
|
||||
# define CWERASE CONTROL('w')
|
||||
# endif /* CWERASE */
|
||||
|
||||
#endif /* hpux */
|
||||
|
||||
#ifndef CSTATUS
|
||||
# define CSTATUS CONTROL('t')
|
||||
#endif /* CSTATUS */
|
||||
#ifndef CPAGE
|
||||
# define CPAGE ' '
|
||||
#endif /* CPAGE */
|
||||
#ifndef CPGOFF
|
||||
# define CPGOFF CONTROL('m')
|
||||
#endif /* CPGOFF */
|
||||
#ifndef CKILL2
|
||||
# define CKILL2 _POSIX_VDISABLE
|
||||
#endif /* CKILL2 */
|
||||
#ifndef CBRK
|
||||
# ifndef masscomp
|
||||
# define CBRK 0377
|
||||
# else
|
||||
# define CBRK '\0'
|
||||
# endif /* masscomp */
|
||||
#endif /* CBRK */
|
||||
#ifndef CMIN
|
||||
# define CMIN CEOF
|
||||
#endif /* CMIN */
|
||||
#ifndef CTIME
|
||||
# define CTIME CEOL
|
||||
#endif /* CTIME */
|
||||
|
||||
/*
|
||||
* Fix for sun inconsistency. On termio VSUSP and the rest of the
|
||||
* ttychars > NCC are defined. So we undefine them.
|
||||
*/
|
||||
#if defined(TERMIO) || defined(POSIX)
|
||||
# if defined(POSIX) && defined(NCCS)
|
||||
# define NUMCC NCCS
|
||||
# else
|
||||
# ifdef NCC
|
||||
# define NUMCC NCC
|
||||
# endif /* NCC */
|
||||
# endif /* POSIX && NCCS */
|
||||
# ifdef NUMCC
|
||||
# ifdef VINTR
|
||||
# if NUMCC <= VINTR
|
||||
# undef VINTR
|
||||
# endif /* NUMCC <= VINTR */
|
||||
# endif /* VINTR */
|
||||
# ifdef VQUIT
|
||||
# if NUMCC <= VQUIT
|
||||
# undef VQUIT
|
||||
# endif /* NUMCC <= VQUIT */
|
||||
# endif /* VQUIT */
|
||||
# ifdef VERASE
|
||||
# if NUMCC <= VERASE
|
||||
# undef VERASE
|
||||
# endif /* NUMCC <= VERASE */
|
||||
# endif /* VERASE */
|
||||
# ifdef VKILL
|
||||
# if NUMCC <= VKILL
|
||||
# undef VKILL
|
||||
# endif /* NUMCC <= VKILL */
|
||||
# endif /* VKILL */
|
||||
# ifdef VEOF
|
||||
# if NUMCC <= VEOF
|
||||
# undef VEOF
|
||||
# endif /* NUMCC <= VEOF */
|
||||
# endif /* VEOF */
|
||||
# ifdef VEOL
|
||||
# if NUMCC <= VEOL
|
||||
# undef VEOL
|
||||
# endif /* NUMCC <= VEOL */
|
||||
# endif /* VEOL */
|
||||
# ifdef VEOL2
|
||||
# if NUMCC <= VEOL2
|
||||
# undef VEOL2
|
||||
# endif /* NUMCC <= VEOL2 */
|
||||
# endif /* VEOL2 */
|
||||
# ifdef VSWTCH
|
||||
# if NUMCC <= VSWTCH
|
||||
# undef VSWTCH
|
||||
# endif /* NUMCC <= VSWTCH */
|
||||
# endif /* VSWTCH */
|
||||
# ifdef VDSWTCH
|
||||
# if NUMCC <= VDSWTCH
|
||||
# undef VDSWTCH
|
||||
# endif /* NUMCC <= VDSWTCH */
|
||||
# endif /* VDSWTCH */
|
||||
# ifdef VERASE2
|
||||
# if NUMCC <= VERASE2
|
||||
# undef VERASE2
|
||||
# endif /* NUMCC <= VERASE2 */
|
||||
# endif /* VERASE2 */
|
||||
# ifdef VSTART
|
||||
# if NUMCC <= VSTART
|
||||
# undef VSTART
|
||||
# endif /* NUMCC <= VSTART */
|
||||
# endif /* VSTART */
|
||||
# ifdef VSTOP
|
||||
# if NUMCC <= VSTOP
|
||||
# undef VSTOP
|
||||
# endif /* NUMCC <= VSTOP */
|
||||
# endif /* VSTOP */
|
||||
# ifdef VWERASE
|
||||
# if NUMCC <= VWERASE
|
||||
# undef VWERASE
|
||||
# endif /* NUMCC <= VWERASE */
|
||||
# endif /* VWERASE */
|
||||
# ifdef VSUSP
|
||||
# if NUMCC <= VSUSP
|
||||
# undef VSUSP
|
||||
# endif /* NUMCC <= VSUSP */
|
||||
# endif /* VSUSP */
|
||||
# ifdef VDSUSP
|
||||
# if NUMCC <= VDSUSP
|
||||
# undef VDSUSP
|
||||
# endif /* NUMCC <= VDSUSP */
|
||||
# endif /* VDSUSP */
|
||||
# ifdef VREPRINT
|
||||
# if NUMCC <= VREPRINT
|
||||
# undef VREPRINT
|
||||
# endif /* NUMCC <= VREPRINT */
|
||||
# endif /* VREPRINT */
|
||||
# ifdef VDISCARD
|
||||
# if NUMCC <= VDISCARD
|
||||
# undef VDISCARD
|
||||
# endif /* NUMCC <= VDISCARD */
|
||||
# endif /* VDISCARD */
|
||||
# ifdef VLNEXT
|
||||
# if NUMCC <= VLNEXT
|
||||
# undef VLNEXT
|
||||
# endif /* NUMCC <= VLNEXT */
|
||||
# endif /* VLNEXT */
|
||||
# ifdef VSTATUS
|
||||
# if NUMCC <= VSTATUS
|
||||
# undef VSTATUS
|
||||
# endif /* NUMCC <= VSTATUS */
|
||||
# endif /* VSTATUS */
|
||||
# ifdef VPAGE
|
||||
# if NUMCC <= VPAGE
|
||||
# undef VPAGE
|
||||
# endif /* NUMCC <= VPAGE */
|
||||
# endif /* VPAGE */
|
||||
# ifdef VPGOFF
|
||||
# if NUMCC <= VPGOFF
|
||||
# undef VPGOFF
|
||||
# endif /* NUMCC <= VPGOFF */
|
||||
# endif /* VPGOFF */
|
||||
# ifdef VKILL2
|
||||
# if NUMCC <= VKILL2
|
||||
# undef VKILL2
|
||||
# endif /* NUMCC <= VKILL2 */
|
||||
# endif /* VKILL2 */
|
||||
# ifdef VBRK
|
||||
# if NUMCC <= VBRK
|
||||
# undef VBRK
|
||||
# endif /* NUMCC <= VBRK */
|
||||
# endif /* VBRK */
|
||||
# ifdef VMIN
|
||||
# if NUMCC <= VMIN
|
||||
# undef VMIN
|
||||
# endif /* NUMCC <= VMIN */
|
||||
# endif /* VMIN */
|
||||
# ifdef VTIME
|
||||
# if NUMCC <= VTIME
|
||||
# undef VTIME
|
||||
# endif /* NUMCC <= VTIME */
|
||||
# endif /* VTIME */
|
||||
# endif /* NUMCC */
|
||||
#endif /* !POSIX */
|
||||
|
||||
#define C_INTR 0
|
||||
#define C_QUIT 1
|
||||
#define C_ERASE 2
|
||||
#define C_KILL 3
|
||||
#define C_EOF 4
|
||||
#define C_EOL 5
|
||||
#define C_EOL2 6
|
||||
#define C_SWTCH 7
|
||||
#define C_DSWTCH 8
|
||||
#define C_ERASE2 9
|
||||
#define C_START 10
|
||||
#define C_STOP 11
|
||||
#define C_WERASE 12
|
||||
#define C_SUSP 13
|
||||
#define C_DSUSP 14
|
||||
#define C_REPRINT 15
|
||||
#define C_DISCARD 16
|
||||
#define C_LNEXT 17
|
||||
#define C_STATUS 18
|
||||
#define C_PAGE 19
|
||||
#define C_PGOFF 20
|
||||
#define C_KILL2 21
|
||||
#define C_BRK 22
|
||||
#define C_MIN 23
|
||||
#define C_TIME 24
|
||||
#define C_NCC 25
|
||||
#define C_SH(A) (1 << (A))
|
||||
|
||||
/*
|
||||
* Terminal dependend data structures
|
||||
*/
|
||||
#define EX_IO 0 /* while we are executing */
|
||||
#define ED_IO 1 /* while we are editing */
|
||||
#define TS_IO 2 /* new mode from terminal */
|
||||
#define QU_IO 2 /* used only for quoted chars */
|
||||
#define NN_IO 3 /* The number of entries */
|
||||
|
||||
#define MD_INP 0
|
||||
#define MD_OUT 1
|
||||
#define MD_CTL 2
|
||||
#define MD_LIN 3
|
||||
#define MD_CHAR 4
|
||||
#define MD_NN 5
|
||||
|
||||
typedef struct {
|
||||
const char *t_name;
|
||||
unsigned int t_setmask;
|
||||
unsigned int t_clrmask;
|
||||
} ttyperm_t[NN_IO][MD_NN];
|
||||
|
||||
typedef unsigned char ttychar_t[NN_IO][C_NCC];
|
||||
|
||||
protected int tty_init(EditLine *);
|
||||
protected void tty_end(EditLine *);
|
||||
protected int tty_stty(EditLine *, int, const char **);
|
||||
protected int tty_rawmode(EditLine *);
|
||||
protected int tty_cookedmode(EditLine *);
|
||||
protected int tty_quotemode(EditLine *);
|
||||
protected int tty_noquotemode(EditLine *);
|
||||
protected void tty_bind_char(EditLine *, int);
|
||||
|
||||
typedef struct {
|
||||
ttyperm_t t_t;
|
||||
ttychar_t t_c;
|
||||
struct termios t_ex, t_ed, t_ts;
|
||||
int t_tabs;
|
||||
int t_eight;
|
||||
speed_t t_speed;
|
||||
int t_mode;
|
||||
unsigned char t_vdisable;
|
||||
} el_tty_t;
|
||||
|
||||
|
||||
#endif /* _h_el_tty */
|
||||
+1120
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
/* Automatically generated file, do not edit */
|
||||
#ifndef _h_vi_c
|
||||
#define _h_vi_c
|
||||
protected el_action_t vi_paste_next (EditLine *, int);
|
||||
protected el_action_t vi_paste_prev (EditLine *, int);
|
||||
protected el_action_t vi_prev_big_word (EditLine *, int);
|
||||
protected el_action_t vi_prev_word (EditLine *, int);
|
||||
protected el_action_t vi_next_big_word (EditLine *, int);
|
||||
protected el_action_t vi_next_word (EditLine *, int);
|
||||
protected el_action_t vi_change_case (EditLine *, int);
|
||||
protected el_action_t vi_change_meta (EditLine *, int);
|
||||
protected el_action_t vi_insert_at_bol (EditLine *, int);
|
||||
protected el_action_t vi_replace_char (EditLine *, int);
|
||||
protected el_action_t vi_replace_mode (EditLine *, int);
|
||||
protected el_action_t vi_substitute_char (EditLine *, int);
|
||||
protected el_action_t vi_substitute_line (EditLine *, int);
|
||||
protected el_action_t vi_change_to_eol (EditLine *, int);
|
||||
protected el_action_t vi_insert (EditLine *, int);
|
||||
protected el_action_t vi_add (EditLine *, int);
|
||||
protected el_action_t vi_add_at_eol (EditLine *, int);
|
||||
protected el_action_t vi_delete_meta (EditLine *, int);
|
||||
protected el_action_t vi_end_big_word (EditLine *, int);
|
||||
protected el_action_t vi_end_word (EditLine *, int);
|
||||
protected el_action_t vi_undo (EditLine *, int);
|
||||
protected el_action_t vi_command_mode (EditLine *, int);
|
||||
protected el_action_t vi_zero (EditLine *, int);
|
||||
protected el_action_t vi_delete_prev_char (EditLine *, int);
|
||||
protected el_action_t vi_list_or_eof (EditLine *, int);
|
||||
protected el_action_t vi_kill_line_prev (EditLine *, int);
|
||||
protected el_action_t vi_search_prev (EditLine *, int);
|
||||
protected el_action_t vi_search_next (EditLine *, int);
|
||||
protected el_action_t vi_repeat_search_next (EditLine *, int);
|
||||
protected el_action_t vi_repeat_search_prev (EditLine *, int);
|
||||
protected el_action_t vi_next_char (EditLine *, int);
|
||||
protected el_action_t vi_prev_char (EditLine *, int);
|
||||
protected el_action_t vi_to_next_char (EditLine *, int);
|
||||
protected el_action_t vi_to_prev_char (EditLine *, int);
|
||||
protected el_action_t vi_repeat_next_char (EditLine *, int);
|
||||
protected el_action_t vi_repeat_prev_char (EditLine *, int);
|
||||
protected el_action_t vi_match (EditLine *, int);
|
||||
protected el_action_t vi_undo_line (EditLine *, int);
|
||||
protected el_action_t vi_to_column (EditLine *, int);
|
||||
protected el_action_t vi_yank_end (EditLine *, int);
|
||||
protected el_action_t vi_yank (EditLine *, int);
|
||||
protected el_action_t vi_comment_out (EditLine *, int);
|
||||
protected el_action_t vi_alias (EditLine *, int);
|
||||
protected el_action_t vi_to_history_line (EditLine *, int);
|
||||
protected el_action_t vi_histedit (EditLine *, int);
|
||||
protected el_action_t vi_history_word (EditLine *, int);
|
||||
protected el_action_t vi_redo (EditLine *, int);
|
||||
#endif /* _h_vi_c */
|
||||
@@ -0,0 +1,13 @@
|
||||
SubDir HAIKU_TOP src libs util ;
|
||||
|
||||
SetSubDirSupportedPlatforms $(HAIKU_BONE_COMPATIBLE_PLATFORMS) ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
|
||||
|
||||
local defines = [ FDefines SCCSID=0 ] ;
|
||||
SubDirCcFlags $(defines) ;
|
||||
|
||||
StaticLibrary libutil.a :
|
||||
fparseln.c
|
||||
;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/4/93
|
||||
# $FreeBSD: src/lib/libutil/Makefile,v 1.63 2006/07/27 12:36:46 yar Exp $
|
||||
|
||||
SHLIBDIR?= /lib
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
LIB= util
|
||||
SHLIB_MAJOR= 6
|
||||
|
||||
SRCS= _secure_path.c auth.c fparseln.c humanize_number.c kld.c login.c \
|
||||
login_auth.c login_cap.c login_class.c login_crypt.c login_ok.c \
|
||||
login_times.c login_tty.c logout.c logwtmp.c \
|
||||
pidfile.c property.c pty.c pw_util.c realhostname.c stub.c \
|
||||
trimdomain.c uucplock.c
|
||||
INCS= libutil.h login_cap.h
|
||||
|
||||
CFLAGS+= -DLIBC_SCCS
|
||||
|
||||
.if ${MK_INET6_SUPPORT} != "no"
|
||||
CFLAGS+= -DINET6
|
||||
.endif
|
||||
|
||||
CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../libc/gen/
|
||||
|
||||
MAN+= kld.3 login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \
|
||||
login_cap.3 login_class.3 login_times.3 login_ok.3 \
|
||||
_secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
|
||||
realhostname_sa.3 trimdomain.3 fparseln.3 humanize_number.3 \
|
||||
pidfile.3
|
||||
MAN+= login.conf.5 auth.conf.5
|
||||
MLINKS+= kld.3 kld_isloaded.3 kld.3 kld_load.3
|
||||
MLINKS+= property.3 properties_read.3 property.3 properties_free.3
|
||||
MLINKS+= property.3 property_find.3
|
||||
MLINKS+= auth.3 auth_getval.3
|
||||
MLINKS+= pty.3 openpty.3 pty.3 forkpty.3
|
||||
MLINKS+=login_cap.3 login_getclassbyname.3 login_cap.3 login_close.3 \
|
||||
login_cap.3 login_getclass.3 login_cap.3 login_getuserclass.3 \
|
||||
login_cap.3 login_getcapstr.3 login_cap.3 login_getcaplist.3 \
|
||||
login_cap.3 login_getstyle.3 login_cap.3 login_getcaptime.3 \
|
||||
login_cap.3 login_getcapnum.3 login_cap.3 login_getcapsize.3 \
|
||||
login_cap.3 login_getcapbool.3 login_cap.3 login_getpath.3 \
|
||||
login_cap.3 login_getpwclass.3 login_cap.3 login_setcryptfmt.3
|
||||
MLINKS+=login_class.3 setusercontext.3 login_class.3 setclasscontext.3 \
|
||||
login_class.3 setclassenvironment.3 login_class.3 setclassresources.3
|
||||
MLINKS+=login_times.3 parse_lt.3 login_times.3 in_ltm.3 \
|
||||
login_times.3 in_lt.3 login_times.3 in_ltms.3 \
|
||||
login_times.3 in_lts.3
|
||||
MLINKS+=login_ok.3 auth_ttyok.3 login_ok.3 auth_hostok.3 \
|
||||
login_ok.3 auth_timeok.3
|
||||
MLINKS+=login_auth.3 auth_checknologin.3 login_auth.3 auth_cat.3
|
||||
MLINKS+=uucplock.3 uu_lock.3 uucplock.3 uu_lock_txfr.3 \
|
||||
uucplock.3 uu_unlock.3 uucplock.3 uu_lockerr.3
|
||||
MLINKS+=pidfile.3 pidfile_open.3 \
|
||||
pidfile.3 pidfile_write.3 \
|
||||
pidfile.3 pidfile_close.3 \
|
||||
pidfile.3 pidfile_remove.3
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
@@ -0,0 +1,75 @@
|
||||
.\" Copyright (c) 1997 David Nugent <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
.\" is permitted provided this notation is included.
|
||||
.\" 4. Absolutely no warranty of function or purpose is made by the author
|
||||
.\" David Nugent.
|
||||
.\" 5. Modifications may be freely made to this file providing the above
|
||||
.\" conditions are met.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/_secure_path.3,v 1.13 2005/01/20 09:17:07 ru Exp $
|
||||
.\"
|
||||
.Dd May 2, 1997
|
||||
.Os
|
||||
.Dt _SECURE_PATH 3
|
||||
.Sh NAME
|
||||
.Nm _secure_path
|
||||
.Nd determine if a file appears to be secure
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn _secure_path "const char *path" "uid_t uid" "gid_t gid"
|
||||
.Sh DESCRIPTION
|
||||
This function does some basic security checking on a given path.
|
||||
It is intended to be used by processes running with root privileges
|
||||
in order to decide whether or not to trust the contents of a given
|
||||
file.
|
||||
It uses a method often used to detect system compromise.
|
||||
.Pp
|
||||
A file is considered
|
||||
.Sq secure
|
||||
if it meets the following conditions:
|
||||
.Bl -enum
|
||||
.It
|
||||
The file exists, and is a regular file (not a symlink, device
|
||||
special or named pipe, etc.),
|
||||
.It
|
||||
Is not world writable.
|
||||
.It
|
||||
Is owned by the given uid or uid 0, if uid is not -1,
|
||||
.It
|
||||
Is not group writable or it has group ownership by the given
|
||||
gid, if gid is not -1.
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
This function returns zero if the file exists and may be
|
||||
considered secure, -2 if the file does not exist, and
|
||||
-1 otherwise to indicate a security failure.
|
||||
The
|
||||
.Xr syslog 3
|
||||
function is used to log any failure of this function, including the
|
||||
reason, at LOG_ERR priority.
|
||||
.Sh SEE ALSO
|
||||
.Xr lstat 2 ,
|
||||
.Xr syslog 3
|
||||
.Sh HISTORY
|
||||
Code from which this function was derived was contributed to the
|
||||
.Fx
|
||||
project by Berkeley Software Design, Inc.
|
||||
.Sh BUGS
|
||||
The checks carried out are rudimentary and no attempt is made
|
||||
to eliminate race conditions between use of this function and
|
||||
access to the file referenced.
|
||||
@@ -0,0 +1,74 @@
|
||||
/*-
|
||||
* Based on code copyright (c) 1995,1997 by
|
||||
* Berkeley Software Design, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* 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.
|
||||
* 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
* is permitted provided this notation is included.
|
||||
* 4. Absolutely no warranty of function or purpose is made by the authors.
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/_secure_path.c,v 1.9 2004/12/18 12:31:12 ru Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
#include <stddef.h>
|
||||
#include <syslog.h>
|
||||
|
||||
/*
|
||||
* Check for common security problems on a given path
|
||||
* It must be:
|
||||
* 1. A regular file, and exists
|
||||
* 2. Owned and writable only by root (or given owner)
|
||||
* 3. Group ownership is given group or is non-group writable
|
||||
*
|
||||
* Returns: -2 if file does not exist,
|
||||
* -1 if security test failure
|
||||
* 0 otherwise
|
||||
*/
|
||||
|
||||
int
|
||||
_secure_path(const char *path, uid_t uid, gid_t gid)
|
||||
{
|
||||
int r = -1;
|
||||
struct stat sb;
|
||||
const char *msg = NULL;
|
||||
|
||||
if (lstat(path, &sb) < 0) {
|
||||
if (errno == ENOENT) /* special case */
|
||||
r = -2; /* if it is just missing, skip the log entry */
|
||||
else
|
||||
msg = "%s: cannot stat %s: %m";
|
||||
}
|
||||
else if (!S_ISREG(sb.st_mode))
|
||||
msg = "%s: %s is not a regular file";
|
||||
else if (sb.st_mode & S_IWOTH)
|
||||
msg = "%s: %s is world writable";
|
||||
else if ((int)uid != -1 && sb.st_uid != uid && sb.st_uid != 0) {
|
||||
if (uid == 0)
|
||||
msg = "%s: %s is not owned by root";
|
||||
else
|
||||
msg = "%s: %s is not owned by uid %d";
|
||||
} else if ((int)gid != -1 && sb.st_gid != gid && (sb.st_mode & S_IWGRP))
|
||||
msg = "%s: %s is group writeable by non-authorised groups";
|
||||
else
|
||||
r = 0;
|
||||
if (msg != NULL)
|
||||
syslog(LOG_ERR, msg, "_secure_path", path, uid);
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1998 Jordan Hubbard
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/auth.3,v 1.10 2005/01/20 09:17:07 ru Exp $
|
||||
.\" "
|
||||
.Dd October 7, 1998
|
||||
.Os
|
||||
.Dt AUTH_GETVAL 3
|
||||
.Sh NAME
|
||||
.Nm auth_getval
|
||||
.Nd functions for reading values from
|
||||
.Pa /etc/auth.conf
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In libutil.h
|
||||
.Ft char *
|
||||
.Fn auth_getval "const char *name"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn auth_getval
|
||||
returns the value associated with the field called
|
||||
.Fa name
|
||||
or NULL if no such field is found or the auth file cannot be opened.
|
||||
.Sh FILES
|
||||
.Pa /etc/auth.conf
|
||||
contains the name=value pairs looked up by
|
||||
.Fn auth_getval .
|
||||
.Sh SEE ALSO
|
||||
.Xr properties_free 3 ,
|
||||
.Xr properties_read 3 ,
|
||||
.Xr property_find 3 ,
|
||||
.Xr auth.conf 5
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Simple authentication database handling code.
|
||||
*
|
||||
* Copyright (c) 1998
|
||||
* Jordan Hubbard. All rights reserved.
|
||||
*
|
||||
* 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,
|
||||
* verbatim and that no modifications are made prior to this
|
||||
* point in the file.
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR OR HIS PETS 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, LIFE 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/auth.c,v 1.6 2003/06/14 18:42:37 markm Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <libutil.h>
|
||||
#include <paths.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static properties P;
|
||||
|
||||
static int
|
||||
initauthconf(const char *path)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!P) {
|
||||
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
syslog(LOG_ERR, "initauthconf: unable to open file: %s", path);
|
||||
return 1;
|
||||
}
|
||||
P = properties_read(fd);
|
||||
close(fd);
|
||||
if (!P) {
|
||||
syslog(LOG_ERR, "initauthconf: unable to parse file: %s", path);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
auth_getval(const char *name)
|
||||
{
|
||||
if (!P && initauthconf(_PATH_AUTHCONF))
|
||||
return NULL;
|
||||
else
|
||||
return property_find(P, name);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
.\" Copyright (c) 1998 Jordan Hubbard
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/auth.conf.5,v 1.8 2005/01/21 12:07:46 ru Exp $
|
||||
.\"
|
||||
.Dd October 7, 1998
|
||||
.Dt AUTH.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm auth.conf
|
||||
.Nd authentication capability database
|
||||
.Sh SYNOPSIS
|
||||
.Pa /etc/auth.conf
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
contains various attributes important to the authentication
|
||||
code, most notably
|
||||
.Xr crypt 3
|
||||
for the time being.
|
||||
This documentation will be updated as the
|
||||
.Pa /etc/auth.conf
|
||||
file, which is very new, evolves.
|
||||
.Sh SEE ALSO
|
||||
.Xr auth_getval 3 ,
|
||||
.Xr crypt 3
|
||||
@@ -0,0 +1,158 @@
|
||||
.\" $NetBSD: fparseln.3,v 1.7 1999/07/02 15:49:12 simonb Exp $
|
||||
.\" $FreeBSD: src/lib/libutil/fparseln.3,v 1.11 2005/01/11 20:50:50 ru Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997 Christos Zoulas. All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by Christos Zoulas.
|
||||
.\" 4. The name of the author may not be used to endorse or promote products
|
||||
.\" derived from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
.\"
|
||||
.Dd December 1, 1997
|
||||
.Dt FPARSELN 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm fparseln
|
||||
.Nd return the next logical line from a stream
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In stdio.h
|
||||
.In libutil.h
|
||||
.Ft "char *"
|
||||
.Fo fparseln
|
||||
.Fa "FILE *stream" "size_t *len" "size_t *lineno"
|
||||
.Fa "const char delim[3]" "int flags"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn fparseln
|
||||
function
|
||||
returns a pointer to the next logical line from the stream referenced by
|
||||
.Fa stream .
|
||||
This string is
|
||||
.Dv NUL
|
||||
terminated and it is dynamically allocated on each invocation.
|
||||
It is the
|
||||
responsibility of the caller to free the pointer.
|
||||
.Pp
|
||||
By default, if a character is escaped, both it and the preceding escape
|
||||
character will be present in the returned string.
|
||||
Various
|
||||
.Fa flags
|
||||
alter this behaviour.
|
||||
.Pp
|
||||
The meaning of the arguments is as follows:
|
||||
.Bl -tag -width "lineno"
|
||||
.It Fa stream
|
||||
The stream to read from.
|
||||
.It Fa len
|
||||
If not
|
||||
.Dv NULL ,
|
||||
the length of the string is stored in the memory location to which it
|
||||
points.
|
||||
.It Fa lineno
|
||||
If not
|
||||
.Dv NULL ,
|
||||
the value of the memory location to which is pointed to, is incremented
|
||||
by the number of lines actually read from the file.
|
||||
.It Fa delim
|
||||
Contains the escape, continuation, and comment characters.
|
||||
If a character is
|
||||
.Dv NUL
|
||||
then processing for that character is disabled.
|
||||
If
|
||||
.Dv NULL ,
|
||||
all characters default to values specified below.
|
||||
The contents of
|
||||
.Fa delim
|
||||
is as follows:
|
||||
.Bl -tag -width "delim[0]"
|
||||
.It Fa delim[0]
|
||||
The escape character, which defaults to
|
||||
.Cm \e ,
|
||||
is used to remove any special meaning from the next character.
|
||||
.It Fa delim[1]
|
||||
The continuation character, which defaults to
|
||||
.Cm \e ,
|
||||
is used to indicate that the next line should be concatenated with the
|
||||
current one if this character is the last character on the current line
|
||||
and is not escaped.
|
||||
.It Fa delim[2]
|
||||
The comment character, which defaults to
|
||||
.Cm # ,
|
||||
if not escaped indicates the beginning of a comment that extends until the
|
||||
end of the current line.
|
||||
.El
|
||||
.It Fa flags
|
||||
If non-zero, alter the operation of
|
||||
.Fn fparseln .
|
||||
The various flags, which may be
|
||||
.Em or Ns -ed
|
||||
together, are:
|
||||
.Bl -tag -width "FPARSELN_UNESCCOMM"
|
||||
.It Dv FPARSELN_UNESCCOMM
|
||||
Remove escape preceding an escaped comment.
|
||||
.It Dv FPARSELN_UNESCCONT
|
||||
Remove escape preceding an escaped continuation.
|
||||
.It Dv FPARSELN_UNESCESC
|
||||
Remove escape preceding an escaped escape.
|
||||
.It Dv FPARSELN_UNESCREST
|
||||
Remove escape preceding any other character.
|
||||
.It Dv FPARSELN_UNESCALL
|
||||
All of the above.
|
||||
.El
|
||||
.Pp
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
Upon successful completion a pointer to the parsed line is returned;
|
||||
otherwise,
|
||||
.Dv NULL
|
||||
is returned.
|
||||
.Pp
|
||||
The
|
||||
.Fn fparseln
|
||||
function uses internally
|
||||
.Xr fgetln 3 ,
|
||||
so all error conditions that apply to
|
||||
.Xr fgetln 3 ,
|
||||
apply to
|
||||
.Fn fparseln .
|
||||
In addition
|
||||
.Fn fparseln
|
||||
may set
|
||||
.Va errno
|
||||
to
|
||||
.Er ENOMEM
|
||||
and return
|
||||
.Dv NULL
|
||||
if it runs out of memory.
|
||||
.Sh SEE ALSO
|
||||
.Xr fgetln 3
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn fparseln
|
||||
function first appeared in
|
||||
.Nx 1.4
|
||||
and
|
||||
.Fx 4.0 .
|
||||
@@ -0,0 +1,222 @@
|
||||
/* $NetBSD: fparseln.c,v 1.9 1999/09/20 04:48:06 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Christos Zoulas. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Christos Zoulas.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/fparseln.c,v 1.6 2003/10/18 10:04:16 markm Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <libutil.h>
|
||||
|
||||
static int isescaped(const char *, const char *, int);
|
||||
|
||||
/* isescaped():
|
||||
* Return true if the character in *p that belongs to a string
|
||||
* that starts in *sp, is escaped by the escape character esc.
|
||||
*/
|
||||
static int
|
||||
isescaped(const char *sp, const char *p, int esc)
|
||||
{
|
||||
const char *cp;
|
||||
size_t ne;
|
||||
|
||||
#if 0
|
||||
_DIAGASSERT(sp != NULL);
|
||||
_DIAGASSERT(p != NULL);
|
||||
#endif
|
||||
|
||||
/* No escape character */
|
||||
if (esc == '\0')
|
||||
return 1;
|
||||
|
||||
/* Count the number of escape characters that precede ours */
|
||||
for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
|
||||
continue;
|
||||
|
||||
/* Return true if odd number of escape characters */
|
||||
return (ne & 1) != 0;
|
||||
}
|
||||
|
||||
|
||||
/* fparseln():
|
||||
* Read a line from a file parsing continuations ending in \
|
||||
* and eliminating trailing newlines, or comments starting with
|
||||
* the comment char.
|
||||
*/
|
||||
char *
|
||||
fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
|
||||
{
|
||||
static const char dstr[3] = { '\\', '\\', '#' };
|
||||
|
||||
size_t s, len;
|
||||
char *buf;
|
||||
char *ptr, *cp;
|
||||
int cnt;
|
||||
char esc, con, nl, com;
|
||||
|
||||
#if 0
|
||||
_DIAGASSERT(fp != NULL);
|
||||
#endif
|
||||
|
||||
len = 0;
|
||||
buf = NULL;
|
||||
cnt = 1;
|
||||
|
||||
if (str == NULL)
|
||||
str = dstr;
|
||||
|
||||
esc = str[0];
|
||||
con = str[1];
|
||||
com = str[2];
|
||||
/*
|
||||
* XXX: it would be cool to be able to specify the newline character,
|
||||
* but unfortunately, fgetln does not let us
|
||||
*/
|
||||
nl = '\n';
|
||||
|
||||
while (cnt) {
|
||||
cnt = 0;
|
||||
|
||||
if (lineno)
|
||||
(*lineno)++;
|
||||
|
||||
if ((ptr = fgetln(fp, &s)) == NULL)
|
||||
break;
|
||||
|
||||
if (s && com) { /* Check and eliminate comments */
|
||||
for (cp = ptr; cp < ptr + s; cp++)
|
||||
if (*cp == com && !isescaped(ptr, cp, esc)) {
|
||||
s = cp - ptr;
|
||||
cnt = s == 0 && buf == NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s && nl) { /* Check and eliminate newlines */
|
||||
cp = &ptr[s - 1];
|
||||
|
||||
if (*cp == nl)
|
||||
s--; /* forget newline */
|
||||
}
|
||||
|
||||
if (s && con) { /* Check and eliminate continuations */
|
||||
cp = &ptr[s - 1];
|
||||
|
||||
if (*cp == con && !isescaped(ptr, cp, esc)) {
|
||||
s--; /* forget escape */
|
||||
cnt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == 0 && buf != NULL)
|
||||
continue;
|
||||
|
||||
if ((cp = realloc(buf, len + s + 1)) == NULL) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf = cp;
|
||||
|
||||
(void) memcpy(buf + len, ptr, s);
|
||||
len += s;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
|
||||
strchr(buf, esc) != NULL) {
|
||||
ptr = cp = buf;
|
||||
while (cp[0] != '\0') {
|
||||
int skipesc;
|
||||
|
||||
while (cp[0] != '\0' && cp[0] != esc)
|
||||
*ptr++ = *cp++;
|
||||
if (cp[0] == '\0' || cp[1] == '\0')
|
||||
break;
|
||||
|
||||
skipesc = 0;
|
||||
if (cp[1] == com)
|
||||
skipesc += (flags & FPARSELN_UNESCCOMM);
|
||||
if (cp[1] == con)
|
||||
skipesc += (flags & FPARSELN_UNESCCONT);
|
||||
if (cp[1] == esc)
|
||||
skipesc += (flags & FPARSELN_UNESCESC);
|
||||
if (cp[1] != com && cp[1] != con && cp[1] != esc)
|
||||
skipesc = (flags & FPARSELN_UNESCREST);
|
||||
|
||||
if (skipesc)
|
||||
cp++;
|
||||
else
|
||||
*ptr++ = *cp++;
|
||||
*ptr++ = *cp++;
|
||||
}
|
||||
*ptr = '\0';
|
||||
len = strlen(buf);
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *ptr;
|
||||
size_t size, line;
|
||||
|
||||
line = 0;
|
||||
while ((ptr = fparseln(stdin, &size, &line, NULL,
|
||||
FPARSELN_UNESCALL)) != NULL)
|
||||
printf("line %d (%d) |%s|\n", line, size, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
# This is a test
|
||||
line 1
|
||||
line 2 \
|
||||
line 3 # Comment
|
||||
line 4 \# Not comment \\\\
|
||||
|
||||
# And a comment \
|
||||
line 5 \\\
|
||||
line 6
|
||||
|
||||
*/
|
||||
|
||||
#endif /* TEST */
|
||||
@@ -0,0 +1,151 @@
|
||||
.\" $NetBSD: humanize_number.3,v 1.4 2003/04/16 13:34:37 wiz Exp $
|
||||
.\" $FreeBSD: src/lib/libutil/humanize_number.3,v 1.9 2006/07/15 20:53:36 imp Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to The NetBSD Foundation
|
||||
.\" by Luke Mewburn and by Tomas Svensson.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed by the NetBSD
|
||||
.\" Foundation, Inc. and its contributors.
|
||||
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
.\" contributors may be used to endorse or promote products derived
|
||||
.\" from this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
.\"
|
||||
.Dd May 25, 2004
|
||||
.Dt HUMANIZE_NUMBER 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm humanize_number
|
||||
.Nd format a number into a human readable form
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fo humanize_number
|
||||
.Fa "char *buf" "size_t len" "int64_t number" "const char *suffix"
|
||||
.Fa "int scale" "int flags"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn humanize_number
|
||||
function formats the signed 64-bit quantity given in
|
||||
.Fa number
|
||||
into
|
||||
.Fa buffer .
|
||||
A space and then
|
||||
.Fa suffix
|
||||
is appended to the end.
|
||||
The buffer pointed to by
|
||||
.Fa buffer
|
||||
must be at least
|
||||
.Fa len
|
||||
bytes long.
|
||||
.Pp
|
||||
If the formatted number (including
|
||||
.Fa suffix )
|
||||
would be too long to fit into
|
||||
.Fa buffer ,
|
||||
then divide
|
||||
.Fa number
|
||||
by 1024 until it will.
|
||||
In this case, prefix
|
||||
.Fa suffix
|
||||
with the appropriate SI designator.
|
||||
.Nm
|
||||
follows the traditional computer science conventions rather than the proposed
|
||||
SI power of two convention.
|
||||
.Pp
|
||||
The prefixes are:
|
||||
.Bl -column "Prefix" "Description" "1000000000000000000" -offset indent
|
||||
.It Sy "Prefix" Ta Sy "Description" Ta Sy "Multiplier" Ta Sy "Multiplier 1000x"
|
||||
.It Li k Ta No kilo Ta 1024 Ta 1000
|
||||
.It Li M Ta No mega Ta 1048576 Ta 1000000
|
||||
.It Li G Ta No giga Ta 1073741824 Ta 1000000000
|
||||
.It Li T Ta No tera Ta 1099511627776 Ta 1000000000000
|
||||
.It Li P Ta No peta Ta 1125899906842624 Ta 1000000000000000
|
||||
.It Li E Ta No exa Ta 1152921504606846976 Ta 1000000000000000000
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fa len
|
||||
argument must be at least 4 plus the length of
|
||||
.Fa suffix ,
|
||||
in order to ensure a useful result is generated into
|
||||
.Fa buffer .
|
||||
To use a specific prefix, specify this as
|
||||
.Fa scale
|
||||
(multiplier = 1024 ^ scale).
|
||||
This cannot be combined with any of the
|
||||
.Fa scale
|
||||
flags below.
|
||||
.Pp
|
||||
The following flags may be passed in
|
||||
.Fa scale :
|
||||
.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent
|
||||
.It Dv HN_AUTOSCALE
|
||||
Format the buffer using the lowest multiplier possible.
|
||||
.It Dv HN_GETSCALE
|
||||
Return the prefix index number (the number of times
|
||||
.Fa number
|
||||
must be divided to fit) instead of formatting it to the buffer.
|
||||
.El
|
||||
.Pp
|
||||
The following flags may be passed in
|
||||
.Fa flags :
|
||||
.Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent
|
||||
.It Dv HN_DECIMAL
|
||||
If the final result is less than 10, display it using one digit.
|
||||
.It Dv HN_NOSPACE
|
||||
Do not put a space between
|
||||
.Fa number
|
||||
and the prefix.
|
||||
.It Dv HN_B
|
||||
Use
|
||||
.Ql B
|
||||
(bytes) as prefix if the original result does not have a prefix.
|
||||
.It Dv HN_DIVISOR_1000
|
||||
Divide
|
||||
.Fa number
|
||||
with 1000 instead of 1024.
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn humanize_number
|
||||
function returns the number of characters stored in
|
||||
.Fa buffer
|
||||
(excluding the terminating
|
||||
.Dv NUL )
|
||||
upon success, or \-1 upon failure.
|
||||
If
|
||||
.Dv HN_GETSCALE
|
||||
is specified, the prefix index number will be returned instead.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn humanize_number
|
||||
function first appeared in
|
||||
.Nx 2.0 .
|
||||
@@ -0,0 +1,148 @@
|
||||
/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
|
||||
* NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/humanize_number.c,v 1.2 2004/09/25 14:11:34 pjd Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <libutil.h>
|
||||
|
||||
int
|
||||
humanize_number(char *buf, size_t len, int64_t bytes,
|
||||
const char *suffix, int scale, int flags)
|
||||
{
|
||||
const char *prefixes, *sep;
|
||||
int b, i, r, maxscale, s1, s2, sign;
|
||||
int64_t divisor, max;
|
||||
size_t baselen;
|
||||
|
||||
assert(buf != NULL);
|
||||
assert(suffix != NULL);
|
||||
assert(scale >= 0);
|
||||
|
||||
if (flags & HN_DIVISOR_1000) {
|
||||
/* SI for decimal multiplies */
|
||||
divisor = 1000;
|
||||
if (flags & HN_B)
|
||||
prefixes = "B\0k\0M\0G\0T\0P\0E";
|
||||
else
|
||||
prefixes = "\0\0k\0M\0G\0T\0P\0E";
|
||||
} else {
|
||||
/*
|
||||
* binary multiplies
|
||||
* XXX IEC 60027-2 recommends Ki, Mi, Gi...
|
||||
*/
|
||||
divisor = 1024;
|
||||
if (flags & HN_B)
|
||||
prefixes = "B\0K\0M\0G\0T\0P\0E";
|
||||
else
|
||||
prefixes = "\0\0K\0M\0G\0T\0P\0E";
|
||||
}
|
||||
|
||||
#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
|
||||
maxscale = 7;
|
||||
|
||||
if (scale >= maxscale &&
|
||||
(scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
|
||||
return (-1);
|
||||
|
||||
if (buf == NULL || suffix == NULL)
|
||||
return (-1);
|
||||
|
||||
if (len > 0)
|
||||
buf[0] = '\0';
|
||||
if (bytes < 0) {
|
||||
sign = -1;
|
||||
bytes *= -100;
|
||||
baselen = 3; /* sign, digit, prefix */
|
||||
} else {
|
||||
sign = 1;
|
||||
bytes *= 100;
|
||||
baselen = 2; /* digit, prefix */
|
||||
}
|
||||
if (flags & HN_NOSPACE)
|
||||
sep = "";
|
||||
else {
|
||||
sep = " ";
|
||||
baselen++;
|
||||
}
|
||||
baselen += strlen(suffix);
|
||||
|
||||
/* Check if enough room for `x y' + suffix + `\0' */
|
||||
if (len < baselen + 1)
|
||||
return (-1);
|
||||
|
||||
if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
|
||||
/* See if there is additional columns can be used. */
|
||||
for (max = 100, i = len - baselen; i-- > 0;)
|
||||
max *= 10;
|
||||
|
||||
for (i = 0; bytes >= max && i < maxscale; i++)
|
||||
bytes /= divisor;
|
||||
|
||||
if (scale & HN_GETSCALE)
|
||||
return (i);
|
||||
} else
|
||||
for (i = 0; i < scale && i < maxscale; i++)
|
||||
bytes /= divisor;
|
||||
|
||||
/* If a value <= 9.9 after rounding and ... */
|
||||
if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
|
||||
/* baselen + \0 + .N */
|
||||
if (len < baselen + 1 + 2)
|
||||
return (-1);
|
||||
b = ((int)bytes + 5) / 10;
|
||||
s1 = b / 10;
|
||||
s2 = b % 10;
|
||||
r = snprintf(buf, len, "%d%s%d%s%s%s",
|
||||
sign * s1, localeconv()->decimal_point, s2,
|
||||
sep, SCALE2PREFIX(i), suffix);
|
||||
} else
|
||||
r = snprintf(buf, len, "%lld%s%s%s",
|
||||
/* LONGLONG */
|
||||
(long long)(sign * ((bytes + 50) / 100)),
|
||||
sep, SCALE2PREFIX(i), suffix);
|
||||
|
||||
return (r);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2006 Dag-Erling Coïdan Smørgrav
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/kld.3,v 1.2 2006/07/12 14:33:52 maxim Exp $
|
||||
.\"
|
||||
.Dd February 18, 2006
|
||||
.Os
|
||||
.Dt KLD 3
|
||||
.Sh NAME
|
||||
.Nm kld_isloaded ,
|
||||
.Nm kld_load
|
||||
.Nd kld utility functions
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn kld_isloaded "const char *name"
|
||||
.Ft int
|
||||
.Fn kld_load "const char *name"
|
||||
.Sh DESCRIPTION
|
||||
These functions facilitate loading kernel modules from userland
|
||||
applications.
|
||||
.Pp
|
||||
The
|
||||
.Fn kld_isloaded
|
||||
function takes a name and returns a non-zero value if a module of that
|
||||
name is currently loaded.
|
||||
The name can be either the name of a module file
|
||||
.Po
|
||||
.Va cpufreq.ko
|
||||
.Pc ,
|
||||
the same name without the
|
||||
.Pa .ko
|
||||
extension
|
||||
.Po
|
||||
.Va cpufreq
|
||||
.Pc ,
|
||||
or the name of a module contained within that file
|
||||
.Po
|
||||
.Va cpu/ichss
|
||||
.Pc .
|
||||
Only the latter will return correct results if the module is compiled
|
||||
into the kernel.
|
||||
.Pp
|
||||
The
|
||||
.Fn kld_load
|
||||
function is a simple wrapper around the
|
||||
.Fn kldload
|
||||
function.
|
||||
It returns zero if and only if the corresponding
|
||||
.Fn kldload
|
||||
call succeeded or returned
|
||||
.Er EEXIST
|
||||
(signifying that the requested module was already loaded).
|
||||
.Sh SEE ALSO
|
||||
.Xr kldfirstmod 2 ,
|
||||
.Xr kldload 2 ,
|
||||
.Xr kldnext 2 ,
|
||||
.Xr kldstat 2 ,
|
||||
.Xr modfnext 2 ,
|
||||
.Xr modstat 2 ,
|
||||
.Xr kld 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn kld_isloaded
|
||||
and
|
||||
.Fn kld_load
|
||||
functions first appeared in
|
||||
.Fx 7.0 .
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Fn kld_isloaded
|
||||
and
|
||||
.Fn kld_load
|
||||
functions and this manual page were written by
|
||||
.An Dag-Erling Sm\(/orgrav Aq [email protected] .
|
||||
@@ -0,0 +1,76 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Dag-Erling Coïdan Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* in this position and unchanged.
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
*
|
||||
* $FreeBSD: src/lib/libutil/kld.c,v 1.2 2006/05/25 04:01:04 delphij Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
kld_isloaded(const char *name)
|
||||
{
|
||||
struct kld_file_stat fstat;
|
||||
struct module_stat mstat;
|
||||
const char *ko;
|
||||
int fid, mid;
|
||||
|
||||
for (fid = kldnext(0); fid > 0; fid = kldnext(fid)) {
|
||||
fstat.version = sizeof(fstat);
|
||||
if (kldstat(fid, &fstat) != 0)
|
||||
continue;
|
||||
/* check if the file name matches the supplied name */
|
||||
if (strcmp(fstat.name, name) == 0)
|
||||
return (1);
|
||||
/* strip .ko and try again */
|
||||
if ((ko = strstr(fstat.name, ".ko")) != NULL &&
|
||||
strlen(name) == (size_t)(ko - fstat.name) &&
|
||||
strncmp(fstat.name, name, ko - fstat.name) == 0)
|
||||
return (1);
|
||||
/* look for a matching module within the file */
|
||||
for (mid = kldfirstmod(fid); mid > 0; mid = modfnext(mid)) {
|
||||
mstat.version = sizeof(mstat);
|
||||
if (modstat(mid, &mstat) != 0)
|
||||
continue;
|
||||
if (strcmp(mstat.name, name) == 0)
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
kld_load(const char *name)
|
||||
{
|
||||
if (kldload(name) == -1 && errno != EEXIST)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1996 Joerg Wunsch
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login.3,v 1.10 2004/07/02 23:52:19 ru Exp $
|
||||
.\" "
|
||||
.Dd December 29, 1996
|
||||
.Os
|
||||
.Dt LOGIN 3
|
||||
.Sh NAME
|
||||
.Nm login
|
||||
.Nd "log a new login record to the utmp and wtmp files"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In utmp.h
|
||||
.In libutil.h
|
||||
.Ft void
|
||||
.Fn login "struct utmp *ut"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn login
|
||||
records the
|
||||
.Ar ut
|
||||
entry being passed into the appropriate slot of the
|
||||
.Xr utmp 5
|
||||
file,
|
||||
and appends it to the
|
||||
.Xr wtmp 5
|
||||
file.
|
||||
The calling process must have permission to write to both files.
|
||||
.Sh RETURN VALUES
|
||||
None.
|
||||
.Sh SEE ALSO
|
||||
.Xr logout 3 ,
|
||||
.Xr ttyslot 3 ,
|
||||
.Xr utmp 5 ,
|
||||
.Xr wtmp 5
|
||||
.Sh BUGS
|
||||
The interface provided by
|
||||
.Fn login
|
||||
is rather crude.
|
||||
The caller must know about the details of a
|
||||
.Va struct utmp .
|
||||
Some better abstraction needs to be worked out.
|
||||
@@ -0,0 +1,75 @@
|
||||
/*-
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login.c,v 1.11 2003/10/18 10:04:16 markm Exp $");
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)login.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libutil.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ttyent.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
void
|
||||
login(struct utmp *ut)
|
||||
{
|
||||
struct ttyent *ty;
|
||||
int fd;
|
||||
int tty;
|
||||
|
||||
setttyent();
|
||||
for (tty = 1; (ty = getttyent()) != NULL; ++tty)
|
||||
if (strcmp(ty->ty_name, ut->ut_line) == 0)
|
||||
break;
|
||||
endttyent();
|
||||
if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) {
|
||||
(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), L_SET);
|
||||
(void)write(fd, ut, sizeof(struct utmp));
|
||||
(void)close(fd);
|
||||
}
|
||||
if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
|
||||
(void)write(fd, ut, sizeof(struct utmp));
|
||||
(void)close(fd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
.\" Copyright (c) 1996 David Nugent <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
.\" is permitted provided this notation is included.
|
||||
.\" 4. Absolutely no warranty of function or purpose is made by the author
|
||||
.\" David Nugent.
|
||||
.\" 5. Modifications may be freely made to this file providing the above
|
||||
.\" conditions are met.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login.conf.5,v 1.57 2006/04/19 17:46:27 brueffer Exp $
|
||||
.\"
|
||||
.Dd April 19, 2006
|
||||
.Dt LOGIN.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm login.conf
|
||||
.Nd login class capability database
|
||||
.Sh SYNOPSIS
|
||||
.Pa /etc/login.conf ,
|
||||
.Pa ~/.login_conf
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
contains various attributes and capabilities of login classes.
|
||||
A login class (an optional annotation against each record in the user
|
||||
account database,
|
||||
.Pa /etc/master.passwd )
|
||||
determines session accounting, resource limits and user environment settings.
|
||||
It is used by various programs in the system to set up a user's login
|
||||
environment and to enforce policy, accounting and administrative restrictions.
|
||||
It also provides the means by which users are able to be
|
||||
authenticated to the system and the types of authentication available.
|
||||
Attributes in addition to the ones described here are available with
|
||||
third-party packages.
|
||||
.Pp
|
||||
A special record "default" in the system user class capability database
|
||||
.Pa /etc/login.conf
|
||||
is used automatically for any
|
||||
non-root user without a valid login class in
|
||||
.Pa /etc/master.passwd .
|
||||
A user with a uid of 0 without a valid login class will use the record
|
||||
"root" if it exists, or "default" if not.
|
||||
.Pp
|
||||
In
|
||||
.Fx ,
|
||||
users may individually create a file called
|
||||
.Pa .login_conf
|
||||
in their home directory using the same format, consisting of a single
|
||||
entry with a record id of "me".
|
||||
If present, this file is used by
|
||||
.Xr login 1
|
||||
to set user-defined environment settings which override those specified
|
||||
in the system login capabilities database.
|
||||
Only a subset of login capabilities may be overridden, typically those
|
||||
which do not involve authentication, resource limits and accounting.
|
||||
.Pp
|
||||
Records in a class capabilities database consist of a number of
|
||||
colon-separated fields.
|
||||
The first entry for each record gives one or more names that a record is
|
||||
to be known by, each separated by a '|' character.
|
||||
The first name is the most common abbreviation.
|
||||
The last name given should be a long name that is more descriptive
|
||||
of the capability entry, and all others are synonyms.
|
||||
All names but the last should be in lower case and contain no blanks;
|
||||
the last name may contain upper case characters and blanks for
|
||||
readability.
|
||||
.Pp
|
||||
The default
|
||||
.Pa /etc/login.conf
|
||||
shipped with
|
||||
.Fx
|
||||
is an out of the box configuration.
|
||||
Whenever changes to this, or
|
||||
the user's
|
||||
.Pa ~/.login_conf ,
|
||||
file are made, the modifications will not be picked up until
|
||||
.Xr cap_mkdb 1
|
||||
is used to compile the file into a database.
|
||||
This database file will have a
|
||||
.Pa .db
|
||||
extension and is accessed through
|
||||
.Xr cgetent 3 .
|
||||
See
|
||||
.Xr getcap 3
|
||||
for a more in-depth description of the format of a capability database.
|
||||
.Sh CAPABILITIES
|
||||
Fields within each record in the database follow the
|
||||
.Xr getcap 3
|
||||
conventions for boolean, type string
|
||||
.Ql \&=
|
||||
and type numeric
|
||||
.Ql \&# ,
|
||||
although type numeric is deprecated in favour of the string format and
|
||||
either form is accepted for a numeric datum.
|
||||
Values fall into the following categories:
|
||||
.Bl -tag -width "program"
|
||||
.It bool
|
||||
If the name is present, then the boolean value is true; otherwise, it is
|
||||
false
|
||||
.It file
|
||||
Path name to a data file
|
||||
.It program
|
||||
Path name to an executable file
|
||||
.It list
|
||||
A list of values (or pairs of values) separated by commas or spaces
|
||||
.It path
|
||||
A space or comma separated list of path names, following the usual csh
|
||||
conventions (leading tilde with and without username being expanded to
|
||||
home directories etc.)
|
||||
.It number
|
||||
A numeric value, either decimal (default), hexadecimal (with leading 0x),
|
||||
or octal (with a leading 0).
|
||||
With a numeric type, only one numeric value is allowed.
|
||||
Numeric types may also be specified in string format (i.e., the capability
|
||||
tag being delimited from the value by '=' instead of '#').
|
||||
Whichever method is used, then all records in the database must use the
|
||||
same method to allow values to be correctly overridden in interpolated
|
||||
records.
|
||||
.It size
|
||||
A number which expresses a size.
|
||||
The default interpretation of a value is the number of bytes, but a
|
||||
suffix may specify alternate units:
|
||||
.Bl -tag -offset indent -compact -width xxxx
|
||||
.It b
|
||||
explicitly selects 512-byte blocks
|
||||
.It k
|
||||
selects kilobytes (1024 bytes)
|
||||
.It m
|
||||
specifies a multiplier of 1 megabyte (1048576 bytes),
|
||||
.It g
|
||||
specifies units of gigabytes, and
|
||||
.It t
|
||||
represents terabytes.
|
||||
.El
|
||||
A size value is a numeric quantity and case of the suffix is not significant.
|
||||
Concatenated values are added together.
|
||||
.It time
|
||||
A period of time, by default in seconds.
|
||||
A prefix may specify a different unit:
|
||||
.Bl -tag -offset indent -compact -width xxxx
|
||||
.It y
|
||||
indicates the number of 365 day years,
|
||||
.It w
|
||||
indicates the number of weeks,
|
||||
.It d
|
||||
the number of days,
|
||||
.It h
|
||||
the number of hours,
|
||||
.It m
|
||||
the number of minutes, and
|
||||
.It s
|
||||
the number of seconds.
|
||||
.El
|
||||
Concatenated values are added together.
|
||||
For example, 2 hours and 40 minutes may be written either as
|
||||
9600s, 160m or 2h40m.
|
||||
.El
|
||||
.Pp
|
||||
The usual convention to interpolate capability entries using the special
|
||||
.Em tc=value
|
||||
notation may be used.
|
||||
.Sh RESOURCE LIMITS
|
||||
.Bl -column coredumpsize indent indent
|
||||
.It Sy "Name Type Notes Description
|
||||
.It "coredumpsize size Maximum coredump size limit.
|
||||
.It "cputime time CPU usage limit.
|
||||
.It "datasize size Maximum data size limit.
|
||||
.It "filesize size Maximum file size limit.
|
||||
.It "maxproc number Maximum number of processes.
|
||||
.It "memorylocked size Maximum locked in core memory size limit.
|
||||
.It "memoryuse size Maximum of core memory use size limit.
|
||||
.It "openfiles number Maximum number of open files per process.
|
||||
.It "sbsize size Maximum permitted socketbuffer size.
|
||||
.It "vmemoryuse size Maximum permitted total VM usage per process.
|
||||
.It "stacksize size Maximum stack size limit.
|
||||
.El
|
||||
.Pp
|
||||
These resource limit entries actually specify both the maximum
|
||||
and current limits (see
|
||||
.Xr getrlimit 2 ) .
|
||||
The current (soft) limit is the one normally used, although the user is
|
||||
permitted to increase the current limit to the maximum (hard) limit.
|
||||
The maximum and current limits may be specified individually by appending a
|
||||
-max or -cur to the capability name.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -column ignorenologin indent xbinxxusrxbin
|
||||
.It Sy "Name Type Notes Description
|
||||
.It "charset string Set $MM_CHARSET environment variable to the specified
|
||||
value.
|
||||
.It "hushlogin bool false Same as having a ~/.hushlogin file.
|
||||
.It "ignorenologin bool false Login not prevented by nologin.
|
||||
.It "ftp-chroot bool false Limit FTP access with
|
||||
.Xr chroot 2
|
||||
to the
|
||||
.Ev HOME
|
||||
directory of the user.
|
||||
See
|
||||
.Xr ftpd 8
|
||||
for details.
|
||||
.It "label string Default MAC policy; see
|
||||
.Xr maclabel 7 .
|
||||
.It "lang string Set $LANG environment variable to the specified value.
|
||||
.It "manpath path Default search path for manpages.
|
||||
.It "nocheckmail bool false Display mail status at login.
|
||||
.It "nologin file If the file exists it will be displayed and
|
||||
the login session will be terminated.
|
||||
.It "path path /bin /usr/bin Default search path.
|
||||
.It "priority number Initial priority (nice) level.
|
||||
.It "requirehome bool false Require a valid home directory to login.
|
||||
.It "setenv list A comma-separated list of environment variables and
|
||||
values to which they are to be set.
|
||||
.It "shell prog Session shell to execute rather than the
|
||||
shell specified in the passwd file.
|
||||
The SHELL environment variable will
|
||||
contain the shell specified in the password file.
|
||||
.It "term string Default terminal type if not able to determine
|
||||
from other means.
|
||||
.It "timezone string Default value of $TZ environment variable.
|
||||
.It "umask number 022 Initial umask. Should always have a leading 0 to
|
||||
ensure octal interpretation.
|
||||
.It "welcome file /etc/motd File containing welcome message.
|
||||
.El
|
||||
.Sh AUTHENTICATION
|
||||
.Bl -column passwd_prompt indent indent
|
||||
.It Sy "Name Type Notes Description
|
||||
.\" .It "approve program Program to approve login.
|
||||
.It "copyright file File containing additional copyright information
|
||||
.It "host.allow list List of remote host wildcards from which users in
|
||||
the class may access.
|
||||
.It "host.deny list List of remote host wildcards from which users
|
||||
in the class may not access.
|
||||
.It "login_prompt string The login prompt given by
|
||||
.Xr login 1
|
||||
.It "login-backoff number 3 The number of login attempts
|
||||
allowed before the backoff delay is inserted after each subsequent
|
||||
attempt.
|
||||
The backoff delay is the number of tries above
|
||||
.Em login-backoff
|
||||
multiplied by 5 seconds.
|
||||
.It "login-retries number 10 The number of login attempts
|
||||
allowed before the login fails.
|
||||
.It "passwd_format string md5 The encryption format that new or
|
||||
changed passwords will use.
|
||||
Valid values include "des", "md5" and "blf".
|
||||
NIS clients using a
|
||||
.No non- Ns Fx
|
||||
NIS server should probably use "des".
|
||||
.It "passwd_prompt string The password prompt presented by
|
||||
.Xr login 1
|
||||
.It "times.allow list List of time periods during which
|
||||
logins are allowed.
|
||||
.It "times.deny list List of time periods during which logins are
|
||||
disallowed.
|
||||
.It "ttys.allow list List of ttys and ttygroups which users
|
||||
in the class may use for access.
|
||||
.It "ttys.deny list List of ttys and ttygroups which users
|
||||
in the class may not use for access.
|
||||
.It "warnexpire time Advance notice for pending account expiry.
|
||||
.It "warnpassword time Advance notice for pending password expiry.
|
||||
.\".It "widepasswords bool false Use the wide password format. The wide password
|
||||
.\" format allows up to 128 significant characters in the password.
|
||||
.El
|
||||
.Pp
|
||||
These fields are intended to be used by
|
||||
.Xr passwd 1
|
||||
and other programs in the login authentication system.
|
||||
.Pp
|
||||
Capabilities that set environment variables are scanned for both
|
||||
.Ql \&~
|
||||
and
|
||||
.Ql \&$
|
||||
characters, which are substituted for a user's home directory and name
|
||||
respectively.
|
||||
To pass these characters literally into the environment variable, escape
|
||||
the character by preceding it with a backslash '\\'.
|
||||
.Pp
|
||||
The
|
||||
.Em host.allow
|
||||
and
|
||||
.Em host.deny
|
||||
entries are comma separated lists used for checking remote access to the system,
|
||||
and consist of a list of hostnames and/or IP addresses against which remote
|
||||
network logins are checked.
|
||||
Items in these lists may contain wildcards in the form used by shell programs
|
||||
for wildcard matching (See
|
||||
.Xr fnmatch 3
|
||||
for details on the implementation).
|
||||
The check on hosts is made against both the remote system's Internet address
|
||||
and hostname (if available).
|
||||
If both lists are empty or not specified, then logins from any remote host
|
||||
are allowed.
|
||||
If host.allow contains one or more hosts, then only remote systems matching
|
||||
any of the items in that list are allowed to log in.
|
||||
If host.deny contains one or more hosts, then a login from any matching hosts
|
||||
will be disallowed.
|
||||
.Pp
|
||||
The
|
||||
.Em times.allow
|
||||
and
|
||||
.Em times.deny
|
||||
entries consist of a comma-separated list of time periods during which the users
|
||||
in a class are allowed to be logged in.
|
||||
These are expressed as one or more day codes followed by a start and end times
|
||||
expressed in 24 hour format, separated by a hyphen or dash.
|
||||
For example, MoThSa0200-1300 translates to Monday, Thursday and Saturday between
|
||||
the hours of 2 am and 1 p.m..
|
||||
If both of these time lists are empty, users in the class are allowed access at
|
||||
any time.
|
||||
If
|
||||
.Em times.allow
|
||||
is specified, then logins are only allowed during the periods given.
|
||||
If
|
||||
.Em times.deny
|
||||
is specified, then logins are denied during the periods given, regardless of whether
|
||||
one of the periods specified in
|
||||
.Em times.allow
|
||||
applies.
|
||||
.Pp
|
||||
Note that
|
||||
.Xr login 1
|
||||
enforces only that the actual login falls within periods allowed by these entries.
|
||||
Further enforcement over the life of a session requires a separate daemon to
|
||||
monitor transitions from an allowed period to a non-allowed one.
|
||||
.Pp
|
||||
The
|
||||
.Em ttys.allow
|
||||
and
|
||||
.Em ttys.deny
|
||||
entries contain a comma-separated list of tty devices (without the /dev/ prefix)
|
||||
that a user in a class may use to access the system, and/or a list of ttygroups
|
||||
(See
|
||||
.Xr getttyent 3
|
||||
and
|
||||
.Xr ttys 5
|
||||
for information on ttygroups).
|
||||
If neither entry exists, then the choice of login device used by the user is
|
||||
unrestricted.
|
||||
If only
|
||||
.Em ttys.allow
|
||||
is specified, then the user is restricted only to ttys in the given
|
||||
group or device list.
|
||||
If only
|
||||
.Em ttys.deny
|
||||
is specified, then the user is prevented from using the specified devices or
|
||||
devices in the group.
|
||||
If both lists are given and are non-empty, the user is restricted to those
|
||||
devices allowed by ttys.allow that are not available by ttys.deny.
|
||||
.Pp
|
||||
The
|
||||
.Em minpasswordlen
|
||||
and
|
||||
.Em minpasswordcase
|
||||
facilities for enforcing restrictions on password quality, which used
|
||||
to be supported by
|
||||
.Nm ,
|
||||
have been superseded by the
|
||||
.Xr pam_passwdqc 8
|
||||
PAM module.
|
||||
.Sh RESERVED CAPABILITIES
|
||||
The following capabilities are reserved for the purposes indicated and
|
||||
may be supported by third-party software.
|
||||
They are not implemented in the base system.
|
||||
.Bl -column host.accounted indent indent
|
||||
.It Sy "Name Type Notes Description
|
||||
.It "accounted bool false Enable session time accounting for all users
|
||||
in this class.
|
||||
.It "autodelete time Time after expiry when account is auto-deleted.
|
||||
.It "bootfull bool false Enable 'boot only if ttygroup is full' strategy
|
||||
when terminating sessions.
|
||||
.It "daytime time Maximum login time per day.
|
||||
.It "expireperiod time Time for expiry allocation.
|
||||
.It "graceexpire time Grace days for expired account.
|
||||
.It "gracetime time Additional grace login time allowed.
|
||||
.It "host.accounted list List of remote host wildcards from which
|
||||
login sessions will be accounted.
|
||||
.It "host.exempt list List of remote host wildcards from which
|
||||
login session accounting is exempted.
|
||||
.It "idletime time Maximum idle time before logout.
|
||||
.It "minpasswordlen number 6 The minimum length a local
|
||||
password may be.
|
||||
.It "mixpasswordcase bool true Whether
|
||||
.Xr passwd 1
|
||||
will warn the user if an all lower case password is entered.
|
||||
.It "monthtime time Maximum login time per month.
|
||||
.It "passwordtime time Used by
|
||||
.Xr passwd 1
|
||||
to set next password expiry date.
|
||||
.It "refreshtime time New time allowed on account refresh.
|
||||
.It "refreshperiod str How often account time is refreshed.
|
||||
.It "sessiontime time Maximum login time per session.
|
||||
.It "sessionlimit number Maximum number of concurrent
|
||||
login sessions on ttys in any group.
|
||||
.It "ttys.accounted list List of ttys and ttygroups for which
|
||||
login accounting is active.
|
||||
.It "ttys.exempt list List of ttys and ttygroups for which login accounting
|
||||
is exempt.
|
||||
.It "warntime time Advance notice for pending out-of-time.
|
||||
.It "weektime time Maximum login time per week.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Em ttys.accounted
|
||||
and
|
||||
.Em ttys.exempt
|
||||
fields operate in a similar manner to
|
||||
.Em ttys.allow
|
||||
and
|
||||
.Em ttys.deny
|
||||
as explained
|
||||
above.
|
||||
Similarly with the
|
||||
.Em host.accounted
|
||||
and
|
||||
.Em host.exempt
|
||||
lists.
|
||||
.Sh SEE ALSO
|
||||
.Xr cap_mkdb 1 ,
|
||||
.Xr login 1 ,
|
||||
.Xr chroot 2 ,
|
||||
.Xr getcap 3 ,
|
||||
.Xr getttyent 3 ,
|
||||
.Xr login_cap 3 ,
|
||||
.Xr login_class 3 ,
|
||||
.Xr pam 3 ,
|
||||
.Xr passwd 5 ,
|
||||
.Xr ttys 5 ,
|
||||
.Xr ftpd 8 ,
|
||||
.Xr pam_passwdqc 8
|
||||
@@ -0,0 +1,72 @@
|
||||
.\" Copyright (c) 1995 David Nugent <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
.\" is permitted provided this notation is included.
|
||||
.\" 4. Absolutely no warranty of function or purpose is made by the author
|
||||
.\" David Nugent.
|
||||
.\" 5. Modifications may be freely made to this file providing the above
|
||||
.\" conditions are met.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login_auth.3,v 1.14 2001/10/01 16:09:18 ru Exp $
|
||||
.\"
|
||||
.Dd December 29, 1996
|
||||
.Os
|
||||
.Dt LOGIN_AUTH 3
|
||||
.Sh NAME
|
||||
.\" .Nm authenticate
|
||||
.\" .Nm auth_script
|
||||
.\" .Nm auth_env
|
||||
.\" .Nm auth_scan
|
||||
.\" .Nm auth_rmfiles
|
||||
.Nm auth_checknologin ,
|
||||
.Nm auth_cat
|
||||
.\" .Nm auth_ttyok
|
||||
.\" .Nm auth_hostok
|
||||
.\" .Nm auth_timesok
|
||||
.Nd "authentication style support library for login class capabilities database"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In login_cap.h
|
||||
.\" .Ft int
|
||||
.\". Fn authenticate "const char *name" "const char *classname" "const char *style" "const char *service"
|
||||
.\" .Ft int
|
||||
.\" .Fn auth_script "const char * path" ...
|
||||
.\" .Ft void
|
||||
.\" .Fn auth_env "void"
|
||||
.\" .Ft int
|
||||
.\" .Fn auth_scan "int ok"
|
||||
.\" .Ft void
|
||||
.\" .Fn auth_rmfiles "void"
|
||||
.Ft void
|
||||
.Fn auth_checknologin "login_cap_t *lc"
|
||||
.Ft int
|
||||
.Fn auth_cat "const char *file"
|
||||
.\" .Ft int
|
||||
.\" .Fn auth_ttyok "login_cap_t *lc" "const char *tty"
|
||||
.\" .Ft int
|
||||
.\" .Fn auth_hostok "login_cap_t *lc" "const char *hostname" "char const *ip"
|
||||
.\" .Ft int
|
||||
.\" .Fn auth_timesok "login_cap_t *lc" "time_t now"
|
||||
.Sh DESCRIPTION
|
||||
This set of functions support the login class authorisation style interface provided
|
||||
by
|
||||
.Xr login.conf 5 .
|
||||
.\" .Sh RETURN VALUES
|
||||
.Sh SEE ALSO
|
||||
.Xr getcap 3 ,
|
||||
.Xr login_cap 3 ,
|
||||
.Xr login_class 3 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr termcap 5
|
||||
@@ -0,0 +1,108 @@
|
||||
/*-
|
||||
* Copyright (c) 1996 by
|
||||
* Sean Eric Fagan <sef@kithrup.com>
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions copyright (c) 1995,1997 by
|
||||
* Berkeley Software Design, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* 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.
|
||||
* 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
* is permitted provided this notation is included.
|
||||
* 4. Absolutely no warranty of function or purpose is made by the authors.
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*
|
||||
* Low-level routines relating to the user capabilities database
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login_auth.c,v 1.14 2003/06/14 18:42:37 markm Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libutil.h>
|
||||
#include <limits.h>
|
||||
#include <login_cap.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/*
|
||||
* auth_checknologin()
|
||||
* Checks for the existance of a nologin file in the login_cap
|
||||
* capability <lc>. If there isn't one specified, then it checks
|
||||
* to see if this class should just ignore nologin files. Lastly,
|
||||
* it tries to print out the default nologin file, and, if such
|
||||
* exists, it exits.
|
||||
*/
|
||||
|
||||
void
|
||||
auth_checknologin(login_cap_t *lc)
|
||||
{
|
||||
const char *file;
|
||||
|
||||
/* Do we ignore a nologin file? */
|
||||
if (login_getcapbool(lc, "ignorenologin", 0))
|
||||
return;
|
||||
|
||||
/* Note that <file> will be "" if there is no nologin capability */
|
||||
if ((file = login_getcapstr(lc, "nologin", "", NULL)) == NULL)
|
||||
exit(1);
|
||||
|
||||
/*
|
||||
* *file is true IFF there was a "nologin" capability
|
||||
* Note that auth_cat() returns 1 only if the specified
|
||||
* file exists, and is readable. E.g., /.nologin exists.
|
||||
*/
|
||||
if ((*file && auth_cat(file)) || auth_cat(_PATH_NOLOGIN))
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_cat()
|
||||
* Checks for the readability of <file>; if it can be opened for
|
||||
* reading, it prints it out to stdout, and then exits. Otherwise,
|
||||
* it returns 0 (meaning no nologin file).
|
||||
*/
|
||||
|
||||
int
|
||||
auth_cat(const char *file)
|
||||
{
|
||||
int fd, count;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
if ((fd = open(file, O_RDONLY)) < 0)
|
||||
return 0;
|
||||
while ((count = read(fd, buf, sizeof(buf))) > 0)
|
||||
(void)write(fileno(stdout), buf, count);
|
||||
close(fd);
|
||||
sleep(5); /* wait an arbitrary time to drain */
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
.\" Copyright (c) 1995 David Nugent <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
.\" is permitted provided this notation is included.
|
||||
.\" 4. Absolutely no warranty of function or purpose is made by the author
|
||||
.\" David Nugent.
|
||||
.\" 5. Modifications may be freely made to this file providing the above
|
||||
.\" conditions are met.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login_cap.3,v 1.35 2005/11/24 11:29:11 ru Exp $
|
||||
.\"
|
||||
.Dd December 27, 1996
|
||||
.Os
|
||||
.Dt LOGIN_CAP 3
|
||||
.Sh NAME
|
||||
.Nm login_close ,
|
||||
.Nm login_getcapbool ,
|
||||
.Nm login_getcaplist ,
|
||||
.Nm login_getcapnum ,
|
||||
.Nm login_getcapstr ,
|
||||
.Nm login_getcapsize ,
|
||||
.Nm login_getcaptime ,
|
||||
.Nm login_getclass ,
|
||||
.Nm login_getclassbyname ,
|
||||
.Nm login_getpwclass ,
|
||||
.Nm login_getstyle ,
|
||||
.Nm login_getuserclass ,
|
||||
.Nm login_setcryptfmt
|
||||
.Nd "functions for accessing the login class capabilities database"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In login_cap.h
|
||||
.Ft void
|
||||
.Fn login_close "login_cap_t *lc"
|
||||
.Ft login_cap_t *
|
||||
.Fn login_getclassbyname "const char *nam" "const struct passwd *pwd"
|
||||
.Ft login_cap_t *
|
||||
.Fn login_getclass "const char *nam"
|
||||
.Ft login_cap_t *
|
||||
.Fn login_getpwclass "const struct passwd *pwd"
|
||||
.Ft login_cap_t *
|
||||
.Fn login_getuserclass "const struct passwd *pwd"
|
||||
.Ft "const char *"
|
||||
.Fn login_getcapstr "login_cap_t *lc" "const char *cap" "const char *def" "const char *error"
|
||||
.Ft "const char **"
|
||||
.Fn login_getcaplist "login_cap_t *lc" "const char *cap" "const char *chars"
|
||||
.Ft "const char *"
|
||||
.Fn login_getpath "login_cap_t *lc" "const char *cap" "const char *error"
|
||||
.Ft rlim_t
|
||||
.Fn login_getcaptime "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
|
||||
.Ft rlim_t
|
||||
.Fn login_getcapnum "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
|
||||
.Ft rlim_t
|
||||
.Fn login_getcapsize "login_cap_t *lc" "const char *cap" "rlim_t def" "rlim_t error"
|
||||
.Ft int
|
||||
.Fn login_getcapbool "login_cap_t *lc" "const char *cap" "int def"
|
||||
.Ft "const char *"
|
||||
.Fn login_getstyle "login_cap_t *lc" "const char *style" "const char *auth"
|
||||
.Ft const char *
|
||||
.Fn login_setcryptfmt "login_cap_t *lc" "const char *def" "const char *error"
|
||||
.Sh DESCRIPTION
|
||||
These functions represent a programming interface to the login
|
||||
classes database provided in
|
||||
.Xr login.conf 5 .
|
||||
This database contains capabilities, attributes and default environment
|
||||
and accounting settings for users and programs running as specific users,
|
||||
as determined by the login class field within entries in
|
||||
.Pa /etc/master.passwd .
|
||||
.Pp
|
||||
Entries in
|
||||
.Xr login.conf 5
|
||||
consist of colon
|
||||
.Ql \&:
|
||||
separated fields, the first field in each record being one or more
|
||||
identifiers for the record (which must be unique for the entire database),
|
||||
each separated by a '|', and may optionally include a description as
|
||||
the last 'name'.
|
||||
Remaining fields in the record consist of keyword/data pairs.
|
||||
Long lines may be continued with a backslash within empty entries,
|
||||
with the second and subsequent lines optionally indented for readability.
|
||||
This is similar to the format used in
|
||||
.Xr termcap 5 ,
|
||||
except that keywords are not limited to two significant characters,
|
||||
and are usually longer for improved readability.
|
||||
As with termcap entries, multiple records can be linked together
|
||||
(one record including another) using a field containing tc=<recordid>.
|
||||
The result is that the entire record referenced by <recordid> replaces
|
||||
the tc= field at the point at which it occurs.
|
||||
See
|
||||
.Xr getcap 3
|
||||
for further details on the format and use of a capabilities database.
|
||||
.Pp
|
||||
The
|
||||
.Nm login_cap
|
||||
interface provides a convenient means of retrieving login class
|
||||
records with all tc= references expanded.
|
||||
A program will typically call one of
|
||||
.Fn login_getclass ,
|
||||
.Fn login_getpwclass ,
|
||||
.Fn login_getuserclass
|
||||
or
|
||||
.Fn login_getclassbyname
|
||||
according to its requirements.
|
||||
Each of these functions returns a login capabilities structure,
|
||||
.Ft login_cap_t ,
|
||||
which may subsequently be used to interrogate the database for
|
||||
specific values using the rest of the API.
|
||||
Once the login_cap_t is of no further use, the
|
||||
.Fn login_close
|
||||
function should be called to free all resources used.
|
||||
.Pp
|
||||
The structure of login_cap_t is defined in login_cap.h, as:
|
||||
.Bd -literal -offset indent
|
||||
typedef struct {
|
||||
char *lc_class;
|
||||
char *lc_cap;
|
||||
char *lc_style;
|
||||
} login_cap_t;
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Ar lc_class
|
||||
member contains a pointer to the name of the login class
|
||||
retrieved.
|
||||
This may not necessarily be the same as the one requested,
|
||||
either directly via
|
||||
.Fn login_getclassbyname ,
|
||||
indirectly via a user's login record using
|
||||
.Fn login_getpwclass ,
|
||||
by class name using
|
||||
.Fn login_getclass ,
|
||||
or
|
||||
.Fn login_getuserclass .
|
||||
If the referenced user has no login class specified in
|
||||
.Pa /etc/master.passwd ,
|
||||
the class name is NULL or an empty string.
|
||||
If the class
|
||||
specified does not exist in the database, each of these
|
||||
functions will search for a record with an id of "default",
|
||||
with that name returned in the
|
||||
.Ar lc_class
|
||||
field.
|
||||
In addition, if the referenced user has a UID of 0 (normally,
|
||||
"root", although the user name is not considered) then
|
||||
.Fn login_getpwclass
|
||||
will search for a record with an id of "root" before it searches
|
||||
for the record with the id of "default".
|
||||
.Pp
|
||||
The
|
||||
.Ar lc_cap
|
||||
field is used internally by the library to contain the
|
||||
expanded login capabilities record.
|
||||
Programs with unusual requirements may wish to use this
|
||||
with the lower-level
|
||||
.Fn getcap
|
||||
style functions to access the record directly.
|
||||
.Pp
|
||||
The
|
||||
.Ar lc_style
|
||||
field is set by the
|
||||
.Fn login_getstyle
|
||||
function to the authorisation style, according to the requirements
|
||||
of the program handling a login itself.
|
||||
.Pp
|
||||
As noted above, the
|
||||
.Fn login_get*class
|
||||
functions return a login_cap_t object which is used to access
|
||||
the matching or default record in the capabilities database.
|
||||
The
|
||||
.Fn login_getclassbyname
|
||||
function accepts two arguments: the first one is the record identifier of the
|
||||
record to be retrieved, the second is an optional pointer to a
|
||||
.Li passwd
|
||||
structure.
|
||||
If the first
|
||||
.Ar name
|
||||
argument is NULL, an empty string, or a class that does not exist
|
||||
in the supplemental or system login class database, then the system
|
||||
.Em default
|
||||
record is returned instead.
|
||||
If the second
|
||||
.Ar pwd
|
||||
parameter is NULL, then only the system login class database is
|
||||
used.
|
||||
However,
|
||||
if the
|
||||
.Ar pwd
|
||||
parameter and the value of
|
||||
.Ar pwd->pw_dir
|
||||
are both not NULL, then the directory contained in
|
||||
.Ar pwd->pw_dir
|
||||
is searched for
|
||||
a login database file called ".login_conf", and capability records
|
||||
contained within it may override the system defaults.
|
||||
This scheme allows users to override some login settings from
|
||||
those in the system login class database by creating class records
|
||||
for their own private class with a record id of `me'.
|
||||
In the context of a
|
||||
.Em login ,
|
||||
it should be noted that some options cannot by overridden by
|
||||
users for two reasons; many options, such as resource settings
|
||||
and default process priorities, require root privileges
|
||||
in order to take effect, and other fields in the user's file are
|
||||
not be consulted at all during the early phases of login for
|
||||
security or administrative reasons.
|
||||
See
|
||||
.Xr login.conf 5
|
||||
for more information on which settings a user is able to override.
|
||||
Typically, these are limited purely to the user's default login
|
||||
environment which might otherwise have been overridden in shell
|
||||
startup scripts in any case.
|
||||
The user's
|
||||
.Pa .login_conf
|
||||
merely provides a convenient way for a user to set up their preferred
|
||||
login environment before the shell is invoked on login.
|
||||
Note that access to the
|
||||
.Pa /etc/login.conf
|
||||
and
|
||||
.Pa .login_conf
|
||||
files will only be performed subject to the security checks documented in
|
||||
.Xr _secure_path 3
|
||||
for the uids 0 and
|
||||
.Ar pwd->pw_uid
|
||||
respectively.
|
||||
.Pp
|
||||
If the specified record is NULL, empty or does not exist, and the
|
||||
system has no "default" record available to fall back to, there is a
|
||||
memory allocation error or for some reason
|
||||
.Xr cgetent 3
|
||||
is unable to access the login capabilities database, this function
|
||||
returns NULL.
|
||||
.Pp
|
||||
The functions
|
||||
.Fn login_getpwclass ,
|
||||
.Fn login_getclass
|
||||
and
|
||||
.Fn login_getuserclass
|
||||
retrieve the applicable login class record for the user's passwd
|
||||
entry or class name by calling
|
||||
.Fn login_getclassbyname .
|
||||
On failure, NULL is returned.
|
||||
The difference between these functions is that
|
||||
.Fn login_getuserclass
|
||||
includes the user's overriding
|
||||
.Pa .login_conf
|
||||
that exists in the user's home directory, and
|
||||
.Fn login_getpwclass
|
||||
and
|
||||
.Fn login_getclass
|
||||
restrict lookup only to the system login class database in
|
||||
.Pa /etc/login.conf .
|
||||
As explained earlier,
|
||||
.Fn login_getpwclass
|
||||
only differs from
|
||||
.Fn login_getclass
|
||||
in that it allows the default class for user 'root' as "root"
|
||||
if none has been specified in the password database.
|
||||
Otherwise, if the passwd pointer is NULL, or the user record
|
||||
has no login class, then the system "default" entry is retrieved.
|
||||
.Pp
|
||||
Once a program no longer wishes to use a login_cap_t object,
|
||||
.Fn login_close
|
||||
may be called to free all resources used by the login class.
|
||||
The
|
||||
.Fn login_close
|
||||
function may be passed a NULL pointer with no harmful side-effects.
|
||||
.Pp
|
||||
The remaining functions may be used to retrieve individual
|
||||
capability records.
|
||||
Each function takes a login_cap_t object as its first parameter,
|
||||
a capability tag as the second, and remaining parameters being
|
||||
default and error values that are returned if the capability is
|
||||
not found.
|
||||
The type of the additional parameters passed and returned depend
|
||||
on the
|
||||
.Em type
|
||||
of capability each deals with, be it a simple string, a list,
|
||||
a time value, a file or memory size value, a path (consisting of
|
||||
a colon-separated list of directories) or a boolean flag.
|
||||
The manpage for
|
||||
.Xr login.conf 5
|
||||
deals in specific tags and their type.
|
||||
.Pp
|
||||
Note that with all functions in this group, you should not call
|
||||
.Xr free 3
|
||||
on any pointers returned.
|
||||
Memory allocated during retrieval or processing of capability
|
||||
tags is automatically reused by subsequent calls to functions
|
||||
in this group, or deallocated on calling
|
||||
.Fn login_close .
|
||||
.Bl -tag -width "login_getcaplist()"
|
||||
.It Fn login_getcapstr
|
||||
This function returns a simple string capability.
|
||||
If the string is not found, then the value in
|
||||
.Ar def
|
||||
is returned as the default value, or if an error
|
||||
occurs, the value in the
|
||||
.Ar error
|
||||
parameter is returned.
|
||||
.It Fn login_getcaplist
|
||||
This function returns the value corresponding to the named
|
||||
capability tag as a list of values in a NULL terminated
|
||||
array.
|
||||
Within the login class database, some tags are of type
|
||||
.Em list ,
|
||||
which consist of one or more comma- or space separated
|
||||
values.
|
||||
Usually, this function is not called directly from an
|
||||
application, but is used indirectly via
|
||||
.Fn login_getstyle .
|
||||
.It Fn login_getpath
|
||||
This function returns a list of directories separated by colons
|
||||
.Ql \&: .
|
||||
Capability tags for which this function is called consist of a list of
|
||||
directories separated by spaces.
|
||||
.It Fn login_getcaptime
|
||||
This function returns a
|
||||
.Em time value
|
||||
associated with a particular capability tag with the value expressed
|
||||
in seconds (the default), minutes, hours, days, weeks or (365 day)
|
||||
years or any combination of these.
|
||||
A suffix determines the units used: S for seconds, M for minutes,
|
||||
H for hours, D for days, W for weeks and Y for 365 day years.
|
||||
Case of the units suffix is ignored.
|
||||
.Pp
|
||||
Time values are normally used for setting resource, accounting and
|
||||
session limits.
|
||||
If supported by the operating system and compiler (which is true of
|
||||
.Fx ) ,
|
||||
the value returned is a quad (long long), of type
|
||||
.Em rlim_t .
|
||||
A value "inf" or "infinity" may be used to express an infinite
|
||||
value, in which case RLIM_INFINITY is returned.
|
||||
.It Fn login_getcapnum
|
||||
This function returns a numeric value for a tag, expressed either as
|
||||
tag=<value> or the standard
|
||||
.Fn cgetnum
|
||||
format tag#<value>.
|
||||
The first format should be used in preference to the second, the
|
||||
second format is provided for compatibility and consistency with the
|
||||
.Xr getcap 3
|
||||
database format where numeric types use the
|
||||
.Ql \&#
|
||||
as the delimiter for numeric values.
|
||||
If in the first format, then the value given may be "inf" or
|
||||
"infinity" which results in a return value of RLIM_INFINITY.
|
||||
If the given capability tag cannot be found, the
|
||||
.Ar def
|
||||
parameter is returned, and if an error occurs, the
|
||||
.Ar error
|
||||
parameter is returned.
|
||||
.It Fn login_getcapsize
|
||||
.Fn login_getcapsize
|
||||
returns a value representing a size (typically, file or memory)
|
||||
which may be expressed as bytes (the default), 512 byte blocks,
|
||||
kilobytes, megabytes, gigabytes, and on systems that support the
|
||||
.Ar long long
|
||||
type, terabytes.
|
||||
The suffix used determines the units, and multiple values and
|
||||
units may be used in combination (e.g.\& 1m500k = 1.5 megabytes).
|
||||
A value with no suffix is interpreted as bytes, B as 512-byte
|
||||
blocks, K as kilobytes, M as megabytes, G as gigabytes and T as
|
||||
terabytes.
|
||||
Case is ignored.
|
||||
The error value is returned if there is a login capabilities database
|
||||
error, if an invalid suffix is used, or if a numeric value cannot be
|
||||
interpreted.
|
||||
.It Fn login_getcapbool
|
||||
This function returns a boolean value tied to a particular flag.
|
||||
It returns 0 if the given capability tag is not present or is
|
||||
negated by the presence of a "tag@" (See
|
||||
.Xr getcap 3
|
||||
for more information on boolean flags), and returns 1 if the tag
|
||||
is found.
|
||||
.It Fn login_getstyle
|
||||
This function is used by the login authorisation system to determine
|
||||
the style of login available in a particular case.
|
||||
The function accepts three parameters, the login_cap entry itself and
|
||||
two optional parameters, and authorisation type 'auth' and 'style', and
|
||||
applies these to determine the authorisation style that best suites
|
||||
these rules.
|
||||
.Bl -bullet
|
||||
.It
|
||||
If 'auth' is neither NULL nor an empty string, look for a tag of type
|
||||
"auth-<auth>" in the capability record.
|
||||
If not present, then look for the default tag "auth=".
|
||||
.It
|
||||
If no valid authorisation list was found from the previous step, then
|
||||
default to "passwd" as the authorisation list.
|
||||
.It
|
||||
If 'style' is not NULL or empty, look for it in the list of authorisation
|
||||
methods found from the previous step.
|
||||
If 'style' is NULL or an empty string, then default to "passwd"
|
||||
authorisation.
|
||||
.It
|
||||
If 'style' is found in the chosen list of authorisation methods, then
|
||||
return that, otherwise return NULL.
|
||||
.El
|
||||
.Pp
|
||||
This scheme allows the administrator to determine the types of
|
||||
authorisation methods accepted by the system, depending on the
|
||||
means by which the access occurs.
|
||||
For example, the administrator may require skey or kerberos as
|
||||
the authentication method used for access to the system via the
|
||||
network, and standard methods via direct dialup or console
|
||||
logins, significantly reducing the risk of password discovery
|
||||
by "snooping" network packets.
|
||||
.It Fn login_setcryptfmt
|
||||
The
|
||||
.Fn login_setcryptfmt
|
||||
function is used to set the
|
||||
.Xr crypt 3
|
||||
format using the
|
||||
.Ql passwd_format
|
||||
configuration entry.
|
||||
If no entry is found,
|
||||
.Fa def
|
||||
is taken to be used as the fallback.
|
||||
If calling
|
||||
.Xr crypt_set_format 3
|
||||
on the specifier fails,
|
||||
.Fa error
|
||||
is returned to indicate this.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr crypt 3 ,
|
||||
.Xr getcap 3 ,
|
||||
.Xr login_class 3 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr termcap 5
|
||||
@@ -0,0 +1,808 @@
|
||||
/*-
|
||||
* Copyright (c) 1996 by
|
||||
* Sean Eric Fagan <sef@kithrup.com>
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions copyright (c) 1995,1997
|
||||
* Berkeley Software Design, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* 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.
|
||||
* 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
* is permitted provided this notation is included.
|
||||
* 4. Absolutely no warranty of function or purpose is made by the authors.
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*
|
||||
* Low-level routines relating to the user capabilities database
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login_cap.c,v 1.33 2005/04/22 23:11:57 trhodes Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/param.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libutil.h>
|
||||
#include <login_cap.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* allocstr()
|
||||
* Manage a single static pointer for handling a local char* buffer,
|
||||
* resizing as necessary to contain the string.
|
||||
*
|
||||
* allocarray()
|
||||
* Manage a static array for handling a group of strings, resizing
|
||||
* when necessary.
|
||||
*/
|
||||
|
||||
static int lc_object_count = 0;
|
||||
|
||||
static size_t internal_stringsz = 0;
|
||||
static char * internal_string = NULL;
|
||||
static size_t internal_arraysz = 0;
|
||||
static const char ** internal_array = NULL;
|
||||
|
||||
static char *
|
||||
allocstr(const char *str)
|
||||
{
|
||||
char *p;
|
||||
|
||||
size_t sz = strlen(str) + 1; /* realloc() only if necessary */
|
||||
if (sz <= internal_stringsz)
|
||||
p = strcpy(internal_string, str);
|
||||
else if ((p = realloc(internal_string, sz)) != NULL) {
|
||||
internal_stringsz = sz;
|
||||
internal_string = strcpy(p, str);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static const char **
|
||||
allocarray(size_t sz)
|
||||
{
|
||||
static const char **p;
|
||||
|
||||
if (sz <= internal_arraysz)
|
||||
p = internal_array;
|
||||
else if ((p = realloc(internal_array, sz * sizeof(char*))) != NULL) {
|
||||
internal_arraysz = sz;
|
||||
internal_array = p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* arrayize()
|
||||
* Turn a simple string <str> separated by any of
|
||||
* the set of <chars> into an array. The last element
|
||||
* of the array will be NULL, as is proper.
|
||||
* Free using freearraystr()
|
||||
*/
|
||||
|
||||
static const char **
|
||||
arrayize(const char *str, const char *chars, int *size)
|
||||
{
|
||||
int i;
|
||||
char *ptr;
|
||||
const char *cptr;
|
||||
const char **res = NULL;
|
||||
|
||||
/* count the sub-strings */
|
||||
for (i = 0, cptr = str; *cptr; i++) {
|
||||
int count = strcspn(cptr, chars);
|
||||
cptr += count;
|
||||
if (*cptr)
|
||||
++cptr;
|
||||
}
|
||||
|
||||
/* alloc the array */
|
||||
if ((ptr = allocstr(str)) != NULL) {
|
||||
if ((res = allocarray(++i)) == NULL)
|
||||
free((void *)(uintptr_t)(const void *)str);
|
||||
else {
|
||||
/* now split the string */
|
||||
i = 0;
|
||||
while (*ptr) {
|
||||
int count = strcspn(ptr, chars);
|
||||
res[i++] = ptr;
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
res[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = i;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_close()
|
||||
* Frees up all resources relating to a login class
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
login_close(login_cap_t * lc)
|
||||
{
|
||||
if (lc) {
|
||||
free(lc->lc_style);
|
||||
free(lc->lc_class);
|
||||
free(lc->lc_cap);
|
||||
free(lc);
|
||||
if (--lc_object_count == 0) {
|
||||
free(internal_string);
|
||||
free(internal_array);
|
||||
internal_array = NULL;
|
||||
internal_arraysz = 0;
|
||||
internal_string = NULL;
|
||||
internal_stringsz = 0;
|
||||
cgetclose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getclassbyname() get the login class by its name.
|
||||
* If the name given is NULL or empty, the default class
|
||||
* LOGIN_DEFCLASS (ie. "default") is fetched. If the
|
||||
* 'pwd' argument is non-NULL and contains an non-NULL
|
||||
* dir entry, then the file _FILE_LOGIN_CONF is picked
|
||||
* up from that directory and used before the system
|
||||
* login database.
|
||||
* Return a filled-out login_cap_t structure, including
|
||||
* class name, and the capability record buffer.
|
||||
*/
|
||||
|
||||
login_cap_t *
|
||||
login_getclassbyname(char const *name, const struct passwd *pwd)
|
||||
{
|
||||
login_cap_t *lc;
|
||||
|
||||
if ((lc = malloc(sizeof(login_cap_t))) != NULL) {
|
||||
int r, me, i = 0;
|
||||
uid_t euid = 0;
|
||||
gid_t egid = 0;
|
||||
const char *msg = NULL;
|
||||
const char *dir;
|
||||
char userpath[MAXPATHLEN];
|
||||
|
||||
static char *login_dbarray[] = { NULL, NULL, NULL };
|
||||
|
||||
me = (name != NULL && strcmp(name, LOGIN_MECLASS) == 0);
|
||||
dir = (!me || pwd == NULL) ? NULL : pwd->pw_dir;
|
||||
/*
|
||||
* Switch to user mode before checking/reading its ~/.login_conf
|
||||
* - some NFSes have root read access disabled.
|
||||
*
|
||||
* XXX: This fails to configure additional groups.
|
||||
*/
|
||||
if (dir) {
|
||||
euid = geteuid();
|
||||
egid = getegid();
|
||||
(void)setegid(pwd->pw_gid);
|
||||
(void)seteuid(pwd->pw_uid);
|
||||
}
|
||||
|
||||
if (dir && snprintf(userpath, MAXPATHLEN, "%s/%s", dir,
|
||||
_FILE_LOGIN_CONF) < MAXPATHLEN) {
|
||||
login_dbarray[i] = userpath;
|
||||
if (_secure_path(userpath, pwd->pw_uid, pwd->pw_gid) != -1)
|
||||
i++; /* only use 'secure' data */
|
||||
}
|
||||
if (_secure_path(_PATH_LOGIN_CONF, 0, 0) != -1)
|
||||
login_dbarray[i++] = _PATH_LOGIN_CONF;
|
||||
login_dbarray[i] = NULL;
|
||||
|
||||
memset(lc, 0, sizeof(login_cap_t));
|
||||
lc->lc_cap = lc->lc_class = lc->lc_style = NULL;
|
||||
|
||||
if (name == NULL || *name == '\0')
|
||||
name = LOGIN_DEFCLASS;
|
||||
|
||||
switch (cgetent(&lc->lc_cap, login_dbarray, name)) {
|
||||
case -1: /* Failed, entry does not exist */
|
||||
if (me)
|
||||
break; /* Don't retry default on 'me' */
|
||||
if (i == 0)
|
||||
r = -1;
|
||||
else if ((r = open(login_dbarray[0], O_RDONLY)) >= 0)
|
||||
close(r);
|
||||
/*
|
||||
* If there's at least one login class database,
|
||||
* and we aren't searching for a default class
|
||||
* then complain about a non-existent class.
|
||||
*/
|
||||
if (r >= 0 || strcmp(name, LOGIN_DEFCLASS) != 0)
|
||||
syslog(LOG_ERR, "login_getclass: unknown class '%s'", name);
|
||||
/* fall-back to default class */
|
||||
name = LOGIN_DEFCLASS;
|
||||
msg = "%s: no default/fallback class '%s'";
|
||||
if (cgetent(&lc->lc_cap, login_dbarray, name) != 0 && r >= 0)
|
||||
break;
|
||||
/* FALLTHROUGH - just return system defaults */
|
||||
case 0: /* success! */
|
||||
if ((lc->lc_class = strdup(name)) != NULL) {
|
||||
if (dir) {
|
||||
(void)seteuid(euid);
|
||||
(void)setegid(egid);
|
||||
}
|
||||
++lc_object_count;
|
||||
return lc;
|
||||
}
|
||||
msg = "%s: strdup: %m";
|
||||
break;
|
||||
case -2:
|
||||
msg = "%s: retrieving class information: %m";
|
||||
break;
|
||||
case -3:
|
||||
msg = "%s: 'tc=' reference loop '%s'";
|
||||
break;
|
||||
case 1:
|
||||
msg = "couldn't resolve 'tc=' reference in '%s'";
|
||||
break;
|
||||
default:
|
||||
msg = "%s: unexpected cgetent() error '%s': %m";
|
||||
break;
|
||||
}
|
||||
if (dir) {
|
||||
(void)seteuid(euid);
|
||||
(void)setegid(egid);
|
||||
}
|
||||
if (msg != NULL)
|
||||
syslog(LOG_ERR, msg, "login_getclass", name);
|
||||
free(lc);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* login_getclass()
|
||||
* Get the login class for the system (only) login class database.
|
||||
* Return a filled-out login_cap_t structure, including
|
||||
* class name, and the capability record buffer.
|
||||
*/
|
||||
|
||||
login_cap_t *
|
||||
login_getclass(const char *cls)
|
||||
{
|
||||
return login_getclassbyname(cls, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getclass()
|
||||
* Get the login class for a given password entry from
|
||||
* the system (only) login class database.
|
||||
* If the password entry's class field is not set, or
|
||||
* the class specified does not exist, then use the
|
||||
* default of LOGIN_DEFCLASS (ie. "default").
|
||||
* Return a filled-out login_cap_t structure, including
|
||||
* class name, and the capability record buffer.
|
||||
*/
|
||||
|
||||
login_cap_t *
|
||||
login_getpwclass(const struct passwd *pwd)
|
||||
{
|
||||
const char *cls = NULL;
|
||||
|
||||
if (pwd != NULL) {
|
||||
cls = pwd->pw_class;
|
||||
if (cls == NULL || *cls == '\0')
|
||||
cls = (pwd->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
|
||||
}
|
||||
return login_getclassbyname(cls, pwd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getuserclass()
|
||||
* Get the login class for a given password entry, allowing user
|
||||
* overrides via ~/.login_conf.
|
||||
*/
|
||||
|
||||
login_cap_t *
|
||||
login_getuserclass(const struct passwd *pwd)
|
||||
{
|
||||
return login_getclassbyname(LOGIN_MECLASS, pwd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* login_getcapstr()
|
||||
* Given a login_cap entry, and a capability name, return the
|
||||
* value defined for that capability, a default if not found, or
|
||||
* an error string on error.
|
||||
*/
|
||||
|
||||
const char *
|
||||
login_getcapstr(login_cap_t *lc, const char *cap, const char *def, const char *error)
|
||||
{
|
||||
char *res;
|
||||
int ret;
|
||||
|
||||
if (lc == NULL || cap == NULL || lc->lc_cap == NULL || *cap == '\0')
|
||||
return def;
|
||||
|
||||
if ((ret = cgetstr(lc->lc_cap, cap, &res)) == -1)
|
||||
return def;
|
||||
return (ret >= 0) ? res : error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getcaplist()
|
||||
* Given a login_cap entry, and a capability name, return the
|
||||
* value defined for that capability split into an array of
|
||||
* strings.
|
||||
*/
|
||||
|
||||
const char **
|
||||
login_getcaplist(login_cap_t *lc, const char *cap, const char *chars)
|
||||
{
|
||||
const char *lstring;
|
||||
|
||||
if (chars == NULL)
|
||||
chars = ", \t";
|
||||
if ((lstring = login_getcapstr(lc, cap, NULL, NULL)) != NULL)
|
||||
return arrayize(lstring, chars, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getpath()
|
||||
* From the login_cap_t <lc>, get the capability <cap> which is
|
||||
* formatted as either a space or comma delimited list of paths
|
||||
* and append them all into a string and separate by semicolons.
|
||||
* If there is an error of any kind, return <error>.
|
||||
*/
|
||||
|
||||
const char *
|
||||
login_getpath(login_cap_t *lc, const char *cap, const char *error)
|
||||
{
|
||||
const char *str;
|
||||
char *ptr;
|
||||
int count;
|
||||
|
||||
str = login_getcapstr(lc, cap, NULL, NULL);
|
||||
if (str == NULL)
|
||||
return error;
|
||||
ptr = __DECONST(char *, str); /* XXXX Yes, very dodgy */
|
||||
while (*ptr) {
|
||||
count = strcspn(ptr, ", \t");
|
||||
ptr += count;
|
||||
if (*ptr)
|
||||
*ptr++ = ':';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
isinfinite(const char *s)
|
||||
{
|
||||
static const char *infs[] = {
|
||||
"infinity",
|
||||
"inf",
|
||||
"unlimited",
|
||||
"unlimit",
|
||||
"-1",
|
||||
NULL
|
||||
};
|
||||
const char **i = &infs[0];
|
||||
|
||||
while (*i != NULL) {
|
||||
if (strcasecmp(s, *i) == 0)
|
||||
return 1;
|
||||
++i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u_quad_t
|
||||
rmultiply(u_quad_t n1, u_quad_t n2)
|
||||
{
|
||||
u_quad_t m, r;
|
||||
int b1, b2;
|
||||
|
||||
static int bpw = 0;
|
||||
|
||||
/* Handle simple cases */
|
||||
if (n1 == 0 || n2 == 0)
|
||||
return 0;
|
||||
if (n1 == 1)
|
||||
return n2;
|
||||
if (n2 == 1)
|
||||
return n1;
|
||||
|
||||
/*
|
||||
* sizeof() returns number of bytes needed for storage.
|
||||
* This may be different from the actual number of useful bits.
|
||||
*/
|
||||
if (!bpw) {
|
||||
bpw = sizeof(u_quad_t) * 8;
|
||||
while (((u_quad_t)1 << (bpw-1)) == 0)
|
||||
--bpw;
|
||||
}
|
||||
|
||||
/*
|
||||
* First check the magnitude of each number. If the sum of the
|
||||
* magnatude is way to high, reject the number. (If this test
|
||||
* is not done then the first multiply below may overflow.)
|
||||
*/
|
||||
for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
|
||||
;
|
||||
for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
|
||||
;
|
||||
if (b1 + b2 - 2 > bpw) {
|
||||
errno = ERANGE;
|
||||
return (UQUAD_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompose the multiplication to be:
|
||||
* h1 = n1 & ~1
|
||||
* h2 = n2 & ~1
|
||||
* l1 = n1 & 1
|
||||
* l2 = n2 & 1
|
||||
* (h1 + l1) * (h2 + l2)
|
||||
* (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
|
||||
*
|
||||
* Since h1 && h2 do not have the low bit set, we can then say:
|
||||
*
|
||||
* (h1>>1 * h2>>1 * 4) + ...
|
||||
*
|
||||
* So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
|
||||
* overflow.
|
||||
*
|
||||
* Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
|
||||
* then adding in residual amout will cause an overflow.
|
||||
*/
|
||||
|
||||
m = (n1 >> 1) * (n2 >> 1);
|
||||
if (m >= ((u_quad_t)1 << (bpw-2))) {
|
||||
errno = ERANGE;
|
||||
return (UQUAD_MAX);
|
||||
}
|
||||
m *= 4;
|
||||
|
||||
r = (n1 & n2 & 1)
|
||||
+ (n2 & 1) * (n1 & ~(u_quad_t)1)
|
||||
+ (n1 & 1) * (n2 & ~(u_quad_t)1);
|
||||
|
||||
if ((u_quad_t)(m + r) < m) {
|
||||
errno = ERANGE;
|
||||
return (UQUAD_MAX);
|
||||
}
|
||||
m += r;
|
||||
|
||||
return (m);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getcaptime()
|
||||
* From the login_cap_t <lc>, get the capability <cap>, which is
|
||||
* formatted as a time (e.g., "<cap>=10h3m2s"). If <cap> is not
|
||||
* present in <lc>, return <def>; if there is an error of some kind,
|
||||
* return <error>.
|
||||
*/
|
||||
|
||||
rlim_t
|
||||
login_getcaptime(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
{
|
||||
char *res, *ep, *oval;
|
||||
int r;
|
||||
rlim_t tot;
|
||||
|
||||
errno = 0;
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
|
||||
/*
|
||||
* Look for <cap> in lc_cap.
|
||||
* If it's not there (-1), return <def>.
|
||||
* If there's an error, return <error>.
|
||||
*/
|
||||
|
||||
if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
|
||||
return def;
|
||||
else if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* "inf" and "infinity" are special cases */
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
/*
|
||||
* Now go through the string, turning something like 1h2m3s into
|
||||
* an integral value. Whee.
|
||||
*/
|
||||
|
||||
errno = 0;
|
||||
tot = 0;
|
||||
oval = res;
|
||||
while (*res) {
|
||||
rlim_t tim = strtoq(res, &ep, 0);
|
||||
rlim_t mult = 1;
|
||||
|
||||
if (ep == NULL || ep == res || errno != 0) {
|
||||
invalid:
|
||||
syslog(LOG_WARNING, "login_getcaptime: class '%s' bad value %s=%s",
|
||||
lc->lc_class, cap, oval);
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
/* Look for suffixes */
|
||||
switch (*ep++) {
|
||||
case 0:
|
||||
ep--;
|
||||
break; /* end of string */
|
||||
case 's': case 'S': /* seconds */
|
||||
break;
|
||||
case 'm': case 'M': /* minutes */
|
||||
mult = 60;
|
||||
break;
|
||||
case 'h': case 'H': /* hours */
|
||||
mult = 60L * 60L;
|
||||
break;
|
||||
case 'd': case 'D': /* days */
|
||||
mult = 60L * 60L * 24L;
|
||||
break;
|
||||
case 'w': case 'W': /* weeks */
|
||||
mult = 60L * 60L * 24L * 7L;
|
||||
break;
|
||||
case 'y': case 'Y': /* 365-day years */
|
||||
mult = 60L * 60L * 24L * 365L;
|
||||
break;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
res = ep;
|
||||
tot += rmultiply(tim, mult);
|
||||
if (errno)
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
return tot;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getcapnum()
|
||||
* From the login_cap_t <lc>, extract the numerical value <cap>.
|
||||
* If it is not present, return <def> for a default, and return
|
||||
* <error> if there is an error.
|
||||
* Like login_getcaptime(), only it only converts to a number, not
|
||||
* to a time; "infinity" and "inf" are 'special.'
|
||||
*/
|
||||
|
||||
rlim_t
|
||||
login_getcapnum(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
{
|
||||
char *ep, *res;
|
||||
int r;
|
||||
rlim_t val;
|
||||
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
|
||||
/*
|
||||
* For BSDI compatibility, try for the tag=<val> first
|
||||
*/
|
||||
if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1) {
|
||||
long lval;
|
||||
/* string capability not present, so try for tag#<val> as numeric */
|
||||
if ((r = cgetnum(lc->lc_cap, cap, &lval)) == -1)
|
||||
return def; /* Not there, so return default */
|
||||
else if (r >= 0)
|
||||
return (rlim_t)lval;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
errno = 0;
|
||||
val = strtoq(res, &ep, 0);
|
||||
if (ep == NULL || ep == res || errno != 0) {
|
||||
syslog(LOG_WARNING, "login_getcapnum: class '%s' bad value %s=%s",
|
||||
lc->lc_class, cap, res);
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* login_getcapsize()
|
||||
* From the login_cap_t <lc>, extract the capability <cap>, which is
|
||||
* formatted as a size (e.g., "<cap>=10M"); it can also be "infinity".
|
||||
* If not present, return <def>, or <error> if there is an error of
|
||||
* some sort.
|
||||
*/
|
||||
|
||||
rlim_t
|
||||
login_getcapsize(login_cap_t *lc, const char *cap, rlim_t def, rlim_t error)
|
||||
{
|
||||
char *ep, *res, *oval;
|
||||
int r;
|
||||
rlim_t tot;
|
||||
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
|
||||
if ((r = cgetstr(lc->lc_cap, cap, &res)) == -1)
|
||||
return def;
|
||||
else if (r < 0) {
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (isinfinite(res))
|
||||
return RLIM_INFINITY;
|
||||
|
||||
errno = 0;
|
||||
tot = 0;
|
||||
oval = res;
|
||||
while (*res) {
|
||||
rlim_t siz = strtoq(res, &ep, 0);
|
||||
rlim_t mult = 1;
|
||||
|
||||
if (ep == NULL || ep == res || errno != 0) {
|
||||
invalid:
|
||||
syslog(LOG_WARNING, "login_getcapsize: class '%s' bad value %s=%s",
|
||||
lc->lc_class, cap, oval);
|
||||
errno = ERANGE;
|
||||
return error;
|
||||
}
|
||||
switch (*ep++) {
|
||||
case 0: /* end of string */
|
||||
ep--;
|
||||
break;
|
||||
case 'b': case 'B': /* 512-byte blocks */
|
||||
mult = 512;
|
||||
break;
|
||||
case 'k': case 'K': /* 1024-byte Kilobytes */
|
||||
mult = 1024;
|
||||
break;
|
||||
case 'm': case 'M': /* 1024-k kbytes */
|
||||
mult = 1024 * 1024;
|
||||
break;
|
||||
case 'g': case 'G': /* 1Gbyte */
|
||||
mult = 1024 * 1024 * 1024;
|
||||
break;
|
||||
case 't': case 'T': /* 1TBte */
|
||||
mult = 1024LL * 1024LL * 1024LL * 1024LL;
|
||||
break;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
res = ep;
|
||||
tot += rmultiply(siz, mult);
|
||||
if (errno)
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
return tot;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getcapbool()
|
||||
* From the login_cap_t <lc>, check for the existance of the capability
|
||||
* of <cap>. Return <def> if <lc>->lc_cap is NULL, otherwise return
|
||||
* the whether or not <cap> exists there.
|
||||
*/
|
||||
|
||||
int
|
||||
login_getcapbool(login_cap_t *lc, const char *cap, int def)
|
||||
{
|
||||
if (lc == NULL || lc->lc_cap == NULL)
|
||||
return def;
|
||||
return (cgetcap(lc->lc_cap, cap, ':') != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_getstyle()
|
||||
* Given a login_cap entry <lc>, and optionally a type of auth <auth>,
|
||||
* and optionally a style <style>, find the style that best suits these
|
||||
* rules:
|
||||
* 1. If <auth> is non-null, look for an "auth-<auth>=" string
|
||||
* in the capability; if not present, default to "auth=".
|
||||
* 2. If there is no auth list found from (1), default to
|
||||
* "passwd" as an authorization list.
|
||||
* 3. If <style> is non-null, look for <style> in the list of
|
||||
* authorization methods found from (2); if <style> is NULL, default
|
||||
* to LOGIN_DEFSTYLE ("passwd").
|
||||
* 4. If the chosen style is found in the chosen list of authorization
|
||||
* methods, return that; otherwise, return NULL.
|
||||
* E.g.:
|
||||
* login_getstyle(lc, NULL, "ftp");
|
||||
* login_getstyle(lc, "login", NULL);
|
||||
* login_getstyle(lc, "skey", "network");
|
||||
*/
|
||||
|
||||
const char *
|
||||
login_getstyle(login_cap_t *lc, const char *style, const char *auth)
|
||||
{
|
||||
int i;
|
||||
const char **authtypes = NULL;
|
||||
char *auths= NULL;
|
||||
char realauth[64];
|
||||
|
||||
static const char *defauthtypes[] = { LOGIN_DEFSTYLE, NULL };
|
||||
|
||||
if (auth != NULL && *auth != '\0') {
|
||||
if (snprintf(realauth, sizeof realauth, "auth-%s", auth) < (int)sizeof(realauth))
|
||||
authtypes = login_getcaplist(lc, realauth, NULL);
|
||||
}
|
||||
|
||||
if (authtypes == NULL)
|
||||
authtypes = login_getcaplist(lc, "auth", NULL);
|
||||
|
||||
if (authtypes == NULL)
|
||||
authtypes = defauthtypes;
|
||||
|
||||
/*
|
||||
* We have at least one authtype now; auths is a comma-separated
|
||||
* (or space-separated) list of authentication types. We have to
|
||||
* convert from this to an array of char*'s; authtypes then gets this.
|
||||
*/
|
||||
i = 0;
|
||||
if (style != NULL && *style != '\0') {
|
||||
while (authtypes[i] != NULL && strcmp(style, authtypes[i]) != 0)
|
||||
i++;
|
||||
}
|
||||
|
||||
lc->lc_style = NULL;
|
||||
if (authtypes[i] != NULL && (auths = strdup(authtypes[i])) != NULL)
|
||||
lc->lc_style = auths;
|
||||
|
||||
if (lc->lc_style != NULL)
|
||||
lc->lc_style = strdup(lc->lc_style);
|
||||
|
||||
return lc->lc_style;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*-
|
||||
* Copyright (c) 1996 by
|
||||
* Sean Eric Fagan <sef@kithrup.com>
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* 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.
|
||||
* 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
* is permitted provided this notation is included.
|
||||
* 4. Absolutely no warranty of function or purpose is made by the authors.
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*
|
||||
* Low-level routines relating to the user capabilities database
|
||||
*
|
||||
* Was login_cap.h,v 1.9 1997/05/07 20:00:01 eivind Exp
|
||||
* $FreeBSD: src/lib/libutil/login_cap.h,v 1.9 2003/10/18 10:04:16 markm Exp $
|
||||
*/
|
||||
|
||||
#ifndef _LOGIN_CAP_H_
|
||||
#define _LOGIN_CAP_H_
|
||||
|
||||
#define LOGIN_DEFCLASS "default"
|
||||
#define LOGIN_DEFROOTCLASS "root"
|
||||
#define LOGIN_MECLASS "me"
|
||||
#define LOGIN_DEFSTYLE "passwd"
|
||||
#define LOGIN_DEFSERVICE "login"
|
||||
#define LOGIN_DEFUMASK 022
|
||||
#define LOGIN_DEFPRI 0
|
||||
#define _PATH_LOGIN_CONF "/etc/login.conf"
|
||||
#define _FILE_LOGIN_CONF ".login_conf"
|
||||
#define _PATH_AUTHPROG "/usr/libexec/login_"
|
||||
|
||||
#define LOGIN_SETGROUP 0x0001 /* set group */
|
||||
#define LOGIN_SETLOGIN 0x0002 /* set login (via setlogin) */
|
||||
#define LOGIN_SETPATH 0x0004 /* set path */
|
||||
#define LOGIN_SETPRIORITY 0x0008 /* set priority */
|
||||
#define LOGIN_SETRESOURCES 0x0010 /* set resources (cputime, etc.) */
|
||||
#define LOGIN_SETUMASK 0x0020 /* set umask, obviously */
|
||||
#define LOGIN_SETUSER 0x0040 /* set user (via setuid) */
|
||||
#define LOGIN_SETENV 0x0080 /* set user environment */
|
||||
#define LOGIN_SETMAC 0x0100 /* set user default MAC label */
|
||||
#define LOGIN_SETALL 0x01ff /* set everything */
|
||||
|
||||
#define BI_AUTH "authorize" /* accepted authentication */
|
||||
#define BI_REJECT "reject" /* rejected authentication */
|
||||
#define BI_CHALLENG "reject challenge" /* reject with a challenge */
|
||||
#define BI_SILENT "reject silent" /* reject silently */
|
||||
#define BI_REMOVE "remove" /* remove file on error */
|
||||
#define BI_ROOTOKAY "authorize root" /* root authenticated */
|
||||
#define BI_SECURE "authorize secure" /* okay on non-secure line */
|
||||
#define BI_SETENV "setenv" /* set environment variable */
|
||||
#define BI_VALUE "value" /* set local variable */
|
||||
|
||||
#define AUTH_OKAY 0x01 /* user authenticated */
|
||||
#define AUTH_ROOTOKAY 0x02 /* root login okay */
|
||||
#define AUTH_SECURE 0x04 /* secure login */
|
||||
#define AUTH_SILENT 0x08 /* silent rejection */
|
||||
#define AUTH_CHALLENGE 0x10 /* a chellenge was given */
|
||||
|
||||
#define AUTH_ALLOW (AUTH_OKAY | AUTH_ROOTOKAY | AUTH_SECURE)
|
||||
|
||||
typedef struct login_cap {
|
||||
char *lc_class;
|
||||
char *lc_cap;
|
||||
char *lc_style;
|
||||
} login_cap_t;
|
||||
|
||||
typedef struct login_time {
|
||||
u_short lt_start; /* Start time */
|
||||
u_short lt_end; /* End time */
|
||||
#define LTM_NONE 0x00
|
||||
#define LTM_SUN 0x01
|
||||
#define LTM_MON 0x02
|
||||
#define LTM_TUE 0x04
|
||||
#define LTM_WED 0x08
|
||||
#define LTM_THU 0x10
|
||||
#define LTM_FRI 0x20
|
||||
#define LTM_SAT 0x40
|
||||
#define LTM_ANY 0x7F
|
||||
#define LTM_WK 0x3E
|
||||
#define LTM_WD 0x41
|
||||
u_char lt_dow; /* Days of week */
|
||||
} login_time_t;
|
||||
|
||||
#define LC_MAXTIMES 64
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__BEGIN_DECLS
|
||||
struct passwd;
|
||||
|
||||
void login_close(login_cap_t *);
|
||||
login_cap_t *login_getclassbyname(const char *, const struct passwd *);
|
||||
login_cap_t *login_getclass(const char *);
|
||||
login_cap_t *login_getpwclass(const struct passwd *);
|
||||
login_cap_t *login_getuserclass(const struct passwd *);
|
||||
|
||||
const char *login_getcapstr(login_cap_t*, const char *, const char *, const char *);
|
||||
const char **login_getcaplist(login_cap_t *, const char *, const char *);
|
||||
const char *login_getstyle(login_cap_t *, const char *, const char *);
|
||||
rlim_t login_getcaptime(login_cap_t *, const char *, rlim_t, rlim_t);
|
||||
rlim_t login_getcapnum(login_cap_t *, const char *, rlim_t, rlim_t);
|
||||
rlim_t login_getcapsize(login_cap_t *, const char *, rlim_t, rlim_t);
|
||||
const char *login_getpath(login_cap_t *, const char *, const char *);
|
||||
int login_getcapbool(login_cap_t *, const char *, int);
|
||||
const char *login_setcryptfmt(login_cap_t *, const char *, const char *);
|
||||
|
||||
int setclasscontext(const char*, unsigned int);
|
||||
int setusercontext(login_cap_t*, const struct passwd*, uid_t, unsigned int);
|
||||
void setclassresources(login_cap_t *);
|
||||
void setclassenvironment(login_cap_t *, const struct passwd *, int);
|
||||
|
||||
/* Most of these functions are deprecated */
|
||||
int auth_approve(login_cap_t*, const char*, const char*);
|
||||
int auth_check(const char *, const char *, const char *, const char *, int *);
|
||||
void auth_env(void);
|
||||
char *auth_mkvalue(const char *n);
|
||||
int auth_response(const char *, const char *, const char *, const char *, int *, const char *, const char *);
|
||||
void auth_rmfiles(void);
|
||||
int auth_scan(int);
|
||||
int auth_script(const char*, ...);
|
||||
int auth_script_data(const char *, int, const char *, ...);
|
||||
char *auth_valud(const char *);
|
||||
int auth_setopt(const char *, const char *);
|
||||
void auth_clropts(void);
|
||||
|
||||
void auth_checknologin(login_cap_t*);
|
||||
int auth_cat(const char*);
|
||||
|
||||
int auth_ttyok(login_cap_t*, const char *);
|
||||
int auth_hostok(login_cap_t*, const char *, char const *);
|
||||
int auth_timeok(login_cap_t*, time_t);
|
||||
|
||||
struct tm;
|
||||
|
||||
login_time_t parse_lt(const char *);
|
||||
int in_ltm(const login_time_t *, struct tm *, time_t *);
|
||||
int in_ltms(const login_time_t *, struct tm *, time_t *);
|
||||
|
||||
/* helper functions */
|
||||
|
||||
int login_strinlist(const char **, char const *, int);
|
||||
int login_str2inlist(const char **, const char *, const char *, int);
|
||||
login_time_t * login_timelist(login_cap_t *, char const *, int *, login_time_t **);
|
||||
int login_ttyok(login_cap_t *, const char *, const char *, const char *);
|
||||
int login_hostok(login_cap_t *, const char *, const char *, const char *, const char *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _LOGIN_CAP_H_ */
|
||||
@@ -0,0 +1,197 @@
|
||||
.\" Copyright (c) 1995 David Nugent <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
.\" is permitted provided this notation is included.
|
||||
.\" 4. Absolutely no warranty of function or purpose is made by the author
|
||||
.\" David Nugent.
|
||||
.\" 5. Modifications may be freely made to this file providing the above
|
||||
.\" conditions are met.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login_class.3,v 1.19 2006/06/17 07:25:58 maxim Exp $
|
||||
.\"
|
||||
.Dd December 28, 1996
|
||||
.Os
|
||||
.Dt LOGIN_CLASS 3
|
||||
.Sh NAME
|
||||
.Nm setclasscontext ,
|
||||
.Nm setclassenvironment ,
|
||||
.Nm setclassresources ,
|
||||
.Nm setusercontext
|
||||
.Nd "functions for using the login class capabilities database"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In login_cap.h
|
||||
.Ft int
|
||||
.Fn setclasscontext "const char *classname" "unsigned int flags"
|
||||
.Ft int
|
||||
.Fn setusercontext "login_cap_t *lc" "const struct passwd *pwd" "uid_t uid" "unsigned int flags"
|
||||
.Ft void
|
||||
.Fn setclassresources "login_cap_t *lc"
|
||||
.Ft void
|
||||
.Fn setclassenvironment "login_cap_t *lc" "const struct passwd *pwd" "int paths"
|
||||
.Sh DESCRIPTION
|
||||
These functions provide a higher level interface to the login class
|
||||
database than those documented in
|
||||
.Xr login_cap 3 .
|
||||
These functions are used to set resource limits, environment and
|
||||
accounting settings for users on logging into the system and when
|
||||
selecting an appropriate set of environment and resource settings
|
||||
for system daemons based on login classes.
|
||||
These functions may only be called if the current process is
|
||||
running with root privileges.
|
||||
If the LOGIN_SETLOGIN flag is used this function calls
|
||||
.Xr setlogin 2 ,
|
||||
and due care must be taken as detailed in the manpage for that
|
||||
function and this affects all processes running in the same session
|
||||
and not just the current process.
|
||||
.Pp
|
||||
The
|
||||
.Fn setclasscontext
|
||||
function sets various class context values (resource limits, umask and
|
||||
process priorities) based on values for a specific named class.
|
||||
.Pp
|
||||
The
|
||||
.Fn setusercontext
|
||||
function sets class context values based on a given login_cap_t
|
||||
object and a specific passwd record (if login_cap_t is NULL),
|
||||
the current session's login, and the current process
|
||||
user and group ownership.
|
||||
Each of these actions is selectable via bit-flags passed
|
||||
in the
|
||||
.Ar flags
|
||||
parameter, which is comprised of one or more of the following:
|
||||
.Bl -tag -width LOGIN_SETRESOURCES
|
||||
.It LOGIN_SETLOGIN
|
||||
Set the login associated with the current session to the user
|
||||
specified in the passwd structure using
|
||||
.Xr setlogin 2 .
|
||||
The
|
||||
.Ar pwd
|
||||
parameter must not be NULL if this option is used.
|
||||
.It LOGIN_SETUSER
|
||||
Set ownership of the current process to the uid specified in the
|
||||
.Ar uid
|
||||
parameter using
|
||||
.Xr setuid 2 .
|
||||
.It LOGIN_SETGROUP
|
||||
Set group ownership of the current process to the group id
|
||||
specified in the passwd structure using
|
||||
.Xr setgid 2 ,
|
||||
and calls
|
||||
.Xr initgroups 3
|
||||
to set up the group access list for the current process.
|
||||
The
|
||||
.Ar pwd
|
||||
parameter must not be NULL if this option is used.
|
||||
.It LOGIN_SETRESOURCES
|
||||
Set resource limits for the current process based on values
|
||||
specified in the system login class database.
|
||||
Class capability tags used, with and without -cur (soft limit)
|
||||
or -max (hard limit) suffixes and the corresponding resource
|
||||
setting:
|
||||
.Bd -literal
|
||||
cputime RLIMIT_CPU
|
||||
filesize RLIMIT_FSIZE
|
||||
datasize RLIMIT_DATA
|
||||
stacksize RLIMIT_STACK
|
||||
coredumpsize RLIMIT_CORE
|
||||
memoryuse RLIMIT_RSS
|
||||
memorylocked RLIMIT_MEMLOCK
|
||||
maxproc RLIMIT_NPROC
|
||||
openfiles RLIMIT_NOFILE
|
||||
sbsize RLIMIT_SBSIZE
|
||||
vmemoryuse RLIMIT_VMEM
|
||||
.Ed
|
||||
.It LOGIN_SETPRIORITY
|
||||
Set the scheduling priority for the current process based on the
|
||||
value specified in the system login class database.
|
||||
Class capability tags used:
|
||||
.Bd -literal
|
||||
priority
|
||||
.Ed
|
||||
.It LOGIN_SETUMASK
|
||||
Set the umask for the current process to a value in the user or
|
||||
system login class database.
|
||||
Class capability tags used:
|
||||
.Bd -literal
|
||||
umask
|
||||
.Ed
|
||||
.It LOGIN_SETPATH
|
||||
Set the "path" and "manpath" environment variables based on values
|
||||
in the user or system login class database.
|
||||
Class capability tags used with the corresponding environment
|
||||
variables set:
|
||||
.Bd -literal
|
||||
path PATH
|
||||
manpath MANPATH
|
||||
.Ed
|
||||
.It LOGIN_SETENV
|
||||
Set various environment variables based on values in the user or
|
||||
system login class database.
|
||||
Class capability tags used with the corresponding environment
|
||||
variables set:
|
||||
.Bd -literal
|
||||
lang LANG
|
||||
charset MM_CHARSET
|
||||
timezone TZ
|
||||
term TERM
|
||||
.Ed
|
||||
.Pp
|
||||
Additional environment variables may be set using the list type
|
||||
capability "setenv=var1 val1,var2 val2..,varN valN".
|
||||
.It LOGIN_SETMAC
|
||||
Set the MAC label for the current process to the label specified
|
||||
in system login class database.
|
||||
.Pp
|
||||
.It LOGIN_SETALL
|
||||
Enables all of the above settings.
|
||||
.El
|
||||
.Pp
|
||||
Note that when setting environment variables and a valid passwd
|
||||
pointer is provided in the
|
||||
.Ar pwd
|
||||
parameter, the characters
|
||||
.Ql \&~
|
||||
and
|
||||
.Ql \&$
|
||||
are substituted for the user's home directory and login name
|
||||
respectively.
|
||||
.Pp
|
||||
The
|
||||
.Fn setclassresources
|
||||
and
|
||||
.Fn setclassenvironment
|
||||
functions are subsets of the setcontext functions above, but may
|
||||
be useful in isolation.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn setclasscontext
|
||||
and
|
||||
.Fn setusercontext
|
||||
functions return -1 if an error occurred, or 0 on success.
|
||||
If an error occurs when attempting to set the user, login, group
|
||||
or resources, a message is reported to
|
||||
.Xr syslog 3 ,
|
||||
with LOG_ERR priority and directed to the currently active facility.
|
||||
.Sh SEE ALSO
|
||||
.Xr setgid 2 ,
|
||||
.Xr setlogin 2 ,
|
||||
.Xr setuid 2 ,
|
||||
.Xr getcap 3 ,
|
||||
.Xr initgroups 3 ,
|
||||
.Xr login_cap 3 ,
|
||||
.Xr mac_set_proc 3 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr termcap 5
|
||||
@@ -0,0 +1,429 @@
|
||||
/*-
|
||||
* Copyright (c) 1996 by
|
||||
* Sean Eric Fagan <sef@kithrup.com>
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* 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.
|
||||
* 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
* is permitted provided this notation is included.
|
||||
* 4. Absolutely no warranty of function or purpose is made by the authors.
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*
|
||||
* High-level routines relating to use of the user capabilities database
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login_class.c,v 1.24 2003/10/29 10:55:56 tjr Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/mac.h>
|
||||
#include <sys/rtprio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <login_cap.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static struct login_res {
|
||||
const char *what;
|
||||
rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t);
|
||||
int why;
|
||||
} resources[] = {
|
||||
{ "cputime", login_getcaptime, RLIMIT_CPU },
|
||||
{ "filesize", login_getcapsize, RLIMIT_FSIZE },
|
||||
{ "datasize", login_getcapsize, RLIMIT_DATA },
|
||||
{ "stacksize", login_getcapsize, RLIMIT_STACK },
|
||||
{ "memoryuse", login_getcapsize, RLIMIT_RSS },
|
||||
{ "memorylocked", login_getcapsize, RLIMIT_MEMLOCK },
|
||||
{ "maxproc", login_getcapnum, RLIMIT_NPROC },
|
||||
{ "openfiles", login_getcapnum, RLIMIT_NOFILE },
|
||||
{ "coredumpsize", login_getcapsize, RLIMIT_CORE },
|
||||
{ "sbsize", login_getcapsize, RLIMIT_SBSIZE },
|
||||
{ "vmemoryuse", login_getcapsize, RLIMIT_VMEM },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
setclassresources(login_cap_t *lc)
|
||||
{
|
||||
struct login_res *lr;
|
||||
|
||||
if (lc == NULL)
|
||||
return;
|
||||
|
||||
for (lr = resources; lr->what != NULL; ++lr) {
|
||||
struct rlimit rlim;
|
||||
|
||||
/*
|
||||
* The login.conf file can have <limit>, <limit>-max, and
|
||||
* <limit>-cur entries.
|
||||
* What we do is get the current current- and maximum- limits.
|
||||
* Then, we try to get an entry for <limit> from the capability,
|
||||
* using the current and max limits we just got as the
|
||||
* default/error values.
|
||||
* *Then*, we try looking for <limit>-cur and <limit>-max,
|
||||
* again using the appropriate values as the default/error
|
||||
* conditions.
|
||||
*/
|
||||
|
||||
if (getrlimit(lr->why, &rlim) != 0)
|
||||
syslog(LOG_ERR, "getting %s resource limit: %m", lr->what);
|
||||
else {
|
||||
char name_cur[40];
|
||||
char name_max[40];
|
||||
rlim_t rcur = rlim.rlim_cur;
|
||||
rlim_t rmax = rlim.rlim_max;
|
||||
|
||||
sprintf(name_cur, "%s-cur", lr->what);
|
||||
sprintf(name_max, "%s-max", lr->what);
|
||||
|
||||
rcur = (*lr->who)(lc, lr->what, rcur, rcur);
|
||||
rmax = (*lr->who)(lc, lr->what, rmax, rmax);
|
||||
rlim.rlim_cur = (*lr->who)(lc, name_cur, rcur, rcur);
|
||||
rlim.rlim_max = (*lr->who)(lc, name_max, rmax, rmax);
|
||||
|
||||
if (setrlimit(lr->why, &rlim) == -1)
|
||||
syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct login_vars {
|
||||
const char *tag;
|
||||
const char *var;
|
||||
const char *def;
|
||||
int overwrite;
|
||||
} pathvars[] = {
|
||||
{ "path", "PATH", NULL, 1},
|
||||
{ "cdpath", "CDPATH", NULL, 1},
|
||||
{ "manpath", "MANPATH", NULL, 1},
|
||||
{ NULL, NULL, NULL, 0}
|
||||
}, envars[] = {
|
||||
{ "lang", "LANG", NULL, 1},
|
||||
{ "charset", "MM_CHARSET", NULL, 1},
|
||||
{ "timezone", "TZ", NULL, 1},
|
||||
{ "term", "TERM", NULL, 0},
|
||||
{ NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
static char *
|
||||
substvar(const char * var, const struct passwd * pwd, int hlen, int pch, int nlen)
|
||||
{
|
||||
char *np = NULL;
|
||||
|
||||
if (var != NULL) {
|
||||
int tildes = 0;
|
||||
int dollas = 0;
|
||||
char *p;
|
||||
|
||||
if (pwd != NULL) {
|
||||
/* Count the number of ~'s in var to substitute */
|
||||
for (p = (char *)var; (p = strchr(p, '~')) != NULL; p++)
|
||||
++tildes;
|
||||
/* Count the number of $'s in var to substitute */
|
||||
for (p = (char *)var; (p = strchr(p, '$')) != NULL; p++)
|
||||
++dollas;
|
||||
}
|
||||
|
||||
np = malloc(strlen(var) + (dollas * nlen)
|
||||
- dollas + (tildes * (pch+hlen))
|
||||
- tildes + 1);
|
||||
|
||||
if (np != NULL) {
|
||||
p = strcpy(np, var);
|
||||
|
||||
if (pwd != NULL) {
|
||||
/*
|
||||
* This loop does user username and homedir substitutions
|
||||
* for unescaped $ (username) and ~ (homedir)
|
||||
*/
|
||||
while (*(p += strcspn(p, "~$")) != '\0') {
|
||||
int l = strlen(p);
|
||||
|
||||
if (p > np && *(p-1) == '\\') /* Escaped: */
|
||||
memmove(p - 1, p, l + 1); /* Slide-out the backslash */
|
||||
else if (*p == '~') {
|
||||
int v = pch && *(p+1) != '/'; /* Avoid double // */
|
||||
memmove(p + hlen + v, p + 1, l); /* Subst homedir */
|
||||
memmove(p, pwd->pw_dir, hlen);
|
||||
if (v)
|
||||
p[hlen] = '/';
|
||||
p += hlen + v;
|
||||
}
|
||||
else /* if (*p == '$') */ {
|
||||
memmove(p + nlen, p + 1, l); /* Subst username */
|
||||
memmove(p, pwd->pw_name, nlen);
|
||||
p += nlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths)
|
||||
{
|
||||
struct login_vars *vars = paths ? pathvars : envars;
|
||||
int hlen = pwd ? strlen(pwd->pw_dir) : 0;
|
||||
int nlen = pwd ? strlen(pwd->pw_name) : 0;
|
||||
char pch = 0;
|
||||
|
||||
if (hlen && pwd->pw_dir[hlen-1] != '/')
|
||||
++pch;
|
||||
|
||||
while (vars->tag != NULL) {
|
||||
const char * var = paths ? login_getpath(lc, vars->tag, NULL)
|
||||
: login_getcapstr(lc, vars->tag, NULL, NULL);
|
||||
|
||||
char * np = substvar(var, pwd, hlen, pch, nlen);
|
||||
|
||||
if (np != NULL) {
|
||||
setenv(vars->var, np, vars->overwrite);
|
||||
free(np);
|
||||
} else if (vars->def != NULL) {
|
||||
setenv(vars->var, vars->def, 0);
|
||||
}
|
||||
++vars;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're not processing paths, then see if there is a setenv list by
|
||||
* which the admin and/or user may set an arbitrary set of env vars.
|
||||
*/
|
||||
if (!paths) {
|
||||
const char **set_env = login_getcaplist(lc, "setenv", ",");
|
||||
|
||||
if (set_env != NULL) {
|
||||
while (*set_env != NULL) {
|
||||
char *p = strchr(*set_env, '=');
|
||||
|
||||
if (p != NULL) { /* Discard invalid entries */
|
||||
char *np;
|
||||
|
||||
*p++ = '\0';
|
||||
if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) {
|
||||
setenv(*set_env, np, 1);
|
||||
free(np);
|
||||
}
|
||||
}
|
||||
++set_env;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setclasscontext()
|
||||
*
|
||||
* For the login class <class>, set various class context values
|
||||
* (limits, mainly) to the values for that class. Which values are
|
||||
* set are controlled by <flags> -- see <login_class.h> for the
|
||||
* possible values.
|
||||
*
|
||||
* setclasscontext() can only set resources, priority, and umask.
|
||||
*/
|
||||
|
||||
int
|
||||
setclasscontext(const char *classname, unsigned int flags)
|
||||
{
|
||||
int rc;
|
||||
login_cap_t *lc;
|
||||
|
||||
lc = login_getclassbyname(classname, NULL);
|
||||
|
||||
flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY |
|
||||
LOGIN_SETUMASK | LOGIN_SETPATH;
|
||||
|
||||
rc = lc ? setusercontext(lc, NULL, 0, flags) : -1;
|
||||
login_close(lc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Private functionw which takes care of processing
|
||||
*/
|
||||
|
||||
static mode_t
|
||||
setlogincontext(login_cap_t *lc, const struct passwd *pwd,
|
||||
mode_t mymask, unsigned long flags)
|
||||
{
|
||||
if (lc) {
|
||||
/* Set resources */
|
||||
if (flags & LOGIN_SETRESOURCES)
|
||||
setclassresources(lc);
|
||||
/* See if there's a umask override */
|
||||
if (flags & LOGIN_SETUMASK)
|
||||
mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask);
|
||||
/* Set paths */
|
||||
if (flags & LOGIN_SETPATH)
|
||||
setclassenvironment(lc, pwd, 1);
|
||||
/* Set environment */
|
||||
if (flags & LOGIN_SETENV)
|
||||
setclassenvironment(lc, pwd, 0);
|
||||
}
|
||||
return mymask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* setusercontext()
|
||||
*
|
||||
* Given a login class <lc> and a user in <pwd>, with a uid <uid>,
|
||||
* set the context as in setclasscontext(). <flags> controls which
|
||||
* values are set.
|
||||
*
|
||||
* The difference between setclasscontext() and setusercontext() is
|
||||
* that the former sets things up for an already-existing process,
|
||||
* while the latter sets things up from a root context. Such as might
|
||||
* be called from login(1).
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
|
||||
{
|
||||
quad_t p;
|
||||
mode_t mymask;
|
||||
login_cap_t *llc = NULL;
|
||||
struct rtprio rtp;
|
||||
int error;
|
||||
|
||||
if (lc == NULL) {
|
||||
if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL)
|
||||
llc = lc; /* free this when we're done */
|
||||
}
|
||||
|
||||
if (flags & LOGIN_SETPATH)
|
||||
pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH;
|
||||
|
||||
/* we need a passwd entry to set these */
|
||||
if (pwd == NULL)
|
||||
flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN | LOGIN_SETMAC);
|
||||
|
||||
/* Set the process priority */
|
||||
if (flags & LOGIN_SETPRIORITY) {
|
||||
p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);
|
||||
|
||||
if(p > PRIO_MAX) {
|
||||
rtp.type = RTP_PRIO_IDLE;
|
||||
rtp.prio = p - PRIO_MAX - 1;
|
||||
p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p;
|
||||
if(rtprio(RTP_SET, 0, &rtp))
|
||||
syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
|
||||
pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS);
|
||||
} else if(p < PRIO_MIN) {
|
||||
rtp.type = RTP_PRIO_REALTIME;
|
||||
rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX);
|
||||
p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p;
|
||||
if(rtprio(RTP_SET, 0, &rtp))
|
||||
syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
|
||||
pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS);
|
||||
} else {
|
||||
if (setpriority(PRIO_PROCESS, 0, (int)p) != 0)
|
||||
syslog(LOG_WARNING, "setpriority '%s' (%s): %m",
|
||||
pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup the user's group permissions */
|
||||
if (flags & LOGIN_SETGROUP) {
|
||||
if (setgid(pwd->pw_gid) != 0) {
|
||||
syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid);
|
||||
login_close(llc);
|
||||
return -1;
|
||||
}
|
||||
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
|
||||
syslog(LOG_ERR, "initgroups(%s,%lu): %m", pwd->pw_name,
|
||||
(u_long)pwd->pw_gid);
|
||||
login_close(llc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the user's MAC label. */
|
||||
if ((flags & LOGIN_SETMAC) && mac_is_present(NULL) == 1) {
|
||||
const char *label_string;
|
||||
mac_t label;
|
||||
|
||||
label_string = login_getcapstr(lc, "label", NULL, NULL);
|
||||
if (label_string != NULL) {
|
||||
if (mac_from_text(&label, label_string) == -1) {
|
||||
syslog(LOG_ERR, "mac_from_text('%s') for %s: %m",
|
||||
pwd->pw_name, label_string);
|
||||
return -1;
|
||||
}
|
||||
if (mac_set_proc(label) == -1)
|
||||
error = errno;
|
||||
else
|
||||
error = 0;
|
||||
mac_free(label);
|
||||
if (error != 0) {
|
||||
syslog(LOG_ERR, "mac_set_proc('%s') for %s: %s",
|
||||
label_string, pwd->pw_name, strerror(error));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the sessions login */
|
||||
if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) {
|
||||
syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name);
|
||||
login_close(llc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0;
|
||||
mymask = setlogincontext(lc, pwd, mymask, flags);
|
||||
login_close(llc);
|
||||
|
||||
/* This needs to be done after anything that needs root privs */
|
||||
if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
|
||||
syslog(LOG_ERR, "setuid(%lu): %m", (u_long)uid);
|
||||
return -1; /* Paranoia again */
|
||||
}
|
||||
|
||||
/*
|
||||
* Now, we repeat some of the above for the user's private entries
|
||||
*/
|
||||
if ((lc = login_getuserclass(pwd)) != NULL) {
|
||||
mymask = setlogincontext(lc, pwd, mymask, flags);
|
||||
login_close(lc);
|
||||
}
|
||||
|
||||
/* Finally, set any umask we've found */
|
||||
if (flags & LOGIN_SETUMASK)
|
||||
umask(mymask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Brian Fundakowski Feldman
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login_crypt.c,v 1.5 2002/04/08 11:04:56 ru Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <login_cap.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char *
|
||||
login_setcryptfmt(login_cap_t *lc, const char *def, const char *error) {
|
||||
const char *cipher;
|
||||
|
||||
cipher = login_getcapstr(lc, "passwd_format", def, NULL);
|
||||
if (getenv("CRYPT_DEBUG") != NULL)
|
||||
fprintf(stderr, "login_setcryptfmt: "
|
||||
"passwd_format = %s\n", cipher);
|
||||
if (cipher == NULL)
|
||||
return (error);
|
||||
if (!crypt_set_format(cipher))
|
||||
return (error);
|
||||
return (cipher);
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
.\" Copyright (c) 1995 David Nugent <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
.\" is permitted provided this notation is included.
|
||||
.\" 4. Absolutely no warranty of function or purpose is made by the author
|
||||
.\" David Nugent.
|
||||
.\" 5. Modifications may be freely made to this file providing the above
|
||||
.\" conditions are met.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login_ok.3,v 1.14 2004/07/02 23:52:19 ru Exp $
|
||||
.\"
|
||||
.Dd January 2, 1997
|
||||
.Os
|
||||
.Dt LOGIN_OK 3
|
||||
.Sh NAME
|
||||
.Nm auth_ttyok ,
|
||||
.Nm auth_hostok ,
|
||||
.Nm auth_timeok
|
||||
.Nd functions for checking login class based login restrictions
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In time.h
|
||||
.In login_cap.h
|
||||
.Ft int
|
||||
.Fn auth_ttyok "login_cap_t *lc" "const char *tty"
|
||||
.Ft int
|
||||
.Fn auth_hostok "login_cap_t *lc" "const char *host" "char const *ip"
|
||||
.Ft int
|
||||
.Fn auth_timeok "login_cap_t *lc" "time_t t"
|
||||
.Sh DESCRIPTION
|
||||
This set of functions checks to see if login is allowed based on login
|
||||
class capability entries in the login database,
|
||||
.Xr login.conf 5 .
|
||||
.Pp
|
||||
The
|
||||
.Fn auth_ttyok
|
||||
function checks to see if the named tty is available to users of a specific
|
||||
class, and is either in the
|
||||
.Em ttys.allow
|
||||
access list, and not in
|
||||
the
|
||||
.Em ttys.deny
|
||||
access list.
|
||||
An empty
|
||||
.Em ttys.allow
|
||||
list (or if no such capability exists for
|
||||
the give login class) logins via any tty device are allowed unless
|
||||
the
|
||||
.Em ttys.deny
|
||||
list exists and is non-empty, and the device or its
|
||||
tty group (see
|
||||
.Xr ttys 5 )
|
||||
is not in the list.
|
||||
Access to ttys may be allowed or restricted specifically by tty device
|
||||
name, a device name which includes a wildcard (e.g.\& ttyD* or cuaD*),
|
||||
or may name a ttygroup, when group=<name> tags have been assigned in
|
||||
.Pa /etc/ttys .
|
||||
Matching of ttys and ttygroups is case sensitive.
|
||||
Passing a
|
||||
.Dv NULL
|
||||
or empty string as the
|
||||
.Ar tty
|
||||
parameter causes the function to return a non-zero value.
|
||||
.Pp
|
||||
The
|
||||
.Fn auth_hostok
|
||||
function checks for any host restrictions for remote logins.
|
||||
The function checks on both a host name and IP address (given in its
|
||||
text form, typically n.n.n.n) against the
|
||||
.Em host.allow
|
||||
and
|
||||
.Em host.deny
|
||||
login class capabilities.
|
||||
As with ttys and their groups, wildcards and character classes may be
|
||||
used in the host allow and deny capability records.
|
||||
The
|
||||
.Xr fnmatch 3
|
||||
function is used for matching, and the matching on hostnames is case
|
||||
insensitive.
|
||||
Note that this function expects that the hostname is fully expanded
|
||||
(i.e., the local domain name added if necessary) and the IP address
|
||||
is in its canonical form.
|
||||
No hostname or address lookups are attempted.
|
||||
.Pp
|
||||
It is possible to call this function with either the hostname or
|
||||
the IP address missing (i.e.\&
|
||||
.Dv NULL )
|
||||
and matching will be performed
|
||||
only on the basis of the parameter given.
|
||||
Passing
|
||||
.Dv NULL
|
||||
or empty strings in both parameters will result in
|
||||
a non-zero return value.
|
||||
.Pp
|
||||
The
|
||||
.Fn auth_timeok
|
||||
function checks to see that a given time value is within the
|
||||
.Em times.allow
|
||||
login class capability and not within the
|
||||
.Em times.deny
|
||||
access lists.
|
||||
An empty or non-existent
|
||||
.Em times.allow
|
||||
list allows access at any
|
||||
time, except if a given time is falls within a period in the
|
||||
.Em times.deny
|
||||
list.
|
||||
The format of time period records contained in both
|
||||
.Em times.allow
|
||||
and
|
||||
.Em times.deny
|
||||
capability fields is explained in detail in the
|
||||
.Xr login_times 3
|
||||
manual page.
|
||||
.Sh RETURN VALUES
|
||||
A non-zero return value from any of these functions indicates that
|
||||
login access is granted.
|
||||
A zero return value means either that the item being tested is not
|
||||
in the
|
||||
.Em allow
|
||||
access list, or is within the
|
||||
.Em deny
|
||||
access list.
|
||||
.Sh SEE ALSO
|
||||
.Xr getcap 3 ,
|
||||
.Xr login_cap 3 ,
|
||||
.Xr login_class 3 ,
|
||||
.Xr login_times 3 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr termcap 5
|
||||
@@ -0,0 +1,250 @@
|
||||
/*-
|
||||
* Copyright (c) 1996 by
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* 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.
|
||||
* 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
* is permitted provided this notation is included.
|
||||
* 4. Absolutely no warranty of function or purpose is made by the authors.
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*
|
||||
* Support allow/deny lists in login class capabilities
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login_ok.c,v 1.12 2006/01/16 00:28:11 rwatson Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/param.h>
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <login_cap.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ttyent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/* -- support functions -- */
|
||||
|
||||
/*
|
||||
* login_strinlist()
|
||||
* This function is intentionally public - reused by TAS.
|
||||
* Returns TRUE (non-zero) if a string matches a pattern
|
||||
* in a given array of patterns. 'flags' is passed directly
|
||||
* to fnmatch(3).
|
||||
*/
|
||||
|
||||
int
|
||||
login_strinlist(const char **list, char const *str, int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (str != NULL && *str != '\0') {
|
||||
int i = 0;
|
||||
|
||||
while (rc == 0 && list[i] != NULL)
|
||||
rc = fnmatch(list[i++], str, flags) == 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_str2inlist()
|
||||
* Locate either or two strings in a given list
|
||||
*/
|
||||
|
||||
int
|
||||
login_str2inlist(const char **ttlst, const char *str1, const char *str2, int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (login_strinlist(ttlst, str1, flags))
|
||||
rc = 1;
|
||||
else if (login_strinlist(ttlst, str2, flags))
|
||||
rc = 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_timelist()
|
||||
* This function is intentionally public - reused by TAS.
|
||||
* Returns an allocated list of time periods given an array
|
||||
* of time periods in ascii form.
|
||||
*/
|
||||
|
||||
login_time_t *
|
||||
login_timelist(login_cap_t *lc, char const *cap, int *ltno,
|
||||
login_time_t **ltptr)
|
||||
{
|
||||
int j = 0;
|
||||
struct login_time *lt = NULL;
|
||||
const char **tl;
|
||||
|
||||
if ((tl = login_getcaplist(lc, cap, NULL)) != NULL) {
|
||||
|
||||
while (tl[j++] != NULL)
|
||||
;
|
||||
if (*ltno >= j)
|
||||
lt = *ltptr;
|
||||
else if ((lt = realloc(*ltptr, j * sizeof(struct login_time))) != NULL) {
|
||||
*ltno = j;
|
||||
*ltptr = lt;
|
||||
}
|
||||
if (lt != NULL) {
|
||||
int i = 0;
|
||||
|
||||
for (--j; i < j; i++)
|
||||
lt[i] = parse_lt(tl[i]);
|
||||
lt[i].lt_dow = LTM_NONE;
|
||||
}
|
||||
}
|
||||
return lt;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_ttyok()
|
||||
* This function is a variation of auth_ttyok(), but it checks two
|
||||
* arbitrary capability lists not necessarily related to access.
|
||||
* This hook is provided for the accounted/exclude accounting lists.
|
||||
*/
|
||||
|
||||
int
|
||||
login_ttyok(login_cap_t *lc, const char *tty, const char *allowcap,
|
||||
const char *denycap)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
if (lc != NULL && tty != NULL && *tty != '\0') {
|
||||
struct ttyent *te;
|
||||
char *grp;
|
||||
const char **ttl;
|
||||
|
||||
te = getttynam(tty); /* Need group name */
|
||||
grp = te ? te->ty_group : NULL;
|
||||
ttl = login_getcaplist(lc, allowcap, NULL);
|
||||
|
||||
if (ttl != NULL && !login_str2inlist(ttl, tty, grp, 0))
|
||||
rc = 0; /* tty or ttygroup not in allow list */
|
||||
else {
|
||||
|
||||
ttl = login_getcaplist(lc, denycap, NULL);
|
||||
if (ttl != NULL && login_str2inlist(ttl, tty, grp, 0))
|
||||
rc = 0; /* tty or ttygroup in deny list */
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_ttyok()
|
||||
* Determine whether or not login on a tty is accessible for
|
||||
* a login class
|
||||
*/
|
||||
|
||||
int
|
||||
auth_ttyok(login_cap_t *lc, const char * tty)
|
||||
{
|
||||
return login_ttyok(lc, tty, "ttys.allow", "ttys.deny");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* login_hostok()
|
||||
* This function is a variation of auth_hostok(), but it checks two
|
||||
* arbitrary capability lists not necessarily related to access.
|
||||
* This hook is provided for the accounted/exclude accounting lists.
|
||||
*/
|
||||
|
||||
int
|
||||
login_hostok(login_cap_t *lc, const char *host, const char *ip,
|
||||
const char *allowcap, const char *denycap)
|
||||
{
|
||||
int rc = 1; /* Default is ok */
|
||||
|
||||
if (lc != NULL &&
|
||||
((host != NULL && *host != '\0') || (ip != NULL && *ip != '\0'))) {
|
||||
const char **hl;
|
||||
|
||||
hl = login_getcaplist(lc, allowcap, NULL);
|
||||
if (hl != NULL && !login_str2inlist(hl, host, ip, FNM_CASEFOLD))
|
||||
rc = 0; /* host or IP not in allow list */
|
||||
else {
|
||||
|
||||
hl = login_getcaplist(lc, denycap, NULL);
|
||||
if (hl != NULL && login_str2inlist(hl, host, ip, FNM_CASEFOLD))
|
||||
rc = 0; /* host or IP in deny list */
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_hostok()
|
||||
* Determine whether or not login from a host is ok
|
||||
*/
|
||||
|
||||
int
|
||||
auth_hostok(login_cap_t *lc, const char *host, const char *ip)
|
||||
{
|
||||
return login_hostok(lc, host, ip, "host.allow", "host.deny");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* auth_timeok()
|
||||
* Determine whether or not login is ok at a given time
|
||||
*/
|
||||
|
||||
int
|
||||
auth_timeok(login_cap_t *lc, time_t t)
|
||||
{
|
||||
int rc = 1; /* Default is ok */
|
||||
|
||||
if (lc != NULL && t != (time_t)0 && t != (time_t)-1) {
|
||||
struct tm *tptr;
|
||||
|
||||
static int ltimesno = 0;
|
||||
static struct login_time *ltimes = NULL;
|
||||
|
||||
if ((tptr = localtime(&t)) != NULL) {
|
||||
struct login_time *lt;
|
||||
|
||||
lt = login_timelist(lc, "times.allow", <imesno, <imes);
|
||||
if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
|
||||
rc = 0; /* not in allowed times list */
|
||||
else {
|
||||
|
||||
lt = login_timelist(lc, "times.deny", <imesno, <imes);
|
||||
if (lt != NULL && in_ltms(lt, tptr, NULL) != -1)
|
||||
rc = 0; /* in deny times list */
|
||||
}
|
||||
if (ltimes) {
|
||||
free(ltimes);
|
||||
ltimes = NULL;
|
||||
ltimesno = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
.\" Copyright (c) 1995 David Nugent <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, is permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice immediately at the beginning of the file, without modification,
|
||||
.\" 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.
|
||||
.\" 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
.\" is permitted provided this notation is included.
|
||||
.\" 4. Absolutely no warranty of function or purpose is made by the author
|
||||
.\" David Nugent.
|
||||
.\" 5. Modifications may be freely made to this file providing the above
|
||||
.\" conditions are met.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login_times.3,v 1.15 2004/07/02 23:52:19 ru Exp $
|
||||
.\"
|
||||
.Dd January 2, 1997
|
||||
.Os
|
||||
.Dt LOGIN_TIMES 3
|
||||
.Sh NAME
|
||||
.Nm parse_lt ,
|
||||
.Nm in_ltm ,
|
||||
.Nm in_ltms
|
||||
.Nd functions for parsing and checking login time periods
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In time.h
|
||||
.In login_cap.h
|
||||
.Ft login_time_t
|
||||
.Fn parse_lt "const char *str"
|
||||
.Ft int
|
||||
.Fn in_ltm "const login_time_t *lt" "struct tm *t" "time_t *ends"
|
||||
.Ft int
|
||||
.Fn in_ltms "const login_time_t *lt" "struct tm *t" "time_t *ends"
|
||||
.Sh DESCRIPTION
|
||||
This set of functions may be used for parsing and checking login and
|
||||
session times against a predefined list of allowed login times as
|
||||
used in
|
||||
.Xr login.conf 5 .
|
||||
.Pp
|
||||
The format of allowed and disallowed session times specified in the
|
||||
.Ar times.allow
|
||||
and
|
||||
.Ar times.deny
|
||||
capability fields in a login class are comprised of a prefix which
|
||||
specifies one or more 2- or 3-character day codes, followed by
|
||||
a start and end time in 24 hour format separated by a hyphen.
|
||||
Day codes may be concatenated together to select specific days, or
|
||||
the special mnemonics "Any" and "All" (for any/all days of the week),
|
||||
"Wk" for any day of the week (excluding Saturdays and Sundays) and
|
||||
"Wd" for any weekend day may be used.
|
||||
.Pp
|
||||
For example, the following time period:
|
||||
.Dl MoThFrSa1400-2200
|
||||
is interpreted as Monday, Thursday through Saturday between the hours
|
||||
of 2pm and 10pm.
|
||||
.Dl Wd0600-1800
|
||||
means Saturday and Sunday, between the hours of 6am through 6pm, and
|
||||
.Dl Any0400-1600
|
||||
means any day of the week, between 4am and 4pm.
|
||||
.Pp
|
||||
Note that all time periods reference system local time.
|
||||
.Pp
|
||||
The
|
||||
.Fn parse_lt
|
||||
function converts the ASCII representation of a time period into
|
||||
a structure of type
|
||||
.Ft login_time_t .
|
||||
This is defined as:
|
||||
.Bd -literal
|
||||
typedef struct login_time
|
||||
{
|
||||
u_short lt_start; /* Start time */
|
||||
u_short lt_end; /* End time */
|
||||
u_char lt_dow; /* Days of week */
|
||||
} login_time_t;
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Ar lt_start
|
||||
and
|
||||
.Ar lt_end
|
||||
fields contain the number of minutes past midnight at which the
|
||||
described period begins and ends.
|
||||
The
|
||||
.Ar lt_dow
|
||||
field is a bit field, containing one bit for each day of the week
|
||||
and one bit unused.
|
||||
A series
|
||||
.Em LTM_*
|
||||
macros may be used for testing bits individually and in combination.
|
||||
If no bits are set in this field - i.e., it contains the value
|
||||
.Em LTM_NONE
|
||||
- then the entire period is assumed invalid.
|
||||
This is used as a convention to mark the termination of an array
|
||||
of login_time_t values.
|
||||
If
|
||||
.Fn parse_lt
|
||||
returns a
|
||||
.Ar login_time_t
|
||||
with
|
||||
.Ar lt_dow
|
||||
equal to
|
||||
.Em LTM_NONE
|
||||
then a parsing error was encountered.
|
||||
.Pp
|
||||
The remaining functions provide the ability to test a given time_t or
|
||||
struct tm value against a specific time period or array of time
|
||||
periods.
|
||||
The
|
||||
.Fn in_ltm
|
||||
function determines whether the given time described by the struct tm
|
||||
passed as the second parameter falls within the period described
|
||||
by the first parameter.
|
||||
A boolean value is returned, indicating whether or not the time
|
||||
specified falls within the period.
|
||||
If the time does fall within the time period, and the third
|
||||
parameter to the function is not NULL, the time at which the
|
||||
period ends relative to the time passed is returned.
|
||||
.Pp
|
||||
The
|
||||
.Fn in_ltms
|
||||
function is similar to
|
||||
.Fn in_ltm
|
||||
except that the first parameter must be a pointer to an array
|
||||
of login_time_t objects, which is up to LC_MAXTIMES (64)
|
||||
elements in length, and terminated by an element with its
|
||||
.Ar lt_dow
|
||||
field set to
|
||||
.Em LTM_NONE .
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn parse_lt
|
||||
function returns a filled in structure of type login_time_t containing the
|
||||
parsed time period.
|
||||
If a parsing error occurs, the lt_dow field is set to
|
||||
.Em LTM_NONE
|
||||
(i.e., 0).
|
||||
.Pp
|
||||
The
|
||||
.Fn in_ltm
|
||||
function returns non-zero if the given time falls within the period described
|
||||
by the login_time_t passed as the first parameter.
|
||||
.Pp
|
||||
The
|
||||
.Fn in_ltms
|
||||
function returns the index of the first time period found in which the given
|
||||
time falls, or -1 if none of them apply.
|
||||
.Sh SEE ALSO
|
||||
.Xr getcap 3 ,
|
||||
.Xr login_cap 3 ,
|
||||
.Xr login_class 3 ,
|
||||
.Xr login.conf 5 ,
|
||||
.Xr termcap 5
|
||||
@@ -0,0 +1,161 @@
|
||||
/*-
|
||||
* Copyright (c) 1996 by
|
||||
* David Nugent <davidn@blaze.net.au>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* 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.
|
||||
* 3. This work was done expressly for inclusion into FreeBSD. Other use
|
||||
* is permitted provided this notation is included.
|
||||
* 4. Absolutely no warranty of function or purpose is made by the authors.
|
||||
* 5. Modifications may be freely made to this file providing the above
|
||||
* conditions are met.
|
||||
*
|
||||
* Login period parsing and comparison functions.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login_times.c,v 1.11 2006/01/16 11:54:07 rwatson Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <login_cap.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *dw;
|
||||
u_char cn;
|
||||
u_char fl;
|
||||
} dws[] =
|
||||
{
|
||||
{ "su", 2, LTM_SUN }, { "mo", 2, LTM_MON }, { "tu", 2, LTM_TUE },
|
||||
{ "we", 2, LTM_WED }, { "th", 2, LTM_THU }, { "fr", 2, LTM_FRI },
|
||||
{ "sa", 2, LTM_SAT }, { "any",3, LTM_ANY }, { "all",3, LTM_ANY },
|
||||
{ "wk", 2, LTM_WK }, { "wd", 2, LTM_WD }, { NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static char *
|
||||
parse_time(char * ptr, u_short * t)
|
||||
{
|
||||
u_short val;
|
||||
|
||||
for (val = 0; *ptr && isdigit(*ptr); ptr++)
|
||||
val = (u_short)(val * 10 + (*ptr - '0'));
|
||||
|
||||
*t = (u_short)((val / 100) * 60 + (val % 100));
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
login_time_t
|
||||
parse_lt(const char * str)
|
||||
{
|
||||
login_time_t t;
|
||||
|
||||
memset(&t, 0, sizeof t);
|
||||
t.lt_dow = LTM_NONE;
|
||||
if (str && *str && strcmp(str, "Never") != 0 && strcmp(str, "None") != 0) {
|
||||
int i;
|
||||
login_time_t m = t;
|
||||
char *p;
|
||||
char buf[64];
|
||||
|
||||
/* Make local copy and force lowercase to simplify parsing */
|
||||
p = strncpy(buf, str, sizeof buf);
|
||||
buf[sizeof buf - 1] = '\0';
|
||||
for (i = 0; buf[i]; i++)
|
||||
buf[i] = (char)tolower(buf[i]);
|
||||
|
||||
while (isalpha(*p)) {
|
||||
|
||||
i = 0;
|
||||
while (dws[i].dw && strncmp(p, dws[i].dw, dws[i].cn) != 0)
|
||||
i++;
|
||||
if (dws[i].dw == NULL)
|
||||
break;
|
||||
m.lt_dow |= dws[i].fl;
|
||||
p += dws[i].cn;
|
||||
}
|
||||
|
||||
if (m.lt_dow == LTM_NONE) /* No (valid) prefix, assume any */
|
||||
m.lt_dow |= LTM_ANY;
|
||||
|
||||
if (isdigit(*p))
|
||||
p = parse_time(p, &m.lt_start);
|
||||
else
|
||||
m.lt_start = 0;
|
||||
if (*p == '-')
|
||||
p = parse_time(++p, &m.lt_end);
|
||||
else
|
||||
m.lt_end = 1440;
|
||||
|
||||
t = m;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
in_ltm(const login_time_t * ltm, struct tm * tt, time_t * ends)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (tt != NULL) {
|
||||
/* First, examine the day of the week */
|
||||
if ((u_char)(0x01 << tt->tm_wday) & ltm->lt_dow) {
|
||||
/* Convert `current' time to minute of the day */
|
||||
u_short now = (u_short)((tt->tm_hour * 60) + tt->tm_min);
|
||||
|
||||
if (tt->tm_sec > 30)
|
||||
++now;
|
||||
if (now >= ltm->lt_start && now < ltm->lt_end) {
|
||||
rc = 2;
|
||||
if (ends != NULL) {
|
||||
/* If requested, return ending time for this period */
|
||||
tt->tm_hour = (int)(ltm->lt_end / 60);
|
||||
tt->tm_min = (int)(ltm->lt_end % 60);
|
||||
*ends = mktime(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
in_lt(const login_time_t * ltm, time_t * t)
|
||||
{
|
||||
return in_ltm(ltm, localtime(t), t);
|
||||
}
|
||||
|
||||
int
|
||||
in_ltms(const login_time_t * ltm, struct tm * tm, time_t * t)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < LC_MAXTIMES && ltm[i].lt_dow != LTM_NONE) {
|
||||
if (in_ltm(ltm + i, tm, t))
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
in_lts(const login_time_t * ltm, time_t * t)
|
||||
{
|
||||
return in_ltms(ltm, localtime(t), t);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1996 Joerg Wunsch
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/login_tty.3,v 1.10 2004/07/02 23:52:19 ru Exp $
|
||||
.\" "
|
||||
.Dd December 29, 1996
|
||||
.Os
|
||||
.Dt LOGIN_TTY 3
|
||||
.Sh NAME
|
||||
.Nm login_tty
|
||||
.Nd prepare a tty for a new login session
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn login_tty "int fd"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn login_tty
|
||||
prepares a terminal for a new login session.
|
||||
The file descriptor
|
||||
.Ar fd
|
||||
passed to
|
||||
.Fn login_tty
|
||||
must be opened for reading and writing on a terminal device.
|
||||
It will be
|
||||
made the controlling terminal for the calling process, after allocating
|
||||
a new session with
|
||||
.Xr setsid 2 .
|
||||
This terminal device will also be made the standard input, standard output,
|
||||
and standard error output of the calling process.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn login_tty
|
||||
function returns -1 if it could not make the device referenced by
|
||||
.Ar fd
|
||||
the controlling terminal of the calling process, and 0 otherwise.
|
||||
.Sh SEE ALSO
|
||||
.Xr dup2 2 ,
|
||||
.Xr ioctl 2 ,
|
||||
.Xr setsid 2 ,
|
||||
.Xr tty 4
|
||||
@@ -0,0 +1,62 @@
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/login_tty.c,v 1.9 2003/10/18 10:04:16 markm Exp $");
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)login_tty.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <libutil.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
login_tty(int fd)
|
||||
{
|
||||
(void) setsid();
|
||||
if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1)
|
||||
return (-1);
|
||||
(void) dup2(fd, 0);
|
||||
(void) dup2(fd, 1);
|
||||
(void) dup2(fd, 2);
|
||||
if (fd > 2)
|
||||
(void) close(fd);
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1996 Joerg Wunsch
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/logout.3,v 1.12 2004/07/02 23:52:19 ru Exp $
|
||||
.\" "
|
||||
.Dd December 29, 1996
|
||||
.Os
|
||||
.Dt LOGOUT 3
|
||||
.Sh NAME
|
||||
.Nm logout
|
||||
.Nd remove an entry from the utmp file
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn logout "const char *line"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn logout
|
||||
searches the
|
||||
.Xr utmp 5
|
||||
file for the slot described by
|
||||
.Ar line
|
||||
(usually a tty name).
|
||||
If such a slot could be found, it will be updated
|
||||
with a record where the
|
||||
.Em name
|
||||
and
|
||||
.Em host
|
||||
fields are empty, and the time stamp field is updated to the current time.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn logout
|
||||
function returns 1 if the slot described by
|
||||
.Ar line
|
||||
has been found and updated, 0 otherwise.
|
||||
.Sh SEE ALSO
|
||||
.Xr login 3 ,
|
||||
.Xr utmp 5 ,
|
||||
.Xr wtmp 5
|
||||
.Sh BUGS
|
||||
The calling interface of
|
||||
.Fn logout
|
||||
is inconsistent with that of
|
||||
.Xr login 3 .
|
||||
@@ -0,0 +1,78 @@
|
||||
/*-
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/logout.c,v 1.11 2003/10/18 10:04:16 markm Exp $");
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)logout.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <libutil.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <timeconv.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
typedef struct utmp UTMP;
|
||||
|
||||
int
|
||||
logout(const char *line)
|
||||
{
|
||||
int fd;
|
||||
UTMP ut;
|
||||
int rval;
|
||||
|
||||
if ((fd = open(_PATH_UTMP, O_RDWR, 0)) < 0)
|
||||
return(0);
|
||||
rval = 0;
|
||||
while (read(fd, &ut, sizeof(UTMP)) == sizeof(UTMP)) {
|
||||
if (!ut.ut_name[0] || strncmp(ut.ut_line, line, UT_LINESIZE))
|
||||
continue;
|
||||
bzero(ut.ut_name, UT_NAMESIZE);
|
||||
bzero(ut.ut_host, UT_HOSTSIZE);
|
||||
ut.ut_time = _time_to_time32(time(NULL));
|
||||
(void)lseek(fd, -(off_t)sizeof(UTMP), L_INCR);
|
||||
(void)write(fd, &ut, sizeof(UTMP));
|
||||
rval = 1;
|
||||
}
|
||||
(void)close(fd);
|
||||
return(rval);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1996 Joerg Wunsch
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/logwtmp.3,v 1.11 2001/10/11 11:02:50 yar Exp $
|
||||
.\" "
|
||||
.Dd December 29, 1996
|
||||
.Os
|
||||
.Dt LOGWTMP 3
|
||||
.Sh NAME
|
||||
.Nm logwtmp
|
||||
.Nd append a new record to the wtmp file
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In libutil.h
|
||||
.Ft void
|
||||
.Fn logwtmp "const char *line" "const char *name" "const char *host"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn logwtmp
|
||||
tries to append a new record to the
|
||||
.Xr wtmp 5
|
||||
file, using the provided arguments
|
||||
.Ar line ,
|
||||
.Ar name ,
|
||||
and
|
||||
.Ar host ,
|
||||
and the current time.
|
||||
.Pp
|
||||
If the length of the hostname string
|
||||
.Ar host
|
||||
is longer than what would fit into the hostname field of the
|
||||
.Xr wtmp 5
|
||||
file, it will first be attempted to convert it into a numerical IP
|
||||
address using
|
||||
.Xr gethostbyname 3 .
|
||||
Failing this, the hostname will be recorded as
|
||||
.Qq invalid hostname .
|
||||
.Pp
|
||||
The calling process must have permission to write to the
|
||||
.Xr wtmp 5
|
||||
file.
|
||||
.Sh RETURN VALUES
|
||||
None.
|
||||
.Sh SEE ALSO
|
||||
.Xr gethostbyname 3 ,
|
||||
.Xr login 3 ,
|
||||
.Xr wtmp 5
|
||||
@@ -0,0 +1,104 @@
|
||||
/*-
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/logwtmp.c,v 1.20 2005/05/13 16:31:09 ume Exp $");
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <libutil.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <timeconv.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
|
||||
void
|
||||
logwtmp(const char *line, const char *name, const char *host)
|
||||
{
|
||||
struct utmp ut;
|
||||
struct stat buf;
|
||||
char fullhost[MAXHOSTNAMELEN];
|
||||
int fd;
|
||||
|
||||
strncpy(fullhost, host, sizeof(fullhost) - 1);
|
||||
fullhost[sizeof(fullhost) - 1] = '\0';
|
||||
trimdomain(fullhost, UT_HOSTSIZE);
|
||||
host = fullhost;
|
||||
|
||||
if (strlen(host) > UT_HOSTSIZE) {
|
||||
int error;
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
bzero(&hints, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
error = getaddrinfo(host, NULL, &hints, &res);
|
||||
if (error != 0 || res->ai_addr == NULL)
|
||||
host = "invalid hostname";
|
||||
else {
|
||||
error = getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||
fullhost, strlen(fullhost), NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
if (error != 0) {
|
||||
fprintf(stderr, "%d", error);
|
||||
host = "invalid hostname";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
|
||||
return;
|
||||
if (fstat(fd, &buf) == 0) {
|
||||
(void) strncpy(ut.ut_line, line, sizeof(ut.ut_line));
|
||||
(void) strncpy(ut.ut_name, name, sizeof(ut.ut_name));
|
||||
(void) strncpy(ut.ut_host, host, sizeof(ut.ut_host));
|
||||
ut.ut_time = _time_to_time32(time(NULL));
|
||||
if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
|
||||
sizeof(struct utmp))
|
||||
(void) ftruncate(fd, buf.st_size);
|
||||
}
|
||||
(void) close(fd);
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
.\" Copyright (c) 2005 Pawel Jakub Dawidek <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/pidfile.3,v 1.5 2006/03/04 15:20:28 keramida Exp $
|
||||
.\"
|
||||
.Dd August 22, 2005
|
||||
.Dt PIDFILE 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm pidfile_open ,
|
||||
.Nm pidfile_write ,
|
||||
.Nm pidfile_close ,
|
||||
.Nm pidfile_remove
|
||||
.Nd "library for PID files handling"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/param.h
|
||||
.In libutil.h
|
||||
.Ft "struct pidfh *"
|
||||
.Fn pidfile_open "const char *path" "mode_t mode" "pid_t *pidptr"
|
||||
.Ft int
|
||||
.Fn pidfile_write "struct pidfh *pfh"
|
||||
.Ft int
|
||||
.Fn pidfile_close "struct pidfh *pfh"
|
||||
.Ft int
|
||||
.Fn pidfile_remove "struct pidfh *pfh"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm pidfile
|
||||
family of functions allows daemons to handle PID files.
|
||||
It uses
|
||||
.Xr flock 2
|
||||
to lock a pidfile and detect already running daemons.
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_open
|
||||
function opens (or creates) a file specified by the
|
||||
.Fa path
|
||||
argument and locks it with the
|
||||
.Xr flock 2
|
||||
system call.
|
||||
If a file can not be locked, a PID of an already running daemon is returned in
|
||||
the
|
||||
.Fa pidptr
|
||||
argument (if it is not
|
||||
.Dv NULL ) .
|
||||
The function does not write process' PID into the file here, so it can be
|
||||
used before
|
||||
.Fn fork Ns ing
|
||||
and exit with a proper error message when needed.
|
||||
If the
|
||||
.Fa path
|
||||
argument is
|
||||
.Dv NULL ,
|
||||
.Pa /var/run/ Ns Ao Va progname Ac Ns Pa .pid
|
||||
file will be used.
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_write
|
||||
function writes process' PID into a previously opened file.
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_close
|
||||
function closes a pidfile.
|
||||
It should be used after daemon
|
||||
.Fn fork Ns s
|
||||
to start a child process.
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_remove
|
||||
function closes and removes a pidfile.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn pidfile_open
|
||||
function returns a valid pointer to a
|
||||
.Vt pidfh
|
||||
structure on success, or
|
||||
.Dv NULL
|
||||
if an error occurs.
|
||||
If an error occurs,
|
||||
.Va errno
|
||||
will be set.
|
||||
.Rv -std pidfile_write pidfile_close pidfile_remove
|
||||
.Sh EXAMPLES
|
||||
The following example shows in which order these functions should be used.
|
||||
Note that it is safe to pass
|
||||
.Dv NULL
|
||||
to
|
||||
.Fn pidfile_write ,
|
||||
.Fn pidfile_remove
|
||||
and
|
||||
.Fn pidfile_close
|
||||
functions.
|
||||
.Bd -literal
|
||||
struct pidfh *pfh;
|
||||
pid_t otherpid, childpid;
|
||||
|
||||
pfh = pidfile_open("/var/run/daemon.pid", 0600, &otherpid);
|
||||
if (pfh == NULL) {
|
||||
if (errno == EEXIST) {
|
||||
errx(EXIT_FAILURE, "Daemon already running, pid: %jd.",
|
||||
(intmax_t)otherpid);
|
||||
}
|
||||
/* If we cannot create pidfile from other reasons, only warn. */
|
||||
warn("Cannot open or create pidfile");
|
||||
}
|
||||
|
||||
if (daemon(0, 0) == -1) {
|
||||
warn("Cannot daemonize");
|
||||
pidfile_remove(pfh);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pidfile_write(pfh);
|
||||
|
||||
for (;;) {
|
||||
/* Do work. */
|
||||
childpid = fork();
|
||||
switch (childpid) {
|
||||
case -1:
|
||||
syslog(LOG_ERR, "Cannot fork(): %s.", strerror(errno));
|
||||
break;
|
||||
case 0:
|
||||
pidfile_close(pfh);
|
||||
/* Do child work. */
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_INFO, "Child %jd started.", (intmax_t)childpid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pidfile_remove(pfh);
|
||||
exit(EXIT_SUCCESS);
|
||||
.Ed
|
||||
.Sh ERRORS
|
||||
The
|
||||
.Fn pidfile_open
|
||||
function will fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EEXIST
|
||||
Some process already holds the lock on the given pidfile, meaning that a
|
||||
daemon is already running.
|
||||
.It Bq Er ENAMETOOLONG
|
||||
Specified pidfile's name is too long.
|
||||
.It Bq Er EINVAL
|
||||
Some process already holds the lock on the given pidfile, but PID read
|
||||
from there is invalid.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_open
|
||||
function may also fail and set
|
||||
.Va errno
|
||||
for any errors specified for the
|
||||
.Xr fstat 2 ,
|
||||
.Xr open 2 ,
|
||||
and
|
||||
.Xr read 2
|
||||
calls.
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_write
|
||||
function will fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EDOOFUS
|
||||
Improper function use.
|
||||
Probably called before
|
||||
.Fn pidfile_open .
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_write
|
||||
function may also fail and set
|
||||
.Va errno
|
||||
for any errors specified for the
|
||||
.Xr fstat 2 ,
|
||||
.Xr ftruncate 2 ,
|
||||
and
|
||||
.Xr write 2
|
||||
calls.
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_close
|
||||
function may fail and set
|
||||
.Va errno
|
||||
for any errors specified for the
|
||||
.Xr close 2
|
||||
and
|
||||
.Xr fstat 2
|
||||
calls.
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_remove
|
||||
function will fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EDOOFUS
|
||||
Improper function use.
|
||||
Probably called not from the process which made
|
||||
.Fn pidfile_write .
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn pidfile_remove
|
||||
function may also fail and set
|
||||
.Va errno
|
||||
for any errors specified for the
|
||||
.Xr close 2 ,
|
||||
.Xr flock 2 ,
|
||||
.Xr fstat 2 ,
|
||||
.Xr write 2 ,
|
||||
and
|
||||
.Xr unlink 2
|
||||
calls.
|
||||
.Sh SEE ALSO
|
||||
.Xr flock 2 ,
|
||||
.Xr open 2 ,
|
||||
.Xr daemon 3
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm pidfile
|
||||
functionality is based on ideas from
|
||||
.An John-Mark Gurney Aq [email protected] .
|
||||
.Pp
|
||||
The code and manual page was written by
|
||||
.An Pawel Jakub Dawidek Aq [email protected] .
|
||||
@@ -0,0 +1,244 @@
|
||||
/*-
|
||||
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/pidfile.c,v 1.3 2006/06/23 01:42:03 brian Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <libutil.h>
|
||||
|
||||
static int _pidfile_remove(struct pidfh *pfh, int freeit);
|
||||
|
||||
static int
|
||||
pidfile_verify(struct pidfh *pfh)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (pfh == NULL || pfh->pf_fd == -1)
|
||||
return (EDOOFUS);
|
||||
/*
|
||||
* Check remembered descriptor.
|
||||
*/
|
||||
if (fstat(pfh->pf_fd, &sb) == -1)
|
||||
return (errno);
|
||||
if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
|
||||
return (EDOOFUS);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
pidfile_read(const char *path, pid_t *pidptr)
|
||||
{
|
||||
char buf[16], *endptr;
|
||||
int error, fd, i;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return (errno);
|
||||
|
||||
i = read(fd, buf, sizeof(buf) - 1);
|
||||
error = errno; /* Remember errno in case close() wants to change it. */
|
||||
close(fd);
|
||||
if (i == -1)
|
||||
return (error);
|
||||
buf[i] = '\0';
|
||||
|
||||
*pidptr = strtol(buf, &endptr, 10);
|
||||
if (endptr != &buf[i])
|
||||
return (EINVAL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct pidfh *
|
||||
pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
|
||||
{
|
||||
struct pidfh *pfh;
|
||||
struct stat sb;
|
||||
int error, fd;
|
||||
|
||||
pfh = malloc(sizeof(*pfh));
|
||||
if (pfh == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (path == NULL) {
|
||||
snprintf(pfh->pf_path, sizeof(pfh->pf_path), "/var/run/%s.pid",
|
||||
getprogname());
|
||||
} else {
|
||||
strlcpy(pfh->pf_path, path, sizeof(pfh->pf_path));
|
||||
}
|
||||
if (strlen(pfh->pf_path) == sizeof(pfh->pf_path) - 1) {
|
||||
free(pfh);
|
||||
errno = ENAMETOOLONG;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the PID file and obtain exclusive lock.
|
||||
* We truncate PID file here only to remove old PID immediatelly,
|
||||
* PID file will be truncated again in pidfile_write(), so
|
||||
* pidfile_write() can be called multiple times.
|
||||
*/
|
||||
fd = open(pfh->pf_path,
|
||||
O_WRONLY | O_CREAT | O_EXLOCK | O_TRUNC | O_NONBLOCK, mode);
|
||||
if (fd == -1) {
|
||||
if (errno == EWOULDBLOCK && pidptr != NULL) {
|
||||
errno = pidfile_read(pfh->pf_path, pidptr);
|
||||
if (errno == 0)
|
||||
errno = EEXIST;
|
||||
}
|
||||
free(pfh);
|
||||
return (NULL);
|
||||
}
|
||||
/*
|
||||
* Remember file information, so in pidfile_write() we are sure we write
|
||||
* to the proper descriptor.
|
||||
*/
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
error = errno;
|
||||
unlink(pfh->pf_path);
|
||||
close(fd);
|
||||
free(pfh);
|
||||
errno = error;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
pfh->pf_fd = fd;
|
||||
pfh->pf_dev = sb.st_dev;
|
||||
pfh->pf_ino = sb.st_ino;
|
||||
|
||||
return (pfh);
|
||||
}
|
||||
|
||||
int
|
||||
pidfile_write(struct pidfh *pfh)
|
||||
{
|
||||
char pidstr[16];
|
||||
int error, fd;
|
||||
|
||||
/*
|
||||
* Check remembered descriptor, so we don't overwrite some other
|
||||
* file if pidfile was closed and descriptor reused.
|
||||
*/
|
||||
errno = pidfile_verify(pfh);
|
||||
if (errno != 0) {
|
||||
/*
|
||||
* Don't close descriptor, because we are not sure if it's ours.
|
||||
*/
|
||||
return (-1);
|
||||
}
|
||||
fd = pfh->pf_fd;
|
||||
|
||||
/*
|
||||
* Truncate PID file, so multiple calls of pidfile_write() are allowed.
|
||||
*/
|
||||
if (ftruncate(fd, 0) == -1) {
|
||||
error = errno;
|
||||
_pidfile_remove(pfh, 0);
|
||||
errno = error;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
|
||||
if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
|
||||
error = errno;
|
||||
_pidfile_remove(pfh, 0);
|
||||
errno = error;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pidfile_close(struct pidfh *pfh)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = pidfile_verify(pfh);
|
||||
if (error != 0) {
|
||||
errno = error;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (close(pfh->pf_fd) == -1)
|
||||
error = errno;
|
||||
free(pfh);
|
||||
if (error != 0) {
|
||||
errno = error;
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
_pidfile_remove(struct pidfh *pfh, int freeit)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = pidfile_verify(pfh);
|
||||
if (error != 0) {
|
||||
errno = error;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (unlink(pfh->pf_path) == -1)
|
||||
error = errno;
|
||||
if (flock(pfh->pf_fd, LOCK_UN) == -1) {
|
||||
if (error == 0)
|
||||
error = errno;
|
||||
}
|
||||
if (close(pfh->pf_fd) == -1) {
|
||||
if (error == 0)
|
||||
error = errno;
|
||||
}
|
||||
if (freeit)
|
||||
free(pfh);
|
||||
else
|
||||
pfh->pf_fd = -1;
|
||||
if (error != 0) {
|
||||
errno = error;
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pidfile_remove(struct pidfh *pfh)
|
||||
{
|
||||
|
||||
return (_pidfile_remove(pfh, 1));
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1998 Jordan Hubbard
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/property.3,v 1.18 2005/01/20 09:17:07 ru Exp $
|
||||
.\" "
|
||||
.Dd October 7, 1998
|
||||
.Os
|
||||
.Dt PROPERTIES 3
|
||||
.Sh NAME
|
||||
.Nm properties_read ,
|
||||
.Nm propery_find ,
|
||||
.Nm properties_free
|
||||
.Nd "functions to allow creating simple property lists from ASCII file data"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In libutil.h
|
||||
.Ft properties
|
||||
.Fn properties_read "int fd"
|
||||
.Ft char *
|
||||
.Fn property_find "properties list" "const char *name"
|
||||
.Ft void
|
||||
.Fn properties_free "properties list"
|
||||
.Sh DESCRIPTION
|
||||
.Bd -literal
|
||||
typedef struct _properties {
|
||||
struct _properties *next;
|
||||
char *name;
|
||||
char *value;
|
||||
} *properties;
|
||||
.Ed
|
||||
.Pp
|
||||
The function
|
||||
.Fn properties_read
|
||||
reads
|
||||
.Fa name = value
|
||||
pairs from the file descriptor passed in
|
||||
.Fa fd
|
||||
and returns the head of a new property list, assuming that the
|
||||
file's contents have been parsed properly, or NULL in case
|
||||
of error.
|
||||
.Pp
|
||||
The
|
||||
.Fn property_find
|
||||
function returns the associated value string for the property named
|
||||
.Fa name
|
||||
if found, otherwise NULL.
|
||||
The value returned may be up to
|
||||
.Dv PROPERTY_MAX_VALUE
|
||||
bytes in length.
|
||||
.Pp
|
||||
The
|
||||
.Fn properties_free
|
||||
function is used to free the structure returned by
|
||||
.Fn properties_read
|
||||
when it is no longer needed.
|
||||
.Sh FILE FORMAT
|
||||
Each property in the file is assumed to have the format of
|
||||
.Fa name = value
|
||||
where
|
||||
.Fa name
|
||||
is an alphanumeric string (and any punctuation not including the `=' character)
|
||||
and
|
||||
.Fa value
|
||||
is an arbitary string of text terminated by a newline character.
|
||||
If newlines
|
||||
are desired, the entire value should be enclosed in { } (curly-bracket)
|
||||
characters.
|
||||
Any line beginning with a # or ; character is assumed to
|
||||
be a comment and will be ignored.
|
||||
.Sh SEE ALSO
|
||||
.Xr auth_getval 3
|
||||
.Sh AUTHORS
|
||||
.An Jordan Hubbard
|
||||
.Sh BUGS
|
||||
Simplistic.
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
*
|
||||
* Simple property list handling code.
|
||||
*
|
||||
* Copyright (c) 1998
|
||||
* Jordan Hubbard. All rights reserved.
|
||||
*
|
||||
* 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,
|
||||
* verbatim and that no modifications are made prior to this
|
||||
* point in the file.
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR OR HIS PETS 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, LIFE 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/property.c,v 1.14 2005/11/28 16:30:16 jhb Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <libutil.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static properties
|
||||
property_alloc(char *name, char *value)
|
||||
{
|
||||
properties n;
|
||||
|
||||
if ((n = (properties)malloc(sizeof(struct _property))) == NULL)
|
||||
return (NULL);
|
||||
n->next = NULL;
|
||||
if (name != NULL) {
|
||||
if ((n->name = strdup(name)) == NULL) {
|
||||
free(n);
|
||||
return (NULL);
|
||||
}
|
||||
} else
|
||||
n->name = NULL;
|
||||
if (value != NULL) {
|
||||
if ((n->value = strdup(value)) == NULL) {
|
||||
free(n->name);
|
||||
free(n);
|
||||
return (NULL);
|
||||
}
|
||||
} else
|
||||
n->value = NULL;
|
||||
return (n);
|
||||
}
|
||||
|
||||
properties
|
||||
properties_read(int fd)
|
||||
{
|
||||
properties head, ptr;
|
||||
char hold_n[PROPERTY_MAX_NAME + 1];
|
||||
char hold_v[PROPERTY_MAX_VALUE + 1];
|
||||
char buf[BUFSIZ * 4];
|
||||
int bp, n, v, max;
|
||||
enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state, last_state;
|
||||
int ch = 0, blevel = 0;
|
||||
|
||||
n = v = bp = max = 0;
|
||||
head = ptr = NULL;
|
||||
state = last_state = LOOK;
|
||||
while (state != STOP) {
|
||||
if (state != COMMIT) {
|
||||
if (bp == max) {
|
||||
last_state = state;
|
||||
state = FILL;
|
||||
} else
|
||||
ch = buf[bp++];
|
||||
}
|
||||
switch(state) {
|
||||
case FILL:
|
||||
if ((max = read(fd, buf, sizeof buf)) < 0) {
|
||||
properties_free(head);
|
||||
return (NULL);
|
||||
}
|
||||
if (max == 0) {
|
||||
state = STOP;
|
||||
} else {
|
||||
/*
|
||||
* Restore the state from before the fill (which will be
|
||||
* initialised to LOOK for the first FILL). This ensures that
|
||||
* if we were part-way through eg., a VALUE state, when the
|
||||
* buffer ran out, that the previous operation will be allowed
|
||||
* to complete.
|
||||
*/
|
||||
state = last_state;
|
||||
ch = buf[0];
|
||||
bp = 0;
|
||||
}
|
||||
continue;
|
||||
|
||||
case LOOK:
|
||||
if (isspace((unsigned char)ch))
|
||||
continue;
|
||||
/* Allow shell or lisp style comments */
|
||||
else if (ch == '#' || ch == ';') {
|
||||
state = COMMENT;
|
||||
continue;
|
||||
}
|
||||
else if (isalnum((unsigned char)ch) || ch == '_') {
|
||||
if (n >= PROPERTY_MAX_NAME) {
|
||||
n = 0;
|
||||
state = COMMENT;
|
||||
}
|
||||
else {
|
||||
hold_n[n++] = ch;
|
||||
state = NAME;
|
||||
}
|
||||
}
|
||||
else
|
||||
state = COMMENT; /* Ignore the rest of the line */
|
||||
break;
|
||||
|
||||
case COMMENT:
|
||||
if (ch == '\n')
|
||||
state = LOOK;
|
||||
break;
|
||||
|
||||
case NAME:
|
||||
if (ch == '\n' || !ch) {
|
||||
hold_n[n] = '\0';
|
||||
hold_v[0] = '\0';
|
||||
v = n = 0;
|
||||
state = COMMIT;
|
||||
}
|
||||
else if (isspace((unsigned char)ch))
|
||||
continue;
|
||||
else if (ch == '=') {
|
||||
hold_n[n] = '\0';
|
||||
v = n = 0;
|
||||
state = VALUE;
|
||||
}
|
||||
else
|
||||
hold_n[n++] = ch;
|
||||
break;
|
||||
|
||||
case VALUE:
|
||||
if (v == 0 && ch == '\n') {
|
||||
hold_v[v] = '\0';
|
||||
v = n = 0;
|
||||
state = COMMIT;
|
||||
}
|
||||
else if (v == 0 && isspace((unsigned char)ch))
|
||||
continue;
|
||||
else if (ch == '{') {
|
||||
state = MVALUE;
|
||||
++blevel;
|
||||
}
|
||||
else if (ch == '\n' || !ch) {
|
||||
hold_v[v] = '\0';
|
||||
v = n = 0;
|
||||
state = COMMIT;
|
||||
}
|
||||
else {
|
||||
if (v >= PROPERTY_MAX_VALUE) {
|
||||
state = COMMENT;
|
||||
v = n = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
hold_v[v++] = ch;
|
||||
}
|
||||
break;
|
||||
|
||||
case MVALUE:
|
||||
/* multiline value */
|
||||
if (v >= PROPERTY_MAX_VALUE) {
|
||||
warn("properties_read: value exceeds max length");
|
||||
state = COMMENT;
|
||||
n = v = 0;
|
||||
}
|
||||
else if (ch == '}' && !--blevel) {
|
||||
hold_v[v] = '\0';
|
||||
v = n = 0;
|
||||
state = COMMIT;
|
||||
}
|
||||
else {
|
||||
hold_v[v++] = ch;
|
||||
if (ch == '{')
|
||||
++blevel;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMIT:
|
||||
if (head == NULL) {
|
||||
if ((head = ptr = property_alloc(hold_n, hold_v)) == NULL)
|
||||
return (NULL);
|
||||
} else {
|
||||
if ((ptr->next = property_alloc(hold_n, hold_v)) == NULL) {
|
||||
properties_free(head);
|
||||
return (NULL);
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
state = LOOK;
|
||||
v = n = 0;
|
||||
break;
|
||||
|
||||
case STOP:
|
||||
/* we don't handle this here, but this prevents warnings */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (head == NULL && (head = property_alloc(NULL, NULL)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
return (head);
|
||||
}
|
||||
|
||||
char *
|
||||
property_find(properties list, const char *name)
|
||||
{
|
||||
if (list == NULL || name == NULL || !name[0])
|
||||
return (NULL);
|
||||
while (list != NULL) {
|
||||
if (list->name != NULL && strcmp(list->name, name) == 0)
|
||||
return (list->value);
|
||||
list = list->next;
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
properties_free(properties list)
|
||||
{
|
||||
properties tmp;
|
||||
|
||||
while (list) {
|
||||
tmp = list->next;
|
||||
if (list->name)
|
||||
free(list->name);
|
||||
if (list->value)
|
||||
free(list->value);
|
||||
free(list);
|
||||
list = tmp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1996 Joerg Wunsch
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/pty.3,v 1.13 2004/07/02 23:52:19 ru Exp $
|
||||
.\" "
|
||||
.Dd December 29, 1996
|
||||
.Os
|
||||
.Dt PTY 3
|
||||
.Sh NAME
|
||||
.Nm openpty ,
|
||||
.Nm forkpty
|
||||
.Nd auxiliary functions to obtain a pseudo-terminal
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In sys/ioctl.h
|
||||
.In termios.h
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn openpty "int *amaster" "int *aslave" "char *name" "struct termios *termp" "struct winsize *winp"
|
||||
.Ft int
|
||||
.Fn forkpty "int *amaster" "char *name" "struct termios *termp" "struct winsize *winp"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn openpty
|
||||
attempts to obtain the next available pseudo-terminal from the system (see
|
||||
.Xr pty 4 ) .
|
||||
If it successfully finds one, it subsequently tries to change the
|
||||
ownership of the slave device to the real UID of the current process,
|
||||
the group membership to the group
|
||||
.Dq tty
|
||||
(if such a group exists in the system), the access permissions for
|
||||
reading and writing by the owner, and for writing by the group, and to
|
||||
invalidate any current use of the line by calling
|
||||
.Xr revoke 2 .
|
||||
.Pp
|
||||
If the argument
|
||||
.Fa name
|
||||
is not
|
||||
.Dv NULL ,
|
||||
.Fn openpty
|
||||
copies the pathname of the slave pty to this area.
|
||||
The caller is
|
||||
responsible for allocating the required space in this array.
|
||||
.Pp
|
||||
If the arguments
|
||||
.Fa termp
|
||||
or
|
||||
.Fa winp
|
||||
are not
|
||||
.Dv NULL ,
|
||||
.Fn openpty
|
||||
initializes the termios and window size settings from the structures
|
||||
these arguments point to, respectively.
|
||||
.Pp
|
||||
Upon return, the open file descriptors for the master and slave side
|
||||
of the pty are returned in the locations pointed to by
|
||||
.Fa amaster
|
||||
and
|
||||
.Fa aslave ,
|
||||
respectively.
|
||||
.Pp
|
||||
The
|
||||
.Fn forkpty
|
||||
function first calls
|
||||
.Fn openpty
|
||||
to obtain the next available pseudo-terminal from the system.
|
||||
Upon success,
|
||||
it forks off a new process.
|
||||
In the child process, it closes the descriptor
|
||||
for the master side of the pty, and calls
|
||||
.Xr login_tty 3
|
||||
for the slave pty.
|
||||
In the parent process, it closes the descriptor for the
|
||||
slave side of the pty.
|
||||
The arguments
|
||||
.Fa amaster ,
|
||||
.Fa name ,
|
||||
.Fa termp ,
|
||||
and
|
||||
.Fa winp
|
||||
have the same meaning as described for
|
||||
.Fn openpty .
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn openpty
|
||||
function returns 0 on success, or -1 on failure.
|
||||
.Pp
|
||||
The
|
||||
.Fn forkpty
|
||||
function returns -1 on failure, 0 in the slave process, and the process ID of
|
||||
the slave process in the parent process.
|
||||
.Sh ERRORS
|
||||
On failure,
|
||||
.Fn openpty
|
||||
will set the global variable
|
||||
.Dv errno
|
||||
to
|
||||
.Er ENOENT .
|
||||
.Pp
|
||||
In addition to this,
|
||||
.Fn forkpty
|
||||
may set it to any value as described for
|
||||
.Xr fork 2 .
|
||||
.Sh SEE ALSO
|
||||
.Xr chmod 2 ,
|
||||
.Xr chown 2 ,
|
||||
.Xr fork 2 ,
|
||||
.Xr getuid 2 ,
|
||||
.Xr open 2 ,
|
||||
.Xr revoke 2 ,
|
||||
.Xr login_tty 3 ,
|
||||
.Xr pty 4 ,
|
||||
.Xr termios 4 ,
|
||||
.Xr group 5
|
||||
.Sh BUGS
|
||||
The calling process must have an effective UID of super-user in order
|
||||
to perform all the intended actions.
|
||||
No notification will occur if
|
||||
.Fn openpty
|
||||
or
|
||||
.Fn forkpty
|
||||
failed to proceed with one of the described steps, as long as they could
|
||||
at least allocate the pty at all (and create the new process in the case
|
||||
of
|
||||
.Fn forkpty ) .
|
||||
@@ -0,0 +1,172 @@
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/pty.c,v 1.16 2006/01/26 01:33:26 cognet Exp $");
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)pty.c 8.3 (Berkeley) 5/16/94";
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <libutil.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int __use_pts(void);
|
||||
|
||||
static int
|
||||
new_openpty(int *amaster, int *aslave, char *name, struct termios *termp,
|
||||
struct winsize *winp)
|
||||
{
|
||||
int master, slave;
|
||||
|
||||
master = posix_openpt(O_RDWR);
|
||||
if (master == -1)
|
||||
return (-1);
|
||||
|
||||
if (grantpt(master) == -1) {
|
||||
close(master);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
slave = open(ptsname(master), O_RDWR);
|
||||
if (slave == -1) {
|
||||
close(master);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (unlockpt(master) == -1) {
|
||||
close(master);
|
||||
close(slave);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*amaster = master;
|
||||
*aslave = slave;
|
||||
|
||||
if (name)
|
||||
strcpy(name, ptsname(master));
|
||||
if (termp)
|
||||
tcsetattr(slave, TCSAFLUSH, termp);
|
||||
if (winp)
|
||||
ioctl(slave, TIOCSWINSZ, (char *)winp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp)
|
||||
{
|
||||
char line[] = "/dev/ptyXX";
|
||||
const char *cp1, *cp2;
|
||||
int master, slave, ttygid;
|
||||
struct group *gr;
|
||||
|
||||
if (__use_pts())
|
||||
return (new_openpty(amaster, aslave, name, termp, winp));
|
||||
|
||||
if ((gr = getgrnam("tty")) != NULL)
|
||||
ttygid = gr->gr_gid;
|
||||
else
|
||||
ttygid = -1;
|
||||
|
||||
for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
|
||||
line[8] = *cp1;
|
||||
for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
|
||||
line[5] = 'p';
|
||||
line[9] = *cp2;
|
||||
if ((master = open(line, O_RDWR, 0)) == -1) {
|
||||
if (errno == ENOENT)
|
||||
break; /* try the next pty group */
|
||||
} else {
|
||||
line[5] = 't';
|
||||
(void) chown(line, getuid(), ttygid);
|
||||
(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
|
||||
(void) revoke(line);
|
||||
if ((slave = open(line, O_RDWR, 0)) != -1) {
|
||||
*amaster = master;
|
||||
*aslave = slave;
|
||||
if (name)
|
||||
strcpy(name, line);
|
||||
if (termp)
|
||||
(void) tcsetattr(slave,
|
||||
TCSAFLUSH, termp);
|
||||
if (winp)
|
||||
(void) ioctl(slave, TIOCSWINSZ,
|
||||
(char *)winp);
|
||||
return (0);
|
||||
}
|
||||
(void) close(master);
|
||||
}
|
||||
}
|
||||
}
|
||||
errno = ENOENT; /* out of ptys */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
|
||||
{
|
||||
int master, slave, pid;
|
||||
|
||||
if (openpty(&master, &slave, name, termp, winp) == -1)
|
||||
return (-1);
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0:
|
||||
/*
|
||||
* child
|
||||
*/
|
||||
(void) close(master);
|
||||
login_tty(slave);
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* parent
|
||||
*/
|
||||
*amaster = master;
|
||||
(void) close(slave);
|
||||
return (pid);
|
||||
}
|
||||
@@ -0,0 +1,616 @@
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2002 Networks Associates Technology, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed for the FreeBSD Project by
|
||||
* ThinkSec AS and NAI Labs, the Security Research Division of Network
|
||||
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
|
||||
* ("CBOSS"), as part of the DARPA CHATS research program.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94";
|
||||
#endif
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD: src/lib/libutil/pw_util.c,v 1.35 2004/05/18 15:53:58 stefanf Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* This file is used by all the "password" programs; vipw(8), chpass(1),
|
||||
* and passwd(1).
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libgen.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libutil.h>
|
||||
|
||||
static pid_t editpid = -1;
|
||||
static int lockfd = -1;
|
||||
static char masterpasswd[PATH_MAX];
|
||||
static char passwd_dir[PATH_MAX];
|
||||
static char tempname[PATH_MAX];
|
||||
static int initialized;
|
||||
|
||||
#if 0
|
||||
void
|
||||
pw_cont(int sig)
|
||||
{
|
||||
|
||||
if (editpid != -1)
|
||||
kill(editpid, sig);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize statics and set limits, signals & umask to try to avoid
|
||||
* interruptions, crashes etc. that might expose passord data.
|
||||
*/
|
||||
int
|
||||
pw_init(const char *dir, const char *master)
|
||||
{
|
||||
#if 0
|
||||
struct rlimit rlim;
|
||||
#endif
|
||||
|
||||
if (dir == NULL) {
|
||||
strcpy(passwd_dir, _PATH_ETC);
|
||||
} else {
|
||||
if (strlen(dir) >= sizeof(passwd_dir)) {
|
||||
errno = ENAMETOOLONG;
|
||||
return (-1);
|
||||
}
|
||||
strcpy(passwd_dir, dir);
|
||||
}
|
||||
|
||||
if (master == NULL) {
|
||||
if (dir == NULL) {
|
||||
strcpy(masterpasswd, _PATH_MASTERPASSWD);
|
||||
} else if (snprintf(masterpasswd, sizeof(masterpasswd), "%s/%s",
|
||||
passwd_dir, _MASTERPASSWD) > (int)sizeof(masterpasswd)) {
|
||||
errno = ENAMETOOLONG;
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
if (strlen(master) >= sizeof(masterpasswd)) {
|
||||
errno = ENAMETOOLONG;
|
||||
return (-1);
|
||||
}
|
||||
strcpy(masterpasswd, master);
|
||||
}
|
||||
|
||||
/*
|
||||
* The code that follows is extremely disruptive to the calling
|
||||
* process, and is therefore disabled until someone can conceive
|
||||
* of a realistic scenario where it would fend off a compromise.
|
||||
* Race conditions concerning the temporary files can be guarded
|
||||
* against in other ways than masking signals (by checking stat(2)
|
||||
* results after creation).
|
||||
*/
|
||||
#if 0
|
||||
/* Unlimited resource limits. */
|
||||
rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
|
||||
(void)setrlimit(RLIMIT_CPU, &rlim);
|
||||
(void)setrlimit(RLIMIT_FSIZE, &rlim);
|
||||
(void)setrlimit(RLIMIT_STACK, &rlim);
|
||||
(void)setrlimit(RLIMIT_DATA, &rlim);
|
||||
(void)setrlimit(RLIMIT_RSS, &rlim);
|
||||
|
||||
/* Don't drop core (not really necessary, but GP's). */
|
||||
rlim.rlim_cur = rlim.rlim_max = 0;
|
||||
(void)setrlimit(RLIMIT_CORE, &rlim);
|
||||
|
||||
/* Turn off signals. */
|
||||
(void)signal(SIGALRM, SIG_IGN);
|
||||
(void)signal(SIGHUP, SIG_IGN);
|
||||
(void)signal(SIGINT, SIG_IGN);
|
||||
(void)signal(SIGPIPE, SIG_IGN);
|
||||
(void)signal(SIGQUIT, SIG_IGN);
|
||||
(void)signal(SIGTERM, SIG_IGN);
|
||||
(void)signal(SIGCONT, pw_cont);
|
||||
|
||||
/* Create with exact permissions. */
|
||||
(void)umask(0);
|
||||
#endif
|
||||
initialized = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock the master password file.
|
||||
*/
|
||||
int
|
||||
pw_lock(void)
|
||||
{
|
||||
|
||||
if (*masterpasswd == '\0')
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* If the master password file doesn't exist, the system is hosed.
|
||||
* Might as well try to build one. Set the close-on-exec bit so
|
||||
* that users can't get at the encrypted passwords while editing.
|
||||
* Open should allow flock'ing the file; see 4.4BSD. XXX
|
||||
*/
|
||||
for (;;) {
|
||||
struct stat st;
|
||||
|
||||
lockfd = open(masterpasswd, O_RDONLY, 0);
|
||||
if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
|
||||
err(1, "%s", masterpasswd);
|
||||
/* XXX vulnerable to race conditions */
|
||||
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
errx(1, "the password db file is busy");
|
||||
} else {
|
||||
err(1, "could not lock the passwd file: ");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the password file was replaced while we were trying to
|
||||
* get the lock, our hardlink count will be 0 and we have to
|
||||
* close and retry.
|
||||
*/
|
||||
if (fstat(lockfd, &st) == -1)
|
||||
err(1, "fstat() failed: ");
|
||||
if (st.st_nlink != 0)
|
||||
break;
|
||||
close(lockfd);
|
||||
lockfd = -1;
|
||||
}
|
||||
return (lockfd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and open a presumably safe temp file for editing the password
|
||||
* data, and copy the master password file into it.
|
||||
*/
|
||||
int
|
||||
pw_tmp(int mfd)
|
||||
{
|
||||
char buf[8192];
|
||||
ssize_t nr;
|
||||
const char *p;
|
||||
int tfd;
|
||||
|
||||
if (*masterpasswd == '\0')
|
||||
return (-1);
|
||||
if ((p = strrchr(masterpasswd, '/')))
|
||||
++p;
|
||||
else
|
||||
p = masterpasswd;
|
||||
if (snprintf(tempname, sizeof(tempname), "%.*spw.XXXXXX",
|
||||
(int)(p - masterpasswd), masterpasswd) >= (int)sizeof(tempname)) {
|
||||
errno = ENAMETOOLONG;
|
||||
return (-1);
|
||||
}
|
||||
if ((tfd = mkstemp(tempname)) == -1)
|
||||
return (-1);
|
||||
if (mfd != -1) {
|
||||
while ((nr = read(mfd, buf, sizeof(buf))) > 0)
|
||||
if (write(tfd, buf, (size_t)nr) != nr)
|
||||
break;
|
||||
if (nr != 0) {
|
||||
unlink(tempname);
|
||||
*tempname = '\0';
|
||||
close(tfd);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
return (tfd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Regenerate the password database.
|
||||
*/
|
||||
int
|
||||
pw_mkdb(const char *user)
|
||||
{
|
||||
int pstat;
|
||||
pid_t pid;
|
||||
|
||||
(void)fflush(stderr);
|
||||
switch ((pid = fork())) {
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0:
|
||||
/* child */
|
||||
if (user == NULL)
|
||||
execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
|
||||
"-d", passwd_dir, tempname, (char *)NULL);
|
||||
else
|
||||
execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p",
|
||||
"-d", passwd_dir, "-u", user, tempname,
|
||||
(char *)NULL);
|
||||
_exit(1);
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
/* parent */
|
||||
break;
|
||||
}
|
||||
if (waitpid(pid, &pstat, 0) == -1)
|
||||
return (-1);
|
||||
if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
|
||||
return (0);
|
||||
errno = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Edit the temp file. Return -1 on error, >0 if the file was modified, 0
|
||||
* if it was not.
|
||||
*/
|
||||
int
|
||||
pw_edit(int notsetuid)
|
||||
{
|
||||
struct sigaction sa, sa_int, sa_quit;
|
||||
sigset_t oldsigset, sigset;
|
||||
struct stat st1, st2;
|
||||
const char *editor;
|
||||
int pstat;
|
||||
|
||||
if ((editor = getenv("EDITOR")) == NULL)
|
||||
editor = _PATH_VI;
|
||||
if (stat(tempname, &st1) == -1)
|
||||
return (-1);
|
||||
sa.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGINT, &sa, &sa_int);
|
||||
sigaction(SIGQUIT, &sa, &sa_quit);
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
|
||||
switch ((editpid = fork())) {
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0:
|
||||
sigaction(SIGINT, &sa_int, NULL);
|
||||
sigaction(SIGQUIT, &sa_quit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &oldsigset, NULL);
|
||||
if (notsetuid) {
|
||||
(void)setgid(getgid());
|
||||
(void)setuid(getuid());
|
||||
}
|
||||
errno = 0;
|
||||
execlp(editor, basename(editor), tempname, (char *)NULL);
|
||||
_exit(errno);
|
||||
default:
|
||||
/* parent */
|
||||
break;
|
||||
}
|
||||
for (;;) {
|
||||
if (waitpid(editpid, &pstat, WUNTRACED) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
unlink(tempname);
|
||||
editpid = -1;
|
||||
break;
|
||||
} else if (WIFSTOPPED(pstat)) {
|
||||
raise(WSTOPSIG(pstat));
|
||||
} else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
|
||||
editpid = -1;
|
||||
break;
|
||||
} else {
|
||||
unlink(tempname);
|
||||
editpid = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sigaction(SIGINT, &sa_int, NULL);
|
||||
sigaction(SIGQUIT, &sa_quit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &oldsigset, NULL);
|
||||
if (stat(tempname, &st2) == -1)
|
||||
return (-1);
|
||||
return (st1.st_mtime != st2.st_mtime);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up. Preserve errno for the caller's convenience.
|
||||
*/
|
||||
void
|
||||
pw_fini(void)
|
||||
{
|
||||
int serrno, status;
|
||||
|
||||
if (!initialized)
|
||||
return;
|
||||
initialized = 0;
|
||||
serrno = errno;
|
||||
if (editpid != -1) {
|
||||
kill(editpid, SIGTERM);
|
||||
kill(editpid, SIGCONT);
|
||||
waitpid(editpid, &status, 0);
|
||||
editpid = -1;
|
||||
}
|
||||
if (*tempname != '\0') {
|
||||
unlink(tempname);
|
||||
*tempname = '\0';
|
||||
}
|
||||
if (lockfd != -1)
|
||||
close(lockfd);
|
||||
errno = serrno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two struct pwds.
|
||||
*/
|
||||
int
|
||||
pw_equal(const struct passwd *pw1, const struct passwd *pw2)
|
||||
{
|
||||
return (strcmp(pw1->pw_name, pw2->pw_name) == 0 &&
|
||||
pw1->pw_uid == pw2->pw_uid &&
|
||||
pw1->pw_gid == pw2->pw_gid &&
|
||||
strcmp(pw1->pw_class, pw2->pw_class) == 0 &&
|
||||
pw1->pw_change == pw2->pw_change &&
|
||||
pw1->pw_expire == pw2->pw_expire &&
|
||||
strcmp(pw1->pw_gecos, pw2->pw_gecos) == 0 &&
|
||||
strcmp(pw1->pw_dir, pw2->pw_dir) == 0 &&
|
||||
strcmp(pw1->pw_shell, pw2->pw_shell) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a passwd line out of a struct passwd.
|
||||
*/
|
||||
char *
|
||||
pw_make(const struct passwd *pw)
|
||||
{
|
||||
char *line;
|
||||
|
||||
asprintf(&line, "%s:%s:%ju:%ju:%s:%ju:%ju:%s:%s:%s", pw->pw_name,
|
||||
pw->pw_passwd, (uintmax_t)pw->pw_uid, (uintmax_t)pw->pw_gid,
|
||||
pw->pw_class, (uintmax_t)pw->pw_change, (uintmax_t)pw->pw_expire,
|
||||
pw->pw_gecos, pw->pw_dir, pw->pw_shell);
|
||||
return line;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy password file from one descriptor to another, replacing or adding
|
||||
* a single record on the way.
|
||||
*/
|
||||
int
|
||||
pw_copy(int ffd, int tfd, const struct passwd *pw, struct passwd *old_pw)
|
||||
{
|
||||
char buf[8192], *end, *line, *p, *q, *r, t;
|
||||
struct passwd *fpw;
|
||||
size_t len;
|
||||
int eof, readlen;
|
||||
|
||||
if ((line = pw_make(pw)) == NULL)
|
||||
return (-1);
|
||||
|
||||
eof = 0;
|
||||
len = 0;
|
||||
p = q = end = buf;
|
||||
for (;;) {
|
||||
/* find the end of the current line */
|
||||
for (p = q; q < end && *q != '\0'; ++q)
|
||||
if (*q == '\n')
|
||||
break;
|
||||
|
||||
/* if we don't have a complete line, fill up the buffer */
|
||||
if (q >= end) {
|
||||
if (eof)
|
||||
break;
|
||||
if ((size_t)(q - p) >= sizeof(buf)) {
|
||||
warnx("passwd line too long");
|
||||
errno = EINVAL; /* hack */
|
||||
goto err;
|
||||
}
|
||||
if (p < end) {
|
||||
q = memmove(buf, p, end - p);
|
||||
end -= p - buf;
|
||||
} else {
|
||||
p = q = end = buf;
|
||||
}
|
||||
readlen = read(ffd, end, sizeof(buf) - (end - buf));
|
||||
if (readlen == -1)
|
||||
goto err;
|
||||
else
|
||||
len = (size_t)readlen;
|
||||
if (len == 0 && p == buf)
|
||||
break;
|
||||
end += len;
|
||||
len = end - buf;
|
||||
if (len < (ssize_t)sizeof(buf)) {
|
||||
eof = 1;
|
||||
if (len > 0 && buf[len - 1] != '\n')
|
||||
++len, *end++ = '\n';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* is it a blank line or a comment? */
|
||||
for (r = p; r < q && isspace(*r); ++r)
|
||||
/* nothing */ ;
|
||||
if (r == q || *r == '#') {
|
||||
/* yep */
|
||||
if (write(tfd, p, q - p + 1) != q - p + 1)
|
||||
goto err;
|
||||
++q;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* is it the one we're looking for? */
|
||||
t = *q;
|
||||
*q = '\0';
|
||||
fpw = pw_scan(r, PWSCAN_MASTER);
|
||||
*q = t;
|
||||
if (strcmp(fpw->pw_name, pw->pw_name) != 0) {
|
||||
/* nope */
|
||||
free(fpw);
|
||||
if (write(tfd, p, q - p + 1) != q - p + 1)
|
||||
goto err;
|
||||
++q;
|
||||
continue;
|
||||
}
|
||||
if (old_pw && !pw_equal(fpw, old_pw)) {
|
||||
warnx("entry inconsistent");
|
||||
free(fpw);
|
||||
errno = EINVAL; /* hack */
|
||||
goto err;
|
||||
}
|
||||
free(fpw);
|
||||
|
||||
/* it is, replace it */
|
||||
len = strlen(line);
|
||||
if (write(tfd, line, len) != (int)len)
|
||||
goto err;
|
||||
|
||||
/* we're done, just copy the rest over */
|
||||
for (;;) {
|
||||
if (write(tfd, q, end - q) != end - q)
|
||||
goto err;
|
||||
q = buf;
|
||||
readlen = read(ffd, buf, sizeof(buf));
|
||||
if (readlen == 0)
|
||||
break;
|
||||
else
|
||||
len = (size_t)readlen;
|
||||
if (readlen == -1)
|
||||
goto err;
|
||||
end = buf + len;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* if we got here, we have a new entry */
|
||||
len = strlen(line);
|
||||
if ((size_t)write(tfd, line, len) != len ||
|
||||
write(tfd, "\n", 1) != 1)
|
||||
goto err;
|
||||
done:
|
||||
free(line);
|
||||
return (0);
|
||||
err:
|
||||
free(line);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the current value of tempname.
|
||||
*/
|
||||
const char *
|
||||
pw_tempname(void)
|
||||
{
|
||||
|
||||
return (tempname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate a struct passwd.
|
||||
*/
|
||||
struct passwd *
|
||||
pw_dup(const struct passwd *pw)
|
||||
{
|
||||
struct passwd *npw;
|
||||
ssize_t len;
|
||||
|
||||
len = sizeof(*npw) +
|
||||
(pw->pw_name ? strlen(pw->pw_name) + 1 : 0) +
|
||||
(pw->pw_passwd ? strlen(pw->pw_passwd) + 1 : 0) +
|
||||
(pw->pw_class ? strlen(pw->pw_class) + 1 : 0) +
|
||||
(pw->pw_gecos ? strlen(pw->pw_gecos) + 1 : 0) +
|
||||
(pw->pw_dir ? strlen(pw->pw_dir) + 1 : 0) +
|
||||
(pw->pw_shell ? strlen(pw->pw_shell) + 1 : 0);
|
||||
if ((npw = malloc((size_t)len)) == NULL)
|
||||
return (NULL);
|
||||
memcpy(npw, pw, sizeof(*npw));
|
||||
len = sizeof(*npw);
|
||||
if (pw->pw_name) {
|
||||
npw->pw_name = ((char *)npw) + len;
|
||||
len += sprintf(npw->pw_name, "%s", pw->pw_name) + 1;
|
||||
}
|
||||
if (pw->pw_passwd) {
|
||||
npw->pw_passwd = ((char *)npw) + len;
|
||||
len += sprintf(npw->pw_passwd, "%s", pw->pw_passwd) + 1;
|
||||
}
|
||||
if (pw->pw_class) {
|
||||
npw->pw_class = ((char *)npw) + len;
|
||||
len += sprintf(npw->pw_class, "%s", pw->pw_class) + 1;
|
||||
}
|
||||
if (pw->pw_gecos) {
|
||||
npw->pw_gecos = ((char *)npw) + len;
|
||||
len += sprintf(npw->pw_gecos, "%s", pw->pw_gecos) + 1;
|
||||
}
|
||||
if (pw->pw_dir) {
|
||||
npw->pw_dir = ((char *)npw) + len;
|
||||
len += sprintf(npw->pw_dir, "%s", pw->pw_dir) + 1;
|
||||
}
|
||||
if (pw->pw_shell) {
|
||||
npw->pw_shell = ((char *)npw) + len;
|
||||
len += sprintf(npw->pw_shell, "%s", pw->pw_shell) + 1;
|
||||
}
|
||||
return (npw);
|
||||
}
|
||||
|
||||
#include "pw_scan.h"
|
||||
|
||||
/*
|
||||
* Wrapper around an internal libc function
|
||||
*/
|
||||
struct passwd *
|
||||
pw_scan(const char *line, int flags)
|
||||
{
|
||||
struct passwd pw, *ret;
|
||||
char *bp;
|
||||
|
||||
if ((bp = strdup(line)) == NULL)
|
||||
return (NULL);
|
||||
if (!__pw_scan(bp, &pw, flags)) {
|
||||
free(bp);
|
||||
return (NULL);
|
||||
}
|
||||
ret = pw_dup(&pw);
|
||||
free(bp);
|
||||
return (ret);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
.\" Copyright (c) 1999 Brian Somers <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/realhostname.3,v 1.10 2005/02/13 22:25:14 ru Exp $
|
||||
.\"
|
||||
.Dd April 6, 1999
|
||||
.Os
|
||||
.Dt REALHOSTNAME 3
|
||||
.Sh NAME
|
||||
.Nm realhostname
|
||||
.Nd "convert an IP number to the real host name"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In netinet/in.h
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn realhostname "char *host" "size_t hsize" "const struct in_addr *ip"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn realhostname
|
||||
converts
|
||||
.Ar ip
|
||||
to the corresponding host name.
|
||||
This is done by resolving
|
||||
.Ar ip
|
||||
to a host name and then ensuring that the host name resolves
|
||||
back to
|
||||
.Ar ip .
|
||||
.Pp
|
||||
.Ar host
|
||||
must point to a buffer of at least
|
||||
.Ar hsize
|
||||
bytes, and will always be written to by this function.
|
||||
.Pp
|
||||
If the name resolution does not work both ways or if the host name is longer
|
||||
than
|
||||
.Ar hsize
|
||||
bytes,
|
||||
.Xr inet_ntoa 3
|
||||
is used to convert
|
||||
.Ar ip
|
||||
to an ASCII form.
|
||||
.Pp
|
||||
If the string written to
|
||||
.Ar host
|
||||
is
|
||||
.Ar hsize
|
||||
bytes long,
|
||||
.Ar host
|
||||
will not be NUL terminated.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn realhostname
|
||||
function will return one of the following constants which are defined in
|
||||
.In libutil.h :
|
||||
.Pp
|
||||
.Bl -tag -width XXX -offset XXX
|
||||
.It Li HOSTNAME_FOUND
|
||||
A valid host name was found.
|
||||
.It Li HOSTNAME_INCORRECTNAME
|
||||
A host name was found, but it did not resolve back to the passed
|
||||
.Ar ip .
|
||||
.Ar host
|
||||
now contains the numeric value of
|
||||
.Ar ip .
|
||||
.It Li HOSTNAME_INVALIDADDR
|
||||
.Ar ip
|
||||
could not be resolved.
|
||||
.Ar host
|
||||
now contains the numeric value of
|
||||
.Ar ip .
|
||||
.It Li HOSTNAME_INVALIDNAME
|
||||
A host name was found, but it could not be resolved back to any ip number.
|
||||
.Ar host
|
||||
now contains the numeric value of
|
||||
.Ar ip .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr gethostbyaddr 3 ,
|
||||
.Xr gethostbyname 3 ,
|
||||
.Xr inet_ntoa 3 ,
|
||||
.Xr realhostname_sa 3
|
||||
@@ -0,0 +1,186 @@
|
||||
/*-
|
||||
* Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/realhostname.c,v 1.18 2005/05/13 16:31:09 ume Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libutil.h"
|
||||
|
||||
struct sockinet {
|
||||
u_char si_len;
|
||||
u_char si_family;
|
||||
u_short si_port;
|
||||
};
|
||||
|
||||
int
|
||||
realhostname(char *host, size_t hsize, const struct in_addr *ip)
|
||||
{
|
||||
char trimmed[MAXHOSTNAMELEN];
|
||||
int result;
|
||||
struct hostent *hp;
|
||||
|
||||
result = HOSTNAME_INVALIDADDR;
|
||||
hp = gethostbyaddr((const char *)ip, sizeof(*ip), AF_INET);
|
||||
|
||||
if (hp != NULL) {
|
||||
strlcpy(trimmed, hp->h_name, sizeof(trimmed));
|
||||
trimdomain(trimmed, strlen(trimmed));
|
||||
if (strlen(trimmed) <= hsize) {
|
||||
char lookup[MAXHOSTNAMELEN];
|
||||
|
||||
strncpy(lookup, hp->h_name, sizeof(lookup) - 1);
|
||||
lookup[sizeof(lookup) - 1] = '\0';
|
||||
hp = gethostbyname(lookup);
|
||||
if (hp == NULL)
|
||||
result = HOSTNAME_INVALIDNAME;
|
||||
else for (; ; hp->h_addr_list++) {
|
||||
if (*hp->h_addr_list == NULL) {
|
||||
result = HOSTNAME_INCORRECTNAME;
|
||||
break;
|
||||
}
|
||||
if (!memcmp(*hp->h_addr_list, ip, sizeof(*ip))) {
|
||||
strncpy(host, trimmed, hsize);
|
||||
return HOSTNAME_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(host, inet_ntoa(*ip), hsize);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen)
|
||||
{
|
||||
int result, error;
|
||||
char buf[NI_MAXHOST];
|
||||
struct sockaddr_in lsin;
|
||||
|
||||
result = HOSTNAME_INVALIDADDR;
|
||||
|
||||
#ifdef INET6
|
||||
/* IPv4 mapped IPv6 addr consideraton, specified in rfc2373. */
|
||||
if (addr->sa_family == AF_INET6 &&
|
||||
addrlen == sizeof(struct sockaddr_in6) &&
|
||||
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)addr)->sin6_addr)) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)addr;
|
||||
|
||||
memset(&lsin, 0, sizeof(lsin));
|
||||
lsin.sin_len = sizeof(struct sockaddr_in);
|
||||
lsin.sin_family = AF_INET;
|
||||
lsin.sin_port = sin6->sin6_port;
|
||||
memcpy(&lsin.sin_addr, &sin6->sin6_addr.s6_addr[12],
|
||||
sizeof(struct in_addr));
|
||||
addr = (struct sockaddr *)&lsin;
|
||||
addrlen = lsin.sin_len;
|
||||
}
|
||||
#endif
|
||||
|
||||
error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
|
||||
NI_NAMEREQD);
|
||||
if (error == 0) {
|
||||
struct addrinfo hints, *res, *ores;
|
||||
struct sockaddr *sa;
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = addr->sa_family;
|
||||
hints.ai_flags = AI_CANONNAME | AI_PASSIVE;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
error = getaddrinfo(buf, NULL, &hints, &res);
|
||||
if (error) {
|
||||
result = HOSTNAME_INVALIDNAME;
|
||||
goto numeric;
|
||||
}
|
||||
for (ores = res; ; res = res->ai_next) {
|
||||
if (res == NULL) {
|
||||
freeaddrinfo(ores);
|
||||
result = HOSTNAME_INCORRECTNAME;
|
||||
goto numeric;
|
||||
}
|
||||
sa = res->ai_addr;
|
||||
if (sa == NULL) {
|
||||
freeaddrinfo(ores);
|
||||
result = HOSTNAME_INCORRECTNAME;
|
||||
goto numeric;
|
||||
}
|
||||
if (sa->sa_len == addrlen &&
|
||||
sa->sa_family == addr->sa_family) {
|
||||
((struct sockinet *)sa)->si_port = ((struct sockinet *)addr)->si_port;
|
||||
#ifdef INET6
|
||||
/*
|
||||
* XXX: sin6_socpe_id may not been
|
||||
* filled by DNS
|
||||
*/
|
||||
if (sa->sa_family == AF_INET6 &&
|
||||
((struct sockaddr_in6 *)sa)->sin6_scope_id == 0)
|
||||
((struct sockaddr_in6 *)sa)->sin6_scope_id = ((struct sockaddr_in6 *)addr)->sin6_scope_id;
|
||||
#endif
|
||||
if (!memcmp(sa, addr, sa->sa_len)) {
|
||||
result = HOSTNAME_FOUND;
|
||||
if (ores->ai_canonname == NULL) {
|
||||
freeaddrinfo(ores);
|
||||
goto numeric;
|
||||
}
|
||||
strlcpy(buf, ores->ai_canonname,
|
||||
sizeof(buf));
|
||||
trimdomain(buf, hsize);
|
||||
if (strlen(buf) > hsize &&
|
||||
addr->sa_family == AF_INET) {
|
||||
freeaddrinfo(ores);
|
||||
goto numeric;
|
||||
}
|
||||
strncpy(host, buf, hsize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeaddrinfo(ores);
|
||||
} else {
|
||||
numeric:
|
||||
if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
|
||||
NI_NUMERICHOST) == 0)
|
||||
strncpy(host, buf, hsize);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
.\" Copyright (C) 1995, 1996, 1997, 1998, 1999, and 2000 WIDE Project.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 3. Neither the name of the project nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
|
||||
.\"
|
||||
.\" Copyright (c) 1999 Brian Somers <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/realhostname_sa.3,v 1.11 2005/02/13 22:25:14 ru Exp $
|
||||
.\"
|
||||
.Dd January 11, 2000
|
||||
.Os
|
||||
.Dt REALHOSTNAME_SA 3
|
||||
.Sh NAME
|
||||
.Nm realhostname_sa
|
||||
.Nd "convert a"
|
||||
.Vt "struct sockaddr"
|
||||
to the real host name
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In netinet/in.h
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn realhostname_sa "char *host" "size_t hsize" "struct sockaddr *addr" "int addrlen"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn realhostname_sa
|
||||
converts
|
||||
.Ar addr
|
||||
to the corresponding host name.
|
||||
This is done by resolving
|
||||
.Ar addr
|
||||
to a host name and then ensuring that the host name resolves
|
||||
back to
|
||||
.Ar addr .
|
||||
.Pp
|
||||
.Ar host
|
||||
must point to a buffer of at least
|
||||
.Ar hsize
|
||||
bytes, and will always be written to by this function.
|
||||
.Pp
|
||||
If the name resolution does not work both ways or if the host name is longer
|
||||
than
|
||||
.Ar hsize
|
||||
bytes,
|
||||
.Xr getnameinfo 3
|
||||
with NI_NUMERICHOST specified, is used to convert
|
||||
.Ar addr
|
||||
to an ASCII form.
|
||||
.Pp
|
||||
If the string written to
|
||||
.Ar host
|
||||
is
|
||||
.Ar hsize
|
||||
bytes long,
|
||||
.Ar host
|
||||
will not be NUL terminated.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn realhostname_sa
|
||||
function will return one of the following constants which are defined in
|
||||
.In libutil.h :
|
||||
.Pp
|
||||
.Bl -tag -width XXX -offset XXX
|
||||
.It Li HOSTNAME_FOUND
|
||||
A valid host name was found.
|
||||
.It Li HOSTNAME_INCORRECTNAME
|
||||
A host name was found, but it did not resolve back to the passed
|
||||
.Ar ip .
|
||||
.Ar host
|
||||
now contains the numeric value of
|
||||
.Ar ip .
|
||||
.It Li HOSTNAME_INVALIDADDR
|
||||
.Ar ip
|
||||
could not be resolved.
|
||||
.Ar host
|
||||
now contains the numeric value of
|
||||
.Ar ip .
|
||||
.It Li HOSTNAME_INVALIDNAME
|
||||
A host name was found, but it could not be resolved back to any ip number.
|
||||
.Ar host
|
||||
now contains the numeric value of
|
||||
.Ar ip .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr getaddrinfo 3 ,
|
||||
.Xr getnameinfo 3 ,
|
||||
.Xr realhostname 3
|
||||
@@ -0,0 +1,46 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Brian Fundakowski Feldman
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/stub.c,v 1.3 2003/10/18 10:04:16 markm Exp $");
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* Stub out what's in -lcrypt.
|
||||
*/
|
||||
|
||||
#pragma weak crypt_set_format
|
||||
/* ARGSUSED */
|
||||
int
|
||||
crypt_set_format(const char *f __unused) {
|
||||
|
||||
if (getenv("CRYPT_DEBUG") != NULL)
|
||||
fprintf(stderr, "crypt_set_format: eek, stub called!\n");
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
.\" Copyright (c) 1999 Brian Somers <[email protected]>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/trimdomain.3,v 1.8 2004/07/02 23:52:20 ru Exp $
|
||||
.\"
|
||||
.Dd April 7, 1999
|
||||
.Os
|
||||
.Dt TRIMDOMAIN 3
|
||||
.Sh NAME
|
||||
.Nm trimdomain
|
||||
.Nd "trim the current domain name from a host name"
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In libutil.h
|
||||
.Ft void
|
||||
.Fn trimdomain "char *fullhost" "int hostsize"
|
||||
.Sh DESCRIPTION
|
||||
The function
|
||||
.Fn trimdomain
|
||||
removes the current domain name from the passed
|
||||
.Ar fullhost
|
||||
name by writing a
|
||||
.Dv NUL
|
||||
character over the first period of the passed name.
|
||||
The current domain
|
||||
name is determined by calling
|
||||
.Xr gethostname 3
|
||||
and removing everything up to the first period.
|
||||
The name is determined
|
||||
the first time this function is called and is cached for future use.
|
||||
.Pp
|
||||
The
|
||||
.Fn trimdomain
|
||||
function will only trim the domain name if the passed
|
||||
.Ar fullname
|
||||
ends with the current domain name and if the length of the resulting host
|
||||
name does not exceed
|
||||
.Ar hostsize .
|
||||
.Pp
|
||||
If the passed
|
||||
.Ar fullname
|
||||
is actually a
|
||||
.Dv DISPLAY
|
||||
specification of the form
|
||||
.Sm off
|
||||
.Ar host . domain : nn Oo .
|
||||
.Ar nn
|
||||
.Oc
|
||||
.Sm on
|
||||
and the domain name is the same as the local domain name,
|
||||
.Fn trimdomain
|
||||
will remove the embedded domain name, copying the screen and display
|
||||
numbers to the end of the base host name and resulting in
|
||||
.Sm off
|
||||
.Ar host : nn Op . Ar nn .
|
||||
.Sm on
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn trimdomain
|
||||
function does not return a value.
|
||||
.Sh SEE ALSO
|
||||
.Xr gethostname 3
|
||||
@@ -0,0 +1,115 @@
|
||||
/*-
|
||||
* Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
|
||||
* Based on original work by Atsushi Murai <amurai@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/trimdomain.c,v 1.6 2005/10/05 04:42:20 brooks Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <libutil.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int isDISP(const char *);
|
||||
|
||||
/*-
|
||||
* Trim the current domain name from fullhost, but only if the result
|
||||
* is less than or equal to hostsize in length.
|
||||
*
|
||||
* This function understands $DISPLAY type fullhosts.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* trimdomain("abcde.my.domain", 5) -> "abcde"
|
||||
* trimdomain("abcde.my.domain", 4) -> "abcde.my.domain"
|
||||
* trimdomain("abcde.my.domain:0.0", 9) -> "abcde:0.0"
|
||||
* trimdomain("abcde.my.domain:0.0", 8) -> "abcde.my.domain:0.0"
|
||||
*/
|
||||
void
|
||||
trimdomain(char *fullhost, int hostsize)
|
||||
{
|
||||
static size_t dlen;
|
||||
static int first = 1;
|
||||
static char domain[MAXHOSTNAMELEN];
|
||||
char *end, *s;
|
||||
size_t len;
|
||||
|
||||
if (first) {
|
||||
/* XXX: Should we assume that our domain is this persistent ? */
|
||||
first = 0;
|
||||
if (gethostname(domain, sizeof(domain) - 1) == 0 &&
|
||||
(s = strchr(domain, '.')) != NULL)
|
||||
memmove(domain, s + 1, strlen(s + 1) + 1);
|
||||
else
|
||||
domain[0] = '\0';
|
||||
dlen = strlen(domain);
|
||||
}
|
||||
|
||||
if (domain[0] == '\0')
|
||||
return;
|
||||
|
||||
s = fullhost;
|
||||
end = s + hostsize + 1;
|
||||
if ((s = memchr(s, '.', (size_t)(end - s))) != NULL) {
|
||||
if (strncasecmp(s + 1, domain, dlen) == 0) {
|
||||
if (s[dlen + 1] == '\0') {
|
||||
/* Found -- lose the domain. */
|
||||
*s = '\0';
|
||||
} else if (s[dlen + 1] == ':' &&
|
||||
isDISP(s + dlen + 2) &&
|
||||
(len = strlen(s + dlen + 1)) < (size_t)(end - s)) {
|
||||
/* Found -- shuffle the DISPLAY back. */
|
||||
memmove(s, s + dlen + 1, len + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the given string NN or NN.NN where ``NN'' is an all-numeric string ?
|
||||
*/
|
||||
static int
|
||||
isDISP(const char *disp)
|
||||
{
|
||||
size_t w;
|
||||
int res;
|
||||
|
||||
w = strspn(disp, "0123456789");
|
||||
res = 0;
|
||||
if (w > 0) {
|
||||
if (disp[w] == '\0')
|
||||
res = 1; /* NN */
|
||||
else if (disp[w] == '.') {
|
||||
disp += w + 1;
|
||||
w = strspn(disp, "0123456789");
|
||||
if (w > 0 && disp[w] == '\0')
|
||||
res = 1; /* NN.NN */
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1996 Brian Somers <[email protected]>
|
||||
.\"
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
|
||||
.\"
|
||||
.\" $FreeBSD: src/lib/libutil/uucplock.3,v 1.19 2005/02/13 22:25:14 ru Exp $
|
||||
.\" "
|
||||
.Dd March 30, 1997
|
||||
.Os
|
||||
.Dt UUCPLOCK 3
|
||||
.Sh NAME
|
||||
.Nm uu_lock ,
|
||||
.Nm uu_unlock ,
|
||||
.Nm uu_lockerr
|
||||
.Nd acquire and release control of a serial device
|
||||
.Sh LIBRARY
|
||||
.Lb libutil
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In libutil.h
|
||||
.Ft int
|
||||
.Fn uu_lock "const char *ttyname"
|
||||
.Ft int
|
||||
.Fn uu_lock_txfr "const char *ttyname" "pid_t pid"
|
||||
.Ft int
|
||||
.Fn uu_unlock "const char *ttyname"
|
||||
.Ft const char *
|
||||
.Fn uu_lockerr "int uu_lockresult"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn uu_lock
|
||||
function attempts to create a lock file called
|
||||
.Pa /var/spool/lock/LCK..
|
||||
with a suffix given by the passed
|
||||
.Fa ttyname .
|
||||
If the file already exists, it is expected to contain the process
|
||||
id of the locking program.
|
||||
.Pp
|
||||
If the file does not already exist, or the owning process given by
|
||||
the process id found in the lock file is no longer running,
|
||||
.Fn uu_lock
|
||||
will write its own process id into the file and return success.
|
||||
.Pp
|
||||
.Fn uu_lock_txfr
|
||||
transfers lock ownership to another process.
|
||||
.Fn uu_lock
|
||||
must have previously been successful.
|
||||
.Pp
|
||||
.Fn uu_unlock
|
||||
removes the lockfile created by
|
||||
.Fn uu_lock
|
||||
for the given
|
||||
.Fa ttyname .
|
||||
Care should be taken that
|
||||
.Fn uu_lock
|
||||
was successful before calling
|
||||
.Fn uu_unlock .
|
||||
.Pp
|
||||
.Fn uu_lockerr
|
||||
returns an error string representing the error
|
||||
.Fa uu_lockresult ,
|
||||
as returned from
|
||||
.Fn uu_lock .
|
||||
.Sh RETURN VALUES
|
||||
.Fn uu_unlock
|
||||
returns 0 on success and -1 on failure.
|
||||
.Pp
|
||||
.Fn uu_lock
|
||||
may return any of the following values:
|
||||
.Pp
|
||||
.Dv UU_LOCK_INUSE :
|
||||
The lock is in use by another process.
|
||||
.Pp
|
||||
.Dv UU_LOCK_OK :
|
||||
The lock was successfully created.
|
||||
.Pp
|
||||
.Dv UU_LOCK_OPEN_ERR :
|
||||
The lock file could not be opened via
|
||||
.Xr open 2 .
|
||||
.Pp
|
||||
.Dv UU_LOCK_READ_ERR :
|
||||
The lock file could not be read via
|
||||
.Xr read 2 .
|
||||
.Pp
|
||||
.Dv UU_LOCK_CREAT_ERR :
|
||||
Cannot create temporary lock file via
|
||||
.Xr creat 2 .
|
||||
.Pp
|
||||
.Dv UU_LOCK_WRITE_ERR :
|
||||
The current process id could not be written to the lock file via a call to
|
||||
.Xr write 2 .
|
||||
.Pp
|
||||
.Dv UU_LOCK_LINK_ERR :
|
||||
Cannot link temporary lock file via
|
||||
.Xr link 2 .
|
||||
.Pp
|
||||
.Dv UU_LOCK_TRY_ERR :
|
||||
Locking attempts are failed after 5 tries.
|
||||
.Pp
|
||||
If a value of
|
||||
.Dv UU_LOCK_OK
|
||||
is passed to
|
||||
.Fn uu_lockerr ,
|
||||
an empty string is returned.
|
||||
Otherwise, a string specifying
|
||||
the reason for failure is returned.
|
||||
.Fn uu_lockerr
|
||||
uses the current value of
|
||||
.Va errno
|
||||
to determine the exact error.
|
||||
Care should be made not to allow
|
||||
.Va errno
|
||||
to be changed between calls to
|
||||
.Fn uu_lock
|
||||
and
|
||||
.Fn uu_lockerr .
|
||||
.Pp
|
||||
.Fn uu_lock_txfr
|
||||
may return any of the following values:
|
||||
.Pp
|
||||
.Dv UU_LOCK_OK :
|
||||
The transfer was successful.
|
||||
The specified process now holds the device
|
||||
lock.
|
||||
.Pp
|
||||
.Dv UU_LOCK_OWNER_ERR :
|
||||
The current process does not already own a lock on the specified device.
|
||||
.Pp
|
||||
.Dv UU_LOCK_WRITE_ERR :
|
||||
The new process id could not be written to the lock file via a call to
|
||||
.Xr write 2 .
|
||||
.Sh ERRORS
|
||||
If
|
||||
.Fn uu_lock
|
||||
returns one of the error values above, the global value
|
||||
.Va errno
|
||||
can be used to determine the cause.
|
||||
Refer to the respective manual pages
|
||||
for further details.
|
||||
.Pp
|
||||
.Fn uu_unlock
|
||||
will set the global variable
|
||||
.Va errno
|
||||
to reflect the reason that the lock file could not be removed.
|
||||
Refer to the description of
|
||||
.Xr unlink 2
|
||||
for further details.
|
||||
.Sh SEE ALSO
|
||||
.Xr lseek 2 ,
|
||||
.Xr open 2 ,
|
||||
.Xr read 2 ,
|
||||
.Xr write 2
|
||||
.Sh BUGS
|
||||
It is possible that a stale lock is not recognised as such if a new
|
||||
processes is assigned the same processes id as the program that left
|
||||
the stale lock.
|
||||
.Pp
|
||||
The calling process must have write permissions to the
|
||||
.Pa /var/spool/lock
|
||||
directory.
|
||||
There is no mechanism in place to ensure that the
|
||||
permissions of this directory are the same as those of the
|
||||
serial devices that might be locked.
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD: src/lib/libutil/uucplock.c,v 1.16 2003/10/18 10:04:16 markm Exp $");
|
||||
|
||||
#ifndef lint
|
||||
static const char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "libutil.h"
|
||||
|
||||
#define MAXTRIES 5
|
||||
|
||||
#define LOCKTMP "LCKTMP..%d"
|
||||
#define LOCKFMT "LCK..%s"
|
||||
|
||||
#define GORET(level, val) { err = errno; uuerr = (val); \
|
||||
goto __CONCAT(ret, level); }
|
||||
|
||||
/* Forward declarations */
|
||||
static int put_pid (int fd, pid_t pid);
|
||||
static pid_t get_pid (int fd,int *err);
|
||||
|
||||
/*
|
||||
* uucp style locking routines
|
||||
*/
|
||||
|
||||
int
|
||||
uu_lock(const char *tty_name)
|
||||
{
|
||||
int fd, tmpfd, i;
|
||||
pid_t pid, pid_old;
|
||||
char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN],
|
||||
lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
|
||||
int err, uuerr;
|
||||
|
||||
pid = getpid();
|
||||
(void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP,
|
||||
pid);
|
||||
(void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT,
|
||||
tty_name);
|
||||
if ((tmpfd = creat(lcktmpname, 0664)) < 0)
|
||||
GORET(0, UU_LOCK_CREAT_ERR);
|
||||
|
||||
for (i = 0; i < MAXTRIES; i++) {
|
||||
if (link (lcktmpname, lckname) < 0) {
|
||||
if (errno != EEXIST)
|
||||
GORET(1, UU_LOCK_LINK_ERR);
|
||||
/*
|
||||
* file is already locked
|
||||
* check to see if the process holding the lock
|
||||
* still exists
|
||||
*/
|
||||
if ((fd = open(lckname, O_RDONLY)) < 0)
|
||||
GORET(1, UU_LOCK_OPEN_ERR);
|
||||
|
||||
if ((pid_old = get_pid (fd, &err)) == -1)
|
||||
GORET(2, UU_LOCK_READ_ERR);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (kill(pid_old, 0) == 0 || errno != ESRCH)
|
||||
GORET(1, UU_LOCK_INUSE);
|
||||
/*
|
||||
* The process that locked the file isn't running, so
|
||||
* we'll lock it ourselves
|
||||
*/
|
||||
(void)unlink(lckname);
|
||||
} else {
|
||||
if (!put_pid (tmpfd, pid))
|
||||
GORET(3, UU_LOCK_WRITE_ERR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK);
|
||||
|
||||
ret3:
|
||||
(void)unlink(lckname);
|
||||
goto ret1;
|
||||
ret2:
|
||||
(void)close(fd);
|
||||
ret1:
|
||||
(void)close(tmpfd);
|
||||
(void)unlink(lcktmpname);
|
||||
ret0:
|
||||
errno = err;
|
||||
return uuerr;
|
||||
}
|
||||
|
||||
int
|
||||
uu_lock_txfr(const char *tty_name, pid_t pid)
|
||||
{
|
||||
int fd, err;
|
||||
char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
|
||||
|
||||
snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, tty_name);
|
||||
|
||||
if ((fd = open(lckname, O_RDWR)) < 0)
|
||||
return UU_LOCK_OWNER_ERR;
|
||||
if (get_pid(fd, &err) != getpid())
|
||||
err = UU_LOCK_OWNER_ERR;
|
||||
else {
|
||||
lseek(fd, (off_t)0, SEEK_SET);
|
||||
err = put_pid(fd, pid) ? 0 : UU_LOCK_WRITE_ERR;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
uu_unlock(const char *tty_name)
|
||||
{
|
||||
char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN];
|
||||
|
||||
(void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, tty_name);
|
||||
return unlink(tbuf);
|
||||
}
|
||||
|
||||
const char *
|
||||
uu_lockerr(int uu_lockresult)
|
||||
{
|
||||
static char errbuf[128];
|
||||
const char *fmt;
|
||||
|
||||
switch (uu_lockresult) {
|
||||
case UU_LOCK_INUSE:
|
||||
return "device in use";
|
||||
case UU_LOCK_OK:
|
||||
return "";
|
||||
case UU_LOCK_OPEN_ERR:
|
||||
fmt = "open error: %s";
|
||||
break;
|
||||
case UU_LOCK_READ_ERR:
|
||||
fmt = "read error: %s";
|
||||
break;
|
||||
case UU_LOCK_CREAT_ERR:
|
||||
fmt = "creat error: %s";
|
||||
break;
|
||||
case UU_LOCK_WRITE_ERR:
|
||||
fmt = "write error: %s";
|
||||
break;
|
||||
case UU_LOCK_LINK_ERR:
|
||||
fmt = "link error: %s";
|
||||
break;
|
||||
case UU_LOCK_TRY_ERR:
|
||||
fmt = "too many tries: %s";
|
||||
break;
|
||||
case UU_LOCK_OWNER_ERR:
|
||||
fmt = "not locking process: %s";
|
||||
break;
|
||||
default:
|
||||
fmt = "undefined error: %s";
|
||||
break;
|
||||
}
|
||||
|
||||
(void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno));
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
static int
|
||||
put_pid(int fd, pid_t pid)
|
||||
{
|
||||
char buf[32];
|
||||
int len;
|
||||
|
||||
len = sprintf (buf, "%10d\n", (int)pid);
|
||||
return write (fd, buf, (size_t)len) == len;
|
||||
}
|
||||
|
||||
static pid_t
|
||||
get_pid(int fd, int *err)
|
||||
{
|
||||
int bytes_read;
|
||||
char buf[32];
|
||||
pid_t pid;
|
||||
|
||||
bytes_read = read (fd, buf, sizeof (buf) - 1);
|
||||
if (bytes_read > 0) {
|
||||
buf[bytes_read] = '\0';
|
||||
pid = (pid_t)strtol (buf, (char **) NULL, 10);
|
||||
} else {
|
||||
pid = -1;
|
||||
*err = bytes_read ? errno : EINVAL;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* end of uucplock.c */
|
||||
Reference in New Issue
Block a user