/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1981 Regents of the University of California */
#include "ex.h"
#include "ex_tty.h"
/*
* Input routines for command mode.
* Since we translate the end of reads into the implied ^D's
* we have different flavors of routines which do/don't return such.
*/
static bool junkbs;
short lastc = '\n';
void
ignchar(void)
{
(void)getchar();
}
int
getchar(void)
{
int c;
do
c = getcd();
while (!globp && c == CTRL('d'));
return (c);
}
int
getcd(void)
{
int c;
extern short slevel;
again:
c = getach();
if (c == EOF)
return (c);
if (!inopen && slevel==0)
if (!globp && c == CTRL('d'))
setlastchar('\n');
else if (junk(c)) {
checkjunk(c);
goto again;
}
return (c);
}
int
peekchar(void)
{
if (peekc == 0)
peekc = getchar();
return (peekc);
}
int
peekcd(void)
{
if (peekc == 0)
peekc = getcd();
return (peekc);
}
int verbose;
int
getach(void)
{
int c, i, prev;
static unsigned char inputline[128];
c = peekc;
if (c != 0) {
peekc = 0;
return (c);
}
if (globp) {
if (*globp)
return (*globp++);
globp = 0;
return (lastc = EOF);
}
top:
if (input) {
if(c = *input++)
return (lastc = c);
input = 0;
}
flush();
if (intty) {
c = read(0, inputline, sizeof inputline - 4);
if (c < 0)
return (lastc = EOF);
if (c == 0 || inputline[c-1] != '\n')
inputline[c++] = CTRL('d');
if (inputline[c-1] == '\n')
noteinp();
prev = 0;
/* remove nulls from input buffer */
for (i = 0; i < c; i++)
if(inputline[i] != 0)
inputline[prev++] = inputline[i];
inputline[prev] = 0;
input = inputline;
goto top;
}
if (read(0, inputline, 1) != 1)
lastc = EOF;
else {
lastc = inputline[0];
if (verbose)
write(2, inputline, 1);
}
return (lastc);
}
/*
* Input routine for insert/append/change in command mode.
* Most work here is in handling autoindent.
*/
static short lastin;
int
gettty(void)
{
int c = 0;
unsigned char *cp = genbuf;
unsigned char hadup = 0;
extern int (*Pline)();
int offset = Pline == numbline ? 8 : 0;
int ch;
if (intty && !inglobal) {
if (offset) {
holdcm = 1;
viprintf(" %4d ", lineDOT() + 1);
flush();
holdcm = 0;
}
if (value(vi_AUTOINDENT) ^ aiflag) {
holdcm = 1;
if (value(vi_LISP))
lastin = lindent(dot + 1);
gotab(lastin + offset);
while ((c = getcd()) == CTRL('d')) {
if (lastin == 0 && isatty(0) == -1) {
holdcm = 0;
return (EOF);
}
lastin = backtab(lastin);
gotab(lastin + offset);
}
switch (c) {
case '^':
case '0':
ch = getcd();
if (ch == CTRL('d')) {
if (c == '0')
lastin = 0;
if (!over_strike) {
putchar((int)('\b' | QUOTE));
putchar((int)(' ' | QUOTE));
putchar((int)('\b' | QUOTE));
}
gotab(offset);
hadup = 1;
c = getchar();
} else
ungetchar(ch);
break;
case '.':
if (peekchar() == '\n') {
ignchar();
noteinp();
holdcm = 0;
return (EOF);
}
break;
case '\n':
hadup = 1;
break;
}
}
flush();
holdcm = 0;
}
if (c == 0)
c = getchar();
while (c != EOF && c != '\n') {
if (cp > &genbuf[LBSIZE - 2])
error(gettext("Input line too long"));
*cp++ = c;
c = getchar();
}
if (c == EOF) {
if (inglobal)
ungetchar(EOF);
return (EOF);
}
*cp = 0;
cp = linebuf;
if ((value(vi_AUTOINDENT) ^ aiflag) && hadup == 0 && intty && !inglobal) {
lastin = c = smunch(lastin, genbuf);
for (c = lastin; c >= value(vi_TABSTOP); c -= value(vi_TABSTOP))
*cp++ = '\t';
for (; c > 0; c--)
*cp++ = ' ';
}
CP(cp, genbuf);
if (linebuf[0] == '.' && linebuf[1] == 0)
return (EOF);
return (0);
}
/*
* Crunch the indent.
* Hard thing here is that in command mode some of the indent
* is only implicit, so we must seed the column counter.
* This should really be done differently so as to use the whitecnt routine
* and also to hack indenting for LISP.
*/
int
smunch(int col, unsigned char *ocp)
{
unsigned char *cp;
cp = ocp;
for (;;)
switch (*cp++) {
case ' ':
col++;
continue;
case '\t':
col += value(vi_TABSTOP) - (col % value(vi_TABSTOP));
continue;
default:
cp--;
CP(ocp, cp);
return (col);
}
}
unsigned char *cntrlhm = (unsigned char *)"^H discarded\n";
void
checkjunk(unsigned char c)
{
if (junkbs == 0 && c == '\b') {
write(2, cntrlhm, 13);
junkbs = 1;
}
}
void
setin(line *addr)
{
if (addr == zero)
lastin = 0;
else
getaline(*addr), lastin = smunch(0, linebuf);
}