#include "less.h"
#include "option.h"
extern int bufspace;
extern int pr_type;
extern int plusoption;
extern int swindow;
extern int sc_width;
extern int sc_height;
extern int secure;
extern int dohelp;
extern int any_display;
extern char openquote;
extern char closequote;
extern char *prproto[];
extern char *eqproto;
extern char *hproto;
extern char *wproto;
extern IFILE curr_ifile;
extern char version[];
extern int jump_sline;
extern int jump_sline_fraction;
extern int less_is_more;
extern char *namelogfile;
extern int force_logfile;
extern int logfile;
char *tagoption = NULL;
extern char *tags;
int shift_count;
static int shift_count_fraction = -1;
void
opt_o(int type, char *s)
{
PARG parg;
if (secure) {
error("log file support is not available", NULL);
return;
}
switch (type) {
case INIT:
namelogfile = estrdup(s);
break;
case TOGGLE:
if (ch_getflags() & CH_CANSEEK) {
error("Input is not a pipe", NULL);
return;
}
if (logfile >= 0) {
error("Log file is already in use", NULL);
return;
}
s = skipsp(s);
free(namelogfile);
namelogfile = lglob(s);
use_logfile(namelogfile);
sync_logfile();
break;
case QUERY:
if (logfile < 0) {
error("No log file", NULL);
} else {
parg.p_string = namelogfile;
error("Log file \"%s\"", &parg);
}
break;
}
}
void
opt__O(int type, char *s)
{
force_logfile = TRUE;
opt_o(type, s);
}
void
opt_j(int type, char *s)
{
PARG parg;
char buf[16];
int len;
int err;
switch (type) {
case INIT:
case TOGGLE:
if (*s == '.') {
s++;
jump_sline_fraction = getfraction(&s, "j", &err);
if (err)
error("Invalid line fraction", NULL);
else
calc_jump_sline();
} else {
int sline = getnum(&s, "j", &err);
if (err) {
error("Invalid line number", NULL);
} else {
jump_sline = sline;
jump_sline_fraction = -1;
}
}
break;
case QUERY:
if (jump_sline_fraction < 0) {
parg.p_int = jump_sline;
error("Position target at screen line %d", &parg);
} else {
(void) snprintf(buf, sizeof (buf), ".%06d",
jump_sline_fraction);
len = strlen(buf);
while (len > 2 && buf[len-1] == '0')
len--;
buf[len] = '\0';
parg.p_string = buf;
error("Position target at screen position %s", &parg);
}
break;
}
}
void
calc_jump_sline(void)
{
if (jump_sline_fraction < 0)
return;
jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
}
void
opt_shift(int type, char *s)
{
PARG parg;
char buf[16];
int len;
int err;
switch (type) {
case INIT:
case TOGGLE:
if (*s == '.') {
s++;
shift_count_fraction = getfraction(&s, "#", &err);
if (err)
error("Invalid column fraction", NULL);
else
calc_shift_count();
} else {
int hs = getnum(&s, "#", &err);
if (err) {
error("Invalid column number", NULL);
} else {
shift_count = hs;
shift_count_fraction = -1;
}
}
break;
case QUERY:
if (shift_count_fraction < 0) {
parg.p_int = shift_count;
error("Horizontal shift %d columns", &parg);
} else {
(void) snprintf(buf, sizeof (buf), ".%06d",
shift_count_fraction);
len = strlen(buf);
while (len > 2 && buf[len-1] == '0')
len--;
buf[len] = '\0';
parg.p_string = buf;
error("Horizontal shift %s of screen width", &parg);
}
break;
}
}
void
calc_shift_count(void)
{
if (shift_count_fraction < 0)
return;
shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
}
void
opt_k(int type, char *s)
{
PARG parg;
switch (type) {
case INIT:
if (lesskey(s, 0)) {
parg.p_string = s;
error("Cannot use lesskey file \"%s\"", &parg);
}
break;
}
}
void
opt_t(int type, char *s)
{
IFILE save_ifile;
off_t pos;
switch (type) {
case INIT:
tagoption = s;
break;
case TOGGLE:
if (secure) {
error("tags support is not available", NULL);
break;
}
findtag(skipsp(s));
save_ifile = save_curr_ifile();
if (edit_tagfile() || (pos = tagsearch()) == -1) {
reedit_ifile(save_ifile);
break;
}
unsave_ifile(save_ifile);
jump_loc(pos, jump_sline);
break;
}
}
void
opt__T(int type, char *s)
{
PARG parg;
switch (type) {
case INIT:
tags = s;
break;
case TOGGLE:
s = skipsp(s);
tags = lglob(s);
break;
case QUERY:
parg.p_string = tags;
error("Tags file \"%s\"", &parg);
break;
}
}
void
opt_p(int type, char *s)
{
switch (type) {
case INIT:
plusoption = TRUE;
ungetsc(s);
if (!less_is_more)
ungetsc("/");
break;
}
}
void
opt__P(int type, char *s)
{
char **proto;
PARG parg;
switch (type) {
case INIT:
case TOGGLE:
switch (*s) {
case 's': proto = &prproto[PR_SHORT]; s++; break;
case 'm': proto = &prproto[PR_MEDIUM]; s++; break;
case 'M': proto = &prproto[PR_LONG]; s++; break;
case '=': proto = &eqproto; s++; break;
case 'h': proto = &hproto; s++; break;
case 'w': proto = &wproto; s++; break;
default: proto = &prproto[PR_SHORT]; break;
}
free(*proto);
*proto = estrdup(s);
break;
case QUERY:
parg.p_string = prproto[pr_type];
error("%s", &parg);
break;
}
}
void
opt_b(int type, char *s)
{
switch (type) {
case INIT:
case TOGGLE:
ch_setbufspace(bufspace);
break;
case QUERY:
break;
}
}
void
opt_i(int type, char *s)
{
switch (type) {
case TOGGLE:
chg_caseless();
break;
case QUERY:
case INIT:
break;
}
}
void
opt__V(int type, char *s)
{
switch (type) {
case TOGGLE:
case QUERY:
dispversion();
break;
case INIT:
any_display = 1;
putstr("less ");
putstr(version);
putstr(" (");
putstr("POSIX ");
putstr("regular expressions)\n");
putstr("Copyright (C) 1984-2012 Mark Nudelman\n");
putstr("Modified for use with illumos by Garrett D'Amore.\n");
putstr("Copyright 2014 Garrett D'Amore\n\n");
putstr("less comes with NO WARRANTY, ");
putstr("to the extent permitted by law.\n");
putstr("For information about the terms of redistribution,\n");
putstr("see the file named README in the less distribution.\n");
putstr("Homepage: https://www.greenwoodsoftware.com/less\n");
putstr("\n");
quit(QUIT_OK);
break;
}
}
void
opt_x(int type, char *s)
{
extern int tabstops[];
extern int ntabstops;
extern int tabdefault;
char tabs[60 + 11 * TABSTOP_MAX];
int i;
PARG p;
switch (type) {
case INIT:
case TOGGLE:
for (i = 1; i < TABSTOP_MAX; ) {
int n = 0;
s = skipsp(s);
while (*s >= '0' && *s <= '9')
n = (10 * n) + (*s++ - '0');
if (n > tabstops[i-1])
tabstops[i++] = n;
s = skipsp(s);
if (*s++ != ',')
break;
}
if (i < 2)
return;
ntabstops = i;
tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2];
break;
case QUERY:
(void) strlcpy(tabs, "Tab stops ", sizeof(tabs));
if (ntabstops > 2) {
for (i = 1; i < ntabstops; i++) {
if (i > 1)
strlcat(tabs, ",", sizeof(tabs));
(void) snprintf(tabs+strlen(tabs),
sizeof(tabs)-strlen(tabs),
"%d", tabstops[i]);
}
(void) snprintf(tabs+strlen(tabs),
sizeof(tabs)-strlen(tabs), " and then ");
}
(void) snprintf(tabs+strlen(tabs), sizeof(tabs)-strlen(tabs),
"every %d spaces", tabdefault);
p.p_string = tabs;
error("%s", &p);
break;
}
}
void
opt_quote(int type, char *s)
{
char buf[3];
PARG parg;
switch (type) {
case INIT:
case TOGGLE:
if (s[0] == '\0') {
openquote = closequote = '\0';
break;
}
if (s[1] != '\0' && s[2] != '\0') {
error("-\" must be followed by 1 or 2 chars",
NULL);
return;
}
openquote = s[0];
if (s[1] == '\0')
closequote = openquote;
else
closequote = s[1];
break;
case QUERY:
buf[0] = openquote;
buf[1] = closequote;
buf[2] = '\0';
parg.p_string = buf;
error("quotes %s", &parg);
break;
}
}
void
opt_query(int type, char *s)
{
switch (type) {
case QUERY:
case TOGGLE:
error("Use \"h\" for help", NULL);
break;
case INIT:
dohelp = 1;
}
}
int
get_swindow(void)
{
if (swindow > 0)
return (swindow);
return (sc_height + swindow);
}