Ejemplo n.º 1
0
static int
pg_wc_isalpha(pg_wchar c)
{
	switch (pg_regex_strategy)
	{
		case PG_REGEX_LOCALE_C:
			return (c <= (pg_wchar) 127 &&
					(pg_char_properties[c] & PG_ISALPHA));
		case PG_REGEX_LOCALE_WIDE:
#ifdef USE_WIDE_UPPER_LOWER
			if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
				return iswalpha((wint_t) c);
#endif
			/* FALL THRU */
		case PG_REGEX_LOCALE_1BYTE:
			return (c <= (pg_wchar) UCHAR_MAX &&
					isalpha((unsigned char) c));
		case PG_REGEX_LOCALE_WIDE_L:
#if defined(HAVE_LOCALE_T) && defined(USE_WIDE_UPPER_LOWER)
			if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
				return iswalpha_l((wint_t) c, pg_regex_locale);
#endif
			/* FALL THRU */
		case PG_REGEX_LOCALE_1BYTE_L:
#ifdef HAVE_LOCALE_T
			return (c <= (pg_wchar) UCHAR_MAX &&
					isalpha_l((unsigned char) c, pg_regex_locale));
#endif
			break;
	}
	return 0;					/* can't get here, but keep compiler quiet */
}
Ejemplo n.º 2
0
int getNextToken(void **attr)
{
    string_t *s = NULL;
    keywords_t kw;

    int c;

    FSM {
        // ---------------------------------------------------------------
        // initial state
        // ---------------------------------------------------------------
        STATE(S_INIT) {
            SRC_GET(c);

            if (c == EOF) {
                NEXTSTATE(S_EOF);
            }
            else if (c == '\n') {
                NEXTSTATE(S_EOL);
            }
            else if (isspace(c)) {
                NEXTSTATE(S_INIT);
            }
            else if (isdigit(c)) {
                CHECKED(s = string_new(), alloc_failed);
                NEXTSTATE(S_INTEGRAL);
            }
            else if (isalpha_l(c, c_locale) || c == '_') {
                CHECKED(s = string_new(), alloc_failed);
                NEXTSTATE(S_IDENTIFIER);
            }
            else {
                switch (c) {
                default:
                    NEXTSTATE(S_ERROR);
                case '+':
                    NEXTSTATE(S_PLUS);
                case '-':
                    NEXTSTATE(S_MINUS);
                case '!':
                    NEXTSTATE(S_EXCL);
                case '=':
                    NEXTSTATE(S_EQUAL);
                case '*':
                    NEXTSTATE(S_ASTERISK);
                case '/':
                    NEXTSTATE(S_SLASH);
                case '"':
                    CHECKED(s = string_new(), alloc_failed);
                    NEXTSTATE(S_QUOT);
                case '(':
                    NEXTSTATE(S_LPAR);
                case ')':
                    NEXTSTATE(S_RPAR);
                case '[':
                    NEXTSTATE(S_LBRACK);
                case ']':
                    NEXTSTATE(S_RBRACK);
                case '<':
                    NEXTSTATE(S_LCHEV);
                case '>':
                    NEXTSTATE(S_RCHEV);
                case ':':
                    NEXTSTATE(S_COLON);
                case ',':
                    NEXTSTATE(S_COMMA);
                }
            }
        }

        // ---------------------------------------------------------------
        // character +
        // ---------------------------------------------------------------
        STATE(S_PLUS) {
            _ifj_lexical_log("TOK_OP_SUM");
            return TOK_OP_SUM;
        }

        // ---------------------------------------------------------------
        // character -
        // ---------------------------------------------------------------
        STATE(S_MINUS) {
            _ifj_lexical_log("TOK_OP_SUB");
            return TOK_OP_SUB;
        }

        // ---------------------------------------------------------------
        // character !
        // ---------------------------------------------------------------
        STATE(S_EXCL) {
            if (SRC_GET(c) == '=') {
                _ifj_lexical_log("TOK_OP_NEQ");
                return TOK_OP_NEQ;
            }
            else {
                SRC_UNGET(c);
                NEXTSTATE(S_ERROR);
            }
        }

        // ---------------------------------------------------------------
        // character =
        // ---------------------------------------------------------------
        STATE(S_EQUAL) {
            if (SRC_GET(c) == '=') {
                _ifj_lexical_log("TOK_OP_EQ");
                return TOK_OP_EQ;
            }
            else {
                SRC_UNGET(c);
                _ifj_lexical_log("TOK_OP_ASSIGN");
                return TOK_OP_ASSIGN;
            }
        }

        // ---------------------------------------------------------------
        // character *
        // ---------------------------------------------------------------
        STATE(S_ASTERISK) {
            if (SRC_GET(c) == '*') {
                _ifj_lexical_log("TOK_OP_POW");
                return TOK_OP_POW;
            }
            else {
                SRC_UNGET(c);
                _ifj_lexical_log("TOK_OP_MULT");
                return TOK_OP_MULT;
            }
        }

        // ---------------------------------------------------------------
        // character (
        // ---------------------------------------------------------------
        STATE(S_LPAR) {
            _ifj_lexical_log("TOK_LPAR");
            return TOK_LPAR;
        }

        // ---------------------------------------------------------------
        // character )
        // ---------------------------------------------------------------
        STATE(S_RPAR) {
            _ifj_lexical_log("TOK_RPAR");
            return TOK_RPAR;
        }

        // ---------------------------------------------------------------
        // character [
        // ---------------------------------------------------------------
        STATE(S_LBRACK) {
            _ifj_lexical_log("TOK_LBRACK");
            return TOK_LBRACK;
        }

        // ---------------------------------------------------------------
        // character ]
        // ---------------------------------------------------------------
        STATE(S_RBRACK) {
            _ifj_lexical_log("TOK_RBRACK");
            return TOK_RBRACK;
        }

        // ---------------------------------------------------------------
        // character <
        // ---------------------------------------------------------------
        STATE(S_LCHEV) {
            if (SRC_GET(c) == '=') {
                _ifj_lexical_log("TOK_OP_LE");
                return TOK_OP_LE;
            }
            else {
                SRC_UNGET(c);
                _ifj_lexical_log("TOK_OP_LT");
                return TOK_OP_LT;
            }
        }

        // ---------------------------------------------------------------
        // character >
        // ---------------------------------------------------------------
        STATE(S_RCHEV) {
            if (SRC_GET(c) == '=') {
                _ifj_lexical_log("TOK_OP_GE");
                return TOK_OP_GE;
            }
            else {
                SRC_UNGET(c);
                _ifj_lexical_log("TOK_OP_GT");
                return TOK_OP_GT;
            }
        }

        // ---------------------------------------------------------------
        // character :
        // ---------------------------------------------------------------
        STATE(S_COLON) {
            _ifj_lexical_log("TOK_COLON");
            return TOK_COLON;
        }

        // ---------------------------------------------------------------
        // character ,
        // ---------------------------------------------------------------
        STATE(S_COMMA) {
            _ifj_lexical_log("TOK_COMMA");
            return TOK_COMMA;
        }

        // ---------------------------------------------------------------
        // character /
        // ---------------------------------------------------------------
        STATE(S_SLASH) {
            switch (SRC_GET(c)) {
            case '/':
                NEXTSTATE(S_COMMENT);

            case '*':
                NEXTSTATE(S_COMMENT_BLOCK);

            default:
                SRC_UNGET(c);
                _ifj_lexical_log("TOK_OP_DIV");
                return TOK_OP_DIV;
            }
        }

        // ---------------------------------------------------------------
        // string -- inside quotes
        // ---------------------------------------------------------------
        STATE(S_QUOT) {
            SRC_GET(c);
            if (c == '"') {
                NEXTSTATE(S_STRING);
            }
            else if (c == '\\') {
                NEXTSTATE(S_ESCAPECHAR);
            }
            else if (isprint(c)) {
                CHECKED(string_append(&s, c), alloc_failed);
                NEXTSTATE(S_QUOT);
            }
            else {
                NEXTSTATE(S_ESTRING);
            }
        }

        // ---------------------------------------------------------------
        // string -- escape characters
        // ---------------------------------------------------------------
        STATE(S_ESCAPECHAR) {
            switch (SRC_GET(c)) {
            case 'n':
                CHECKED(string_append(&s, '\n'), alloc_failed);
                NEXTSTATE(S_QUOT);

            case 't':
                CHECKED(string_append(&s, '\t'), alloc_failed);
                NEXTSTATE(S_QUOT);

            case '"':
                CHECKED(string_append(&s, '"'), alloc_failed);
                NEXTSTATE(S_QUOT);

            case '\\':
                CHECKED(string_append(&s, '\\'), alloc_failed);
                NEXTSTATE(S_QUOT);

            case 'x':
                NEXTSTATE(S_HEXCHAR);

            default:
                NEXTSTATE(S_ESTRING);
            }
        }

        // ---------------------------------------------------------------
        // string -- character in hexadecimal notation
        // ---------------------------------------------------------------
        STATE(S_HEXCHAR) {
            unsigned char val = 0;

            if (isxdigit(SRC_GET(c))) {
                val = HEX_TO_INT(c) << 4;
            }
            else {
                NEXTSTATE(S_ESTRING);
            }

            if (isxdigit(SRC_GET(c))) {
                val += HEX_TO_INT(c);
            }
            else {
                NEXTSTATE(S_ESTRING);
            }

            CHECKED(string_append(&s, val), alloc_failed);
            NEXTSTATE(S_QUOT);
        }

        // ---------------------------------------------------------------
        // numeric -- integral part
        // ---------------------------------------------------------------
        STATE(S_INTEGRAL) {
            CHECKED(string_append(&s, c), alloc_failed);

            SRC_GET(c);
            if (isdigit(c)) {
                NEXTSTATE(S_INTEGRAL);
            }
            else if (c == '.') {
                CHECKED(string_append(&s, c), alloc_failed);
                SRC_GET(c);

                if (isdigit(c)) {
                    NEXTSTATE(S_DECIMAL);
                }
                else {
                    NEXTSTATE(S_ENUM);
                }
            }
            else if (c == 'e') {
                CHECKED(string_append(&s, c), alloc_failed);
                NEXTSTATE(S_EXPONENT_E);
            }
            else {
                NEXTSTATE(S_ENUM);
            }
        }

        // ---------------------------------------------------------------
        // numeric -- decimal part
        // ---------------------------------------------------------------
        STATE(S_DECIMAL) {
            CHECKED(string_append(&s, c), alloc_failed);

            SRC_GET(c);
            if (isdigit(c)) {
                NEXTSTATE(S_DECIMAL);
            }
            else if (c == 'e') {
                CHECKED(string_append(&s, c), alloc_failed);
                NEXTSTATE(S_EXPONENT_E);
            }
            else {
                SRC_UNGET(c);
                NEXTSTATE(S_NUMERIC);
            }
        }

        // ---------------------------------------------------------------
        // numeric -- exponent part
        // ---------------------------------------------------------------
        STATE(S_EXPONENT_E) {
            SRC_GET(c);
            if (c == '+' || c == '-') {
                CHECKED(string_append(&s, c), alloc_failed);
                SRC_GET(c);
            }

            if (isdigit(c)) {
                NEXTSTATE(S_EXPONENT);
            }
            else {
                NEXTSTATE(S_ENUM);
            }
        }

        STATE(S_EXPONENT) {
            CHECKED(string_append(&s, c), alloc_failed);

            if (isdigit(SRC_GET(c))) {
                NEXTSTATE(S_EXPONENT);
            }
            else {
                SRC_UNGET(c);
                NEXTSTATE(S_NUMERIC);
            }
        }

        // ---------------------------------------------------------------
        // identifier
        // ---------------------------------------------------------------
        STATE(S_IDENTIFIER) {
            CHECKED(string_append(&s, c), alloc_failed);
            if (isalnum_l(SRC_GET(c), c_locale) || c == '_') {
                NEXTSTATE(S_IDENTIFIER);
            }

            SRC_UNGET(c);

#define X_(pstate, str, e) \
    if (0 == strcmp(string_getstr(s), (str))) { \
        kw = e; \
        string_dispose(s); s = NULL; \
        NEXTSTATE(pstate); \
    } else

#define X(a,b) X_(S_KEYWORD, b, KW_##a)
#include "keywords.def"
            X_KEYWORD
#undef X
#define X(a,b) X_(S_BUILTIN, b, FN_##a)
#include "builtin.def"
                //X_BUILTIN_FN
#undef X
#define X(a,b) X_(S_RESERVED_KEYWORD, b, RKW_##a)
#include "keywords.def"
                X_KEYWORD_RESERVED
#undef X
#undef X_
                // -------------------------------------------------------
                // identifier
                // -------------------------------------------------------
            {                   // else
                *attr = s;
                _ifj_lexical_log("TOK_TYPE_ID \"%s\"", string_getstr(s));
                return TOK_TYPE_ID;
            }
        }

        // ---------------------------------------------------------------
        // reserved keyword
        // ---------------------------------------------------------------
        STATE(S_RESERVED_KEYWORD) {
            switch (kw) {
            default:
                break;

#define X(a,b) \
            case (RKW_##a): \
                _ifj_lexical_log("TOK_TYPE_RKW \"%s\"", (b)); \
                break;
#include "keywords.def"
                X_KEYWORD_RESERVED
#undef X
            }

            *attr = (void *) kw;
            return TOK_TYPE_RKW;
        }

        // ---------------------------------------------------------------
        // built-in function
        // ---------------------------------------------------------------
#if 0
        STATE(S_BUILTIN) {
            switch (kw) {
            default:
                break;

#define X(a,b) \
            case (FN_##a): \
                _ifj_lexical_log("TOK_TYPE_FN \"%s\"", (b)); \
                break;
#include "builtin.def"
                //X_BUILTIN_FN
#undef X
            }

            *attr = (void *) kw;
            return TOK_TYPE_FN;
        }
#endif

        // ---------------------------------------------------------------
        // term -- numeric
        // ---------------------------------------------------------------
        STATE(S_NUMERIC) {
            *attr = s;
            _ifj_lexical_log("TOK_TYPE_NUM \"%s\"", string_getstr(s));
            return TOK_TYPE_NUM;
        }

        STATE(S_KEYWORD) {
            switch (kw) {
                // -----------------------------------------------------------
                // keyword
                // -----------------------------------------------------------
            default:
                switch (kw) {
                default:
                    break;

#define X(a,b) \
                case (KW_##a): \
                    _ifj_lexical_log("TOK_TYPE_KW \"%s\"", (b)); \
                    break;
#include "keywords.def"
                    X_KEYWORD
#undef X
                }

                *attr = (void *) kw;
                return TOK_TYPE_KW;

                // -----------------------------------------------------------
                // term -- boolean
                // -----------------------------------------------------------
            case KW_TRUE:
                *attr = (void *) true;
                _ifj_lexical_log("TOK_TYPE_BOOL \"true\"");
                return TOK_TYPE_BOOL;

            case KW_FALSE:
                _ifj_lexical_log("TOK_TYPE_BOOL \"false\"");
                *attr = (void *) false;
                return TOK_TYPE_BOOL;

                // -----------------------------------------------------------
                // term -- nil
                // -----------------------------------------------------------
            case KW_NIL:
                _ifj_lexical_log("TOK_TYPE_NIL \"Nil\"");
                *attr = NULL;
                return TOK_TYPE_NIL;
            }
        }

        // ---------------------------------------------------------------
        // term -- string
        // ---------------------------------------------------------------
        STATE(S_STRING) {
            *attr = s;
            _ifj_lexical_log("TOK_TYPE_STR \"%s\"", string_getstr(s));
            return TOK_TYPE_STR;
        }

        // ---------------------------------------------------------------
        // comment
        // ---------------------------------------------------------------
        STATE(S_COMMENT) {
            SRC_GET(c);
            if (c == EOF) {
                NEXTSTATE(S_EOF);
            }
            else if (c == '\n') {
                NEXTSTATE(S_EOL);
            }
            else {
                NEXTSTATE(S_COMMENT);
            }
        }

        // ---------------------------------------------------------------
        // block comment
        // ---------------------------------------------------------------
        STATE(S_COMMENT_BLOCK) {
            SRC_GET(c);
            if (c == EOF) {
                NEXTSTATE(S_EEOF);
            }
            else if (c != '*') {
                NEXTSTATE(S_COMMENT_BLOCK);
            }
            else {
                NEXTSTATE(S_COMMENT_BLOCK_2);
            }
        }

        STATE(S_COMMENT_BLOCK_2) {
            SRC_GET(c);
            if (c == EOF) {
                NEXTSTATE(S_EEOF);
            }
            else if (c == '/') {
                NEXTSTATE(S_INIT);
            }
            else {
                NEXTSTATE(S_COMMENT_BLOCK);
            }
        }

        // ---------------------------------------------------------------
        // eol
        // ---------------------------------------------------------------
        STATE(S_EOL) {
            ++_line;
            _col = 0;

            if (SRC_GET(c) == '\n') {
                NEXTSTATE(S_EOL);
            }
            else {
                SRC_UNGET(c);
                _ifj_lexical_log("TOK_EOL");
                return TOK_EOL;
            }
        }

        // ---------------------------------------------------------------
        // eof
        // ---------------------------------------------------------------
        STATE(S_EOF) {
            _ifj_lexical_log("TOK_EOF");
            return TOK_EOF;
        }

        // ---------------------------------------------------------------
        // error states
        // ---------------------------------------------------------------
        STATE(S_ERROR) {
            _ifj_error_log("%s:%zu:%zu: Neznamy znak %c",
                           src_name, getCurrLine(), getCurrCol(), c);
            _ifj_lexical_log("TOK_EINVAL");
            return TOK_EINVAL;
        }

        STATE(S_EEOF) {
            _ifj_error_log("%s:%zu:%zu: Neocekavany konec souboru",
                           src_name, getCurrLine(), getCurrCol());
            _ifj_lexical_log("TOK_EEOF");
            return TOK_EEOF;
        }

        STATE(S_ESTRING) {
            _ifj_error_log
                ("%s:%zu:%zu: Neocekavany znak v retezci %c",
                 src_name, getCurrLine(), getCurrCol(), c);
            _ifj_lexical_log("TOK_ESTRING");
            return TOK_EINVAL;
        }

        STATE(S_ENUM) {
            _ifj_error_log("%s:%zu:%zu: Neocekavany tvar cisla %c",
                           src_name, getCurrLine(), getCurrCol(), c);
            _ifj_lexical_log("TOK_ENUM");
            return TOK_ENUM;
        }
    }

    NEXTSTATE(S_ERROR);

  alloc_failed:
    string_dispose(s);
    _ifj_error_log("%s", strerror(ENOMEM));
    _ifj_lexical_log("TOK_ENOMEM");
    return TOK_ENOMEM;
}
Ejemplo n.º 3
0
static int
scan(FILE *fp, const char *name, bool quiet)
{
	int c;
	bool hasid = false;
	bool subversion = false;
	analyzer_states state = INIT;
	struct sbuf *id = sbuf_new_auto();
	locale_t l;

	l = newlocale(LC_ALL_MASK, "C", NULL);

	if (name != NULL)
		printf("%s:\n", name);

	while ((c = fgetc(fp)) != EOF) {
		switch (state) {
		case INIT:
			if (c == '$') {
				/* Transit to DELIM_SEEN if we see $ */
				state = DELIM_SEEN;
			} else {
				/* Otherwise, stay in INIT state */
				continue;
			}
			break;
		case DELIM_SEEN:
			if (isalpha_l(c, l)) {
				/* Transit to KEYWORD if we see letter */
				sbuf_clear(id);
				sbuf_putc(id, '$');
				sbuf_putc(id, c);
				state = KEYWORD;

				continue;
			} else if (c == '$') {
				/* Or, stay in DELIM_SEEN if more $ */
				continue;
			} else {
				/* Otherwise, transit back to INIT */
				state = INIT;
			}
			break;
		case KEYWORD:
			sbuf_putc(id, c);

			if (isalpha_l(c, l)) {
				/*
				 * Stay in KEYWORD if additional letter is seen
				 */
				continue;
			} else if (c == ':') {
				/*
				 * See ':' for the first time, transit to
				 * PUNC_SEEN.
				 */
				state = PUNC_SEEN;
				subversion = false;
			} else if (c == '$') {
				/*
				 * Incomplete ident.  Go back to DELIM_SEEN
				 * state because we see a '$' which could be
				 * the beginning of a keyword.
				 */
				state = DELIM_SEEN;
			} else {
				/*
				 * Go back to INIT state otherwise.
				 */
				state = INIT;
			}
			break;
		case PUNC_SEEN:
		case PUNC_SEEN_SVN:
			sbuf_putc(id, c);

			switch (c) {
			case ':':
				/*
				 * If we see '::' (seen : in PUNC_SEEN),
				 * activate subversion treatment and transit
				 * to PUNC_SEEN_SVN state.
				 *
				 * If more than two :'s were seen, the ident
				 * is invalid and we would therefore go back
				 * to INIT state.
				 */
				if (state == PUNC_SEEN) {
					state = PUNC_SEEN_SVN;
					subversion = true;
				} else {
					state = INIT;
				}
				break;
			case ' ':
				/*
				 * A space after ':' or '::' indicates we are at the
				 * last component of potential ident.
				 */
				state = TEXT;
				break;
			default:
				/* All other characters are invalid */
				state = INIT;
				break;
			}
			break;
		case TEXT:
			sbuf_putc(id, c);

			if (iscntrl_l(c, l)) {
				/* Control characters are not allowed in this state */
				state = INIT;
			} else if (c == '$') {
				sbuf_finish(id);
				/*
				 * valid ident should end with a space.
				 *
				 * subversion extension uses '#' to indicate that
				 * the keyword expansion have exceeded the fixed
				 * width, so it is also permitted if we are in
				 * subversion mode.  No length check is enforced
				 * because GNU RCS ident(1) does not do it either.
				 */
				c = sbuf_data(id)[sbuf_len(id) - 2];
				if (c == ' ' || (subversion && c == '#')) {
					printf("     %s\n", sbuf_data(id));
					hasid = true;
				}
				state = INIT;
			}
			/* Other characters: stay in the state */
			break;
		}
	}
	sbuf_delete(id);
	freelocale(l);

	if (!hasid) {
		if (!quiet)
			fprintf(stderr, "%s warning: no id keywords in %s\n",
			    getprogname(), name ? name : "standard input");

		return (EXIT_FAILURE);
	}

	return (EXIT_SUCCESS);
}
Ejemplo n.º 4
0
char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
	ssize_t nr;
	int input, output, save_errno;
	char ch, *p, *end;
	struct termios term, oterm;
	struct sigaction sa, saveint, savehup, savequit, saveterm;
	struct sigaction savetstp, savettin, savettou;
	locale_t loc = __current_locale();

	/* I suppose we could alloc on demand in this case (XXX). */
	if (bufsiz == 0) {
		errno = EINVAL;
		return(NULL);
	}

restart:
	/*
	 * Read and write to /dev/tty if available.  If not, read from
	 * stdin and write to stderr unless a tty is required.
	 */
	if ((input = output = _open(_PATH_TTY, O_RDWR)) == -1) {
		if (flags & RPP_REQUIRE_TTY) {
			errno = ENOTTY;
			return(NULL);
		}
		input = STDIN_FILENO;
		output = STDERR_FILENO;
	}

	/*
	 * Catch signals that would otherwise cause the user to end
	 * up with echo turned off in the shell.  Don't worry about
	 * things like SIGALRM and SIGPIPE for now.
	 */
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;		/* don't restart system calls */
	sa.sa_handler = handler;
	(void)_sigaction(SIGINT, &sa, &saveint);
	(void)_sigaction(SIGHUP, &sa, &savehup);
	(void)_sigaction(SIGQUIT, &sa, &savequit);
	(void)_sigaction(SIGTERM, &sa, &saveterm);
	(void)_sigaction(SIGTSTP, &sa, &savetstp);
	(void)_sigaction(SIGTTIN, &sa, &savettin);
	(void)_sigaction(SIGTTOU, &sa, &savettou);

	/* Turn off echo if possible. */
	if (tcgetattr(input, &oterm) == 0) {
		memcpy(&term, &oterm, sizeof(term));
		if (!(flags & RPP_ECHO_ON))
			term.c_lflag &= ~(ECHO | ECHONL);
		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
	} else {
		memset(&term, 0, sizeof(term));
		memset(&oterm, 0, sizeof(oterm));
	}

	(void)_write(output, prompt, strlen(prompt));
	end = buf + bufsiz - 1;
	for (p = buf; (nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
		if (p < end) {
			if ((flags & RPP_SEVENBIT))
				ch &= 0x7f;
			if (isalpha_l(ch, loc)) {
				if ((flags & RPP_FORCELOWER))
					ch = tolower_l(ch, loc);
				if ((flags & RPP_FORCEUPPER))
					ch = toupper_l(ch, loc);
			}
			*p++ = ch;
		}
	}
	*p = '\0';
	save_errno = errno;
	if (!(term.c_lflag & ECHO))
		(void)_write(output, "\n", 1);

	/* Restore old terminal settings and signals. */
	if (memcmp(&term, &oterm, sizeof(term)) != 0)
		(void)tcsetattr(input, TCSANOW|TCSASOFT, &oterm);
	(void)_sigaction(SIGINT, &saveint, NULL);
	(void)_sigaction(SIGHUP, &savehup, NULL);
	(void)_sigaction(SIGQUIT, &savequit, NULL);
	(void)_sigaction(SIGTERM, &saveterm, NULL);
	(void)_sigaction(SIGTSTP, &savetstp, NULL);
	(void)_sigaction(SIGTTIN, &savettin, NULL);
	(void)_sigaction(SIGTTOU, &savettou, NULL);
	if (input != STDIN_FILENO)
		(void)_close(input);

	/*
	 * If we were interrupted by a signal, resend it to ourselves
	 * now that we have restored the signal handlers.
	 */
	if (signo) {
		kill(getpid(), signo); 
		switch (signo) {
		case SIGTSTP:
		case SIGTTIN:
		case SIGTTOU:
			signo = 0;
			goto restart;
		}
	}

	errno = save_errno;
	return(nr == -1 ? NULL : buf);
}