* 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:
Axel Dörfler
2006-08-07 16:55:45 +00:00
parent 576e825227
commit 70b0887a48
94 changed files with 25313 additions and 1 deletions
+2 -1
View File
@@ -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 ;
+33
View File
@@ -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
;
+70
View File
@@ -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>
+776
View File
@@ -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);
}
}
+168
View File
@@ -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 */
+920
View File
@@ -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;
}
+39
View File
@@ -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 */
+788
View File
@@ -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.
+516
View File
@@ -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 .
+556
View File
@@ -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);
}
+149
View File
@@ -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 */
+503
View File
@@ -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);
}
+24
View File
@@ -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 */
+58
View File
@@ -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; }
+109
View File
@@ -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 */
+211
View File
@@ -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; }
+5
View File
@@ -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 */
+202
View File
@@ -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;
}
+77
View File
@@ -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 */
+979
View File
@@ -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);
}
+687
View File
@@ -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 */
}
+81
View File
@@ -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 */
+250
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+75
View File
@@ -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 */
+261
View File
@@ -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);
}
+48
View File
@@ -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 */
+165
View File
@@ -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);
}
+58
View File
@@ -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 */
+610
View File
@@ -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);
}
+58
View File
@@ -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
+59
View File
@@ -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 */
+631
View File
@@ -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;
}
+66
View File
@@ -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 */
+192
View File
@@ -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);
}
+69
View File
@@ -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 */
+109
View File
@@ -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 */
+1585
View File
File diff suppressed because it is too large Load Diff
+123
View File
@@ -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 */
+439
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+480
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+51
View File
@@ -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 */
+13
View File
@@ -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
;
+59
View File
@@ -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>
+75
View File
@@ -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.
+74
View File
@@ -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;
}
+56
View File
@@ -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
+70
View File
@@ -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);
}
+35
View File
@@ -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
+158
View File
@@ -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 .
+222
View File
@@ -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 */
+151
View File
@@ -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 .
+148
View File
@@ -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);
}
+99
View File
@@ -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] .
+76
View File
@@ -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);
}
+67
View File
@@ -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.
+75
View File
@@ -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);
}
}
+437
View File
@@ -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
+72
View File
@@ -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
+108
View File
@@ -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;
}
+442
View File
@@ -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
+808
View File
@@ -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;
}
+158
View File
@@ -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_ */
+197
View File
@@ -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
+429
View File
@@ -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;
}
+50
View File
@@ -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);
}
+142
View File
@@ -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
+250
View File
@@ -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", &ltimesno, &ltimes);
if (lt != NULL && in_ltms(lt, tptr, NULL) == -1)
rc = 0; /* not in allowed times list */
else {
lt = login_timelist(lc, "times.deny", &ltimesno, &ltimes);
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;
}
+161
View File
@@ -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
+161
View File
@@ -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);
}
+65
View File
@@ -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
+62
View File
@@ -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);
}
+69
View File
@@ -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 .
+78
View File
@@ -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);
}
+71
View File
@@ -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
+104
View File
@@ -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);
}
+249
View File
@@ -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] .
+244
View File
@@ -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));
}
+99
View File
@@ -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.
+259
View File
@@ -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;
}
}
+149
View File
@@ -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 ) .
+172
View File
@@ -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);
}
+616
View File
@@ -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);
}
+105
View File
@@ -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
+186
View File
@@ -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;
}
+133
View File
@@ -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
+46
View File
@@ -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);
}
+85
View File
@@ -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
+115
View File
@@ -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);
}
+183
View File
@@ -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.
+230
View File
@@ -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 */