home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
531.lha
/
Less_v1.4Z
/
src.LZH
/
src
/
option.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-03
|
16KB
|
524 lines
/*
* Process command line options.
* Each option is a single letter which controls a program variable.
* The options have defaults which may be changed via
* the command line option, or toggled via the "-" command.
*/
#ifdef AMIGA
/* Compile with -HPreHeader.q to get "less.h"! */
#else
#include "less.h"
#endif
#ifdef AMIGA
/* use the old-style toupper() that doesn't check its arguement */
#undef toupper
#define toupper(c) ((c)-'a'+'A')
#endif
#define END_OPTION_STRING ('$')
/*
* Types of options.
*/
#define BOOL 01 /* Boolean option: 0 or 1 */
#define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */
#define NUMBER 04 /* Numeric option */
#define REPAINT 040 /* Repaint screen after toggling option */
#define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */
/* Prototypes for functions defined in option.c */
static char *optstring __PROTO((char *s));
static int getnum __PROTO((char **sp, int c));
/*
* Variables controlled by command line options.
*/
public int p_nbufs, f_nbufs; /* Number of buffers. There are two values,
one used for input from a pipe and
the other for input from a file. */
#ifndef AMIGA
public int clean_data; /* Can we assume the data is "clean"?
(That is, free of nulls, etc) */
#endif
public int quiet; /* Should we suppress the audible bell? */
public int top_search; /* Should forward searches start at the top
of the screen? (alternative is bottom) */
public int top_scroll; /* Repaint screen from top?
(alternative is scroll from bottom) */
public int pr_type; /* Type of prompt (short, medium, long) */
public int bs_mode; /* How to process backspaces */
#ifdef DUMBTERM
public int know_dumb; /* Don't complain about dumb terminals */
#endif
public int quit_at_eof; /* Quit after hitting end of file twice */
public int squeeze; /* Squeeze multiple blank lines into one */
public int tabstop; /* Tab settings */
public int back_scroll; /* Repaint screen on backwards movement */
public int twiddle; /* Display "~" for lines after EOF */
extern char *prproto[];
extern int nbufs;
extern int sc_window;
#ifdef AMIGA
public int scroll;
public int sc_window_spec; /* user's requested -z */
extern int Wind_Spec[4]; /* User-specified window size/position */
#endif
extern char *first_cmd;
extern char *every_first_cmd;
#if LOGFILE
extern char *namelogfile;
extern int force_logfile;
#endif
#define DEF_F_NBUFS 5 /* Default for f_nbufs */
#define DEF_P_NBUFS 12 /* Default for p_nbufs */
static struct option
{
char oletter; /* The controlling letter (a-z) */
char otype; /* Type of the option */
int odefault; /* Default value */
int *ovar; /* Pointer to the associated variable */
char *odesc[3]; /* Description of each value */
} option[] =
{
{ 'c', TRIPLE, 2, &top_scroll,
{ "Repaint by scrolling from bottom of screen",
"Repaint by clearing each line",
"Repaint by painting from top of screen"
}
},
#ifdef DUMBTERM
{ 'd', BOOL|NO_TOGGLE, 0, &know_dumb,
{ NULL, NULL, NULL}
},
#endif
{ 'e', TRIPLE, 1, &quit_at_eof,
{ "Don't quit at end-of-file",
#ifdef AMIGA
"Space bar quits at end-of-file",
"Quit at end-of-file"
#else
"Quit at end-of-file",
"Quit immediately at end-of-file"
#endif
}
},
#ifndef AMIGA
{ 'f', BOOL, 0, &clean_data,
{ "Don't assume data is clean",
"Assume data is clean",
NULL
}
},
#endif
{ 'h', NUMBER, -1, &back_scroll, /* default set at window open */
{ "Backwards scroll limit is %d lines",
NULL, NULL
}
},
{ 'm', TRIPLE, 1, &pr_type,
{ "Short prompt",
"Medium prompt",
"Long prompt"
}
},
{ 'q', TRIPLE, 0, &quiet,
{ "Ring the bell for errors AND at eof/bof",
"Ring the bell for errors but not at eof/bof",
"Never ring the bell"
}
},
{ 's', BOOL|REPAINT, 0, &squeeze,
{ "Don't squeeze multiple blank lines",
"Squeeze multiple blank lines",
NULL
}
},
{ 't', BOOL, 1, &top_search,
{ "Forward search starts from bottom of screen",
"Forward search starts from top of screen",
NULL
}
},
{ 'u', TRIPLE|REPAINT, 0, &bs_mode,
{ "Underlined text displayed in underline mode",
"Backspaces cause overstrike",
"Backspaces print as ^H"
}
},
{ 'w', BOOL|REPAINT, 1, &twiddle,
{ "Display nothing for lines after end-of-file",
"Display ~ for lines after end-of-file",
NULL
}
},
{ 'x', NUMBER|REPAINT, 8, &tabstop,
{ "Tab stops every %d spaces",
NULL, NULL
}
},
{ 'z', NUMBER|REPAINT, -1, &sc_window,
{ "Scroll window size is %d lines",
NULL, NULL
}
},
{ '\0' }
};
public char all_options[64]; /* List of all valid options */
/*
* Initialize each option to its default value.
*/
#ifdef __STDC__
void init_option (void)
#else
public void
init_option()
#endif
{
register struct option *o;
register char *p;
/*
* First do special cases, not in option table.
*/
first_cmd = every_first_cmd = NULL;
f_nbufs = DEF_F_NBUFS; /* -bf */
p_nbufs = DEF_P_NBUFS; /* -bp */
p = all_options;
*p++ = 'b';
for (o = option; o->oletter != '\0'; o++)
{
/*
* Set each variable to its default.
* Also make a list of all options, in "all_options".
*/
*(o->ovar) = o->odefault;
*p++ = o->oletter;
if (o->otype & TRIPLE)
*p++ = toupper(o->oletter);
}
*p = '\0';
}
/*
* Toggle command line flags from within the program.
* Used by the "-" command.
*/
#ifdef __STDC__
void toggle_option (char *s)
#else
public void
toggle_option(s)
char *s;
#endif
{
int c;
register struct option *o;
char *msg;
int n;
int dorepaint;
char message[100];
char buf[5];
c = *s++;
/*
* First check for special cases not handled by the option table.
*/
switch (c)
{
case 'b':
sprintf(message, "%d buffers", nbufs);
error(message);
return;
}
msg = NULL;
for (o = option; o->oletter != '\0'; o++)
{
if (o->otype & NO_TOGGLE)
continue;
dorepaint = (o->otype & REPAINT);
if ((o->otype & BOOL) && (o->oletter == c))
{
/*
* Boolean option:
* just toggle it.
*/
*(o->ovar) = ! *(o->ovar);
} else if ((o->otype & TRIPLE) && (o->oletter == c))
{
/*
* Triple-valued option with lower case letter:
* make it 1 unless already 1, then make it 0.
*/
*(o->ovar) = (*(o->ovar) == 1) ? 0 : 1;
} else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
{
/*
* Triple-valued option with upper case letter:
* make it 2 unless already 2, then make it 0.
*/
*(o->ovar) = (*(o->ovar) == 2) ? 0 : 2;
} else if ((o->otype & NUMBER) && (o->oletter == c))
{
n = getnum(&s, '\0');
if (n < 0)
{
/*
* No number; just a query.
* No need to repaint screen.
*/
dorepaint = 0;
} else
{
/*
* Number follows the option letter.
* Set the variable to that number.
*/
*(o->ovar) = n;
#ifdef AMIGA
if ( c == 'z' )
{
sc_window_spec = sc_window;
set_scroll();
}
#endif
}
sprintf(message, o->odesc[0],
(o->ovar == &back_scroll) ?
get_back_scroll() : *(o->ovar));
msg = message;
} else
continue;
if (dorepaint)
repaint();
if (msg == NULL)
msg = o->odesc[*(o->ovar)];
error(msg);
return;
}
if (control_char(c))
sprintf(buf, "^%c", carat_char(c));
else
sprintf(buf, "%c", c);
sprintf(message, "\"-%s\": no such flag. Use one of \"%s\"",
buf, all_options);
error(message);
}
/*
* Scan to end of string or to an END_OPTION_STRING character.
* In the latter case, replace the char with a null char.
* Return a pointer to the remainder of the string, if any.
*/
#ifdef __STDC__
static char *optstring (char *s)
#else
static char *
optstring(s)
char *s;
#endif
{
register char *p;
for (p = s; *p != '\0'; p++)
if (*p == END_OPTION_STRING)
{
*p = '\0';
return (p+1);
}
return (p);
}
/*
* Scan an argument (either from command line or from LESS environment
* variable) and process it.
*/
#ifdef __STDC__
void scan_option (char *s)
#else
public void
scan_option(s)
char *s;
#endif
{
register struct option *o;
register int c;
char message[80];
if (s == NULL)
return;
next:
if (*s == '\0')
{
sc_window_spec = sc_window;
return;
}
switch (c = *s++)
{
case '-':
case ' ':
case '\t':
case END_OPTION_STRING:
goto next;
case '+':
if (*s == '+')
every_first_cmd = ++s;
first_cmd = s;
s = optstring(s);
goto next;
case 'P':
switch (*s)
{
case 'm': prproto[PR_MEDIUM] = ++s; break;
case 'M': prproto[PR_LONG] = ++s; break;
default: prproto[PR_SHORT] = s; break;
}
s = optstring(s);
goto next;
#if LOGFILE
case 'L':
force_logfile = 1;
/* fall thru */
case 'l':
namelogfile = s;
s = optstring(s);
goto next;
#endif
case 'b':
switch (*s)
{
case 'f':
s++;
f_nbufs = getnum(&s, 'b');
break;
case 'p':
s++;
p_nbufs = getnum(&s, 'b');
break;
default:
f_nbufs = p_nbufs = getnum(&s, 'b');
break;
}
goto next;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
/*
* Handle special "more" compatibility form "-number"
* to set the scrolling window size.
*/
s--;
sc_window = getnum(&s, '-');
goto next;
}
#ifdef AMIGA
case '[': /* window specifier */
{
int i, rel;
for (i = 0; i < 4; i++)
{
rel = 1;
while ( *s == ' ' ) s++;
if ( *s == ',' )
{ s++; continue; }
if ( *s == '-' )
{ s++; rel = -1; }
if ( *s == ']' || *s == '\0' ) break;
Wind_Spec[i] = rel * getnum ( &s, s[-1] );
if ( *s == ',' ) s++;
}
if ( *s++ != ']' )
{
error ("Invalid window specification");
quit();
}
goto next;
}
#endif
}
for (o = option; o->oletter != '\0'; o++)
{
if ((o->otype & BOOL) && (o->oletter == c))
{
*(o->ovar) = ! o->odefault;
goto next;
} else if ((o->otype & TRIPLE) && (o->oletter == c))
{
*(o->ovar) = (o->odefault == 1) ? 0 : 1;
goto next;
} else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c))
{
*(o->ovar) = (o->odefault == 2) ? 0 : 2;
goto next;
} else if ((o->otype & NUMBER) && (o->oletter == c))
{
*(o->ovar) = getnum(&s, c);
goto next;
}
}
sprintf(message, "\"-%c\": invalid flag", c);
error(message);
quit();
}
/*
* Translate a string into a number.
* Like atoi(), but takes a pointer to a char *, and updates
* the char * to point after the translated number.
*/
#ifdef __STDC__
static int getnum (char **sp, int c)
#else
static int
getnum(sp, c)
char **sp;
int c;
#endif
{
register char *s;
register int n;
char message[80];
s = *sp;
if (*s < '0' || *s > '9')
{
if (c == '\0')
return (-1);
#ifdef AMIGA
sprintf(message,
"number is required in option after '%c'", c);
#else
sprintf(message, "number is required after -%c", c);
#endif
error(message);
quit();
}
n = 0;
while (*s >= '0' && *s <= '9')
n = 10 * n + *s++ - '0';
*sp = s;
return (n);
}