261 lines
5.8 KiB
C
261 lines
5.8 KiB
C
#ifndef lint
|
|
#ifdef sccs
|
|
static char sccsid[] = "@(#)input.c 1.1 94/10/31 Copyr 1985 Sun Micro";
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1985 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/* last edited January 28, 1985, 13:19:14 */
|
|
#include <sunwindow/io_stream.h>
|
|
|
|
#define Get_Input_Ops \
|
|
struct input_ops_vector *ops;\
|
|
if (in->stream_type != Input) exit(1);\
|
|
ops = in->ops.input_ops
|
|
|
|
char *
|
|
stream_getstring();
|
|
|
|
/* GENERIC INPUT FUNCTIONS */
|
|
|
|
int
|
|
stream_chars_avail(in)
|
|
STREAM *in;
|
|
{
|
|
Get_Input_Ops;
|
|
return ((*ops->chars_avail) (in));
|
|
}
|
|
|
|
int
|
|
stream_getc(in)
|
|
STREAM *in;
|
|
{
|
|
Get_Input_Ops;
|
|
return ((*ops->str_getc) (in));
|
|
}
|
|
|
|
int
|
|
stream_peekc(in)
|
|
STREAM *in;
|
|
{
|
|
int c;
|
|
c = stream_getc(in);
|
|
if (c != EOF)
|
|
(void) stream_ungetc(c, in);
|
|
return (c);
|
|
}
|
|
|
|
int
|
|
stream_ungetc(c, in)
|
|
char c;
|
|
STREAM *in;
|
|
{
|
|
Get_Input_Ops;
|
|
return ((*ops->ungetc) (c, in));
|
|
/* NOT IMPLEMENTED YET : GENERIC CASE WHERE ungetc not DEFINED */
|
|
}
|
|
|
|
char *
|
|
stream_gets(s, in)
|
|
char *s;
|
|
STREAM *in;
|
|
{
|
|
return (stream_getstring(s, 10000, in, False));
|
|
}
|
|
|
|
char *
|
|
stream_fgets(s, n, in)
|
|
char *s;
|
|
int n;
|
|
STREAM *in;
|
|
{
|
|
return (stream_getstring(s, n, in, True));
|
|
}
|
|
|
|
static char *
|
|
stream_getstring(s, n, in, include_newline)
|
|
char *s;
|
|
int n;
|
|
STREAM *in;
|
|
Bool include_newline;
|
|
{
|
|
int i, c;
|
|
|
|
Get_Input_Ops;
|
|
if (ops->str_fgets != NULL) {
|
|
if ((*ops->str_fgets) (s, n, in) == NULL)
|
|
return (NULL);
|
|
else if (!include_newline) {
|
|
i = strlen(s);
|
|
if (s[i - 1] == '\n')
|
|
s[i - 1] = '\0';
|
|
}
|
|
return (s);
|
|
}
|
|
/* str_fgets not defined. simulate with n calls to getc */
|
|
for (i = 0; i < n; i++) {
|
|
c = (*ops->str_getc) (in);
|
|
if (c == EOF) {
|
|
s[i] = '\0';
|
|
break;
|
|
} else if (c == '\n' && (i == 0 || s[i - 1] != '\\')) {
|
|
/*
|
|
* \ followed by newline copies both \ and newline
|
|
* into s without terminating
|
|
*/
|
|
if (include_newline)
|
|
s[i++] = c;
|
|
break;
|
|
}
|
|
s[i] = c;
|
|
}
|
|
if (i == 0)
|
|
return (NULL);
|
|
s[i] = '\0';
|
|
return (s);
|
|
}
|
|
|
|
/*
|
|
* stream_get_token is used for tokenizing input, where more degree of
|
|
* flexibility is required than simply delimiting tokens by white spaces
|
|
* characters are divided into three classes, Break, Sepr, and Other.
|
|
* separators (Sepr) serve to delimit a token. Leading separators are
|
|
* skipped. think of separators as white space. Break characters delimit
|
|
* tokens, and are themselves tokens. Thus, if a break character is the first
|
|
* thing seen it is returned as the token. If any non-separator characters
|
|
* have been seen, then they are returned as the token, and the break
|
|
* character will be the returned as the result of the next call to
|
|
* get_token. for example, if charproc returns Sepr for space, and Break for
|
|
* '(' and ')' and Other for all alphabetic characters, then the string "now
|
|
* (is) the" will yield five tokens consisting of "now" "(" "is" ")" and
|
|
* "the"
|
|
*
|
|
* get_token stores the token that it constructs into dest, which is also
|
|
* returned as its value. STREAM *in;
|
|
*
|
|
* get_token returns NULL, rather than the empty string, corresponding to the
|
|
* case where the token is empty
|
|
*/
|
|
|
|
char *
|
|
stream_get_token(in, dest, charproc)
|
|
STREAM *in;
|
|
char *dest;
|
|
enum CharClass (*charproc) ();
|
|
{
|
|
int c;
|
|
int i = 0;
|
|
for (;;) {
|
|
c = stream_getc(in);
|
|
if (c == EOF)
|
|
goto done;
|
|
switch ((*charproc) (c)) {
|
|
case Sepr:
|
|
if (i != 0) /* something seen */
|
|
goto backup;
|
|
else
|
|
continue;
|
|
case Break:
|
|
if (i == 0) {
|
|
/*
|
|
* nothing seen yet, this character is the
|
|
* token
|
|
*/
|
|
dest[i++] = (char) c;
|
|
goto done;
|
|
} else
|
|
goto backup;
|
|
case Other:
|
|
dest[i++] = (char) c;
|
|
}
|
|
}
|
|
backup:
|
|
(void) stream_ungetc((char) c, in);
|
|
done:
|
|
dest[i] = '\0';
|
|
return (i == 0 ? NULL : dest);
|
|
}
|
|
|
|
/*
|
|
* stream_get_sequence is a more primitive tokenizer than get_token. it takes
|
|
* a procedure which for each character specifies whether the character is to
|
|
* terminate the sequence, and whether or not the character is to be included
|
|
* in the sequence. (If the character terminates the sequence, but is not
|
|
* included, then it will be seen again on the next call.) For example,
|
|
* having seen a \"\, to read to the matching \"\, call get_sequence with an
|
|
* action procedure that returns {True, True} for \"\ and {False, True} for
|
|
* everything else. (If you want to detect the case where a " is preceded by
|
|
* a \\, simply save the last character and modify the procedure accordingly.
|
|
*
|
|
* Note that gettoken can be defined in terms of get_sequence by having Other
|
|
* characters return {False, True}, and also noticing whether any have been
|
|
* seen yet, having Seprs return {(seen_some_others ? True : False), False}
|
|
* and Break characters return {True, (seen_some_others ? False : True)}
|
|
*
|
|
* returns NULL for the empty sequence
|
|
*/
|
|
|
|
char *
|
|
stream_get_sequence(in, dest, charproc)
|
|
STREAM *in;
|
|
char *dest;
|
|
struct CharAction (*charproc) ();
|
|
{
|
|
int c;
|
|
struct CharAction action;
|
|
int i = 0;
|
|
|
|
FOREVER {
|
|
c = stream_getc(in);
|
|
if (c == EOF)
|
|
goto done;
|
|
action = (*charproc) (c);
|
|
if (action.include)
|
|
dest[i++] = (char) c;
|
|
if (action.stop) {
|
|
if (!action.include)
|
|
goto backup; /* if c was not included,
|
|
* then need to put it back */
|
|
else
|
|
goto done;
|
|
}
|
|
}
|
|
backup:
|
|
(void) stream_ungetc((char) c, in);
|
|
done:
|
|
dest[i] = '\0';
|
|
return (i == 0 ? NULL : dest);
|
|
}
|
|
|
|
void
|
|
skip_over(in, charproc)
|
|
STREAM *in;
|
|
enum CharClass (*charproc) ();
|
|
|
|
{
|
|
char c;
|
|
FOREVER {
|
|
c = stream_getc(in);
|
|
if (charproc(c) != Sepr) {
|
|
(void) stream_ungetc(c, in);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
stream_set_pos(in, n)
|
|
STREAM *in;
|
|
int n;
|
|
{
|
|
Get_Input_Ops;
|
|
if (ops->set_pos)
|
|
return (*ops->set_pos) (in, n);
|
|
else
|
|
return (-1);
|
|
|
|
}
|