#include "config.h"
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <assert.h>
#include "proto.h"
#include "nano.h"
static int statblank = 0;
int do_first_line(void)
{
current = fileage;
placewewant = 0;
current_x = 0;
edit_update(current, CENTER);
return 1;
}
int do_last_line(void)
{
current = filebot;
placewewant = 0;
current_x = 0;
edit_update(current, CENTER);
return 1;
}
size_t xplustabs(void)
{
return strnlenpt(current->data, current_x);
}
size_t actual_x(const filestruct *fileptr, size_t xplus)
{
size_t i = 0;
size_t length = 0;
char *c;
assert(fileptr != NULL && fileptr->data != NULL);
for (c = fileptr->data; length < xplus && *c != '\0'; i++, c++) {
if (*c == '\t')
length += tabsize - length % tabsize;
else if (is_cntrl_char((int)*c))
length += 2;
else
length++;
}
assert(length == strnlenpt(fileptr->data, i));
assert(i <= strlen(fileptr->data));
if (length > xplus)
i--;
#ifdef DEBUG
fprintf(stderr, "actual_x for xplus=%d returns %d\n", xplus, i);
#endif
return i;
}
size_t strnlenpt(const char *buf, size_t size)
{
size_t length = 0;
if (buf != NULL)
for (; *buf != '\0' && size != 0; size--, buf++) {
if (*buf == '\t')
length += tabsize - (length % tabsize);
else if (is_cntrl_char((int)*buf))
length += 2;
else
length++;
}
return length;
}
size_t strlenpt(const char *buf)
{
return strnlenpt(buf, -1);
}
void blank_bottombars(void)
{
if (!no_help()) {
mvwaddstr(bottomwin, 1, 0, hblank);
mvwaddstr(bottomwin, 2, 0, hblank);
}
}
void blank_bottomwin(void)
{
if (ISSET(NO_HELP))
return;
mvwaddstr(bottomwin, 1, 0, hblank);
mvwaddstr(bottomwin, 2, 0, hblank);
}
void blank_edit(void)
{
int i;
for (i = 0; i <= editwinrows - 1; i++)
mvwaddstr(edit, i, 0, hblank);
}
void blank_statusbar(void)
{
mvwaddstr(bottomwin, 0, 0, hblank);
}
void blank_statusbar_refresh(void)
{
blank_statusbar();
wrefresh(bottomwin);
}
void check_statblank(void)
{
if (statblank > 1)
statblank--;
else if (statblank == 1 && !ISSET(CONSTUPDATE)) {
statblank--;
blank_statusbar_refresh();
}
}
void nanoget_repaint(const char *buf, const char *inputbuf, int x)
{
int len = strlen(buf) + 2;
int wid = COLS - len;
assert(wid >= 2);
assert(0 <= x && x <= strlen(inputbuf));
wattron(bottomwin, A_REVERSE);
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddch(bottomwin, ':');
waddch(bottomwin, x < wid ? ' ' : '$');
waddnstr(bottomwin, &inputbuf[wid * (x / wid)], wid);
wmove(bottomwin, 0, (x % wid) + len);
wattroff(bottomwin, A_REVERSE);
}
int nanogetstr(int allowtabs, const char *buf, const char *def,
#ifndef NANO_SMALL
historyheadtype *history_list,
#endif
const shortcut *s
#ifndef DISABLE_TABCOMP
, int *list
#endif
)
{
int kbinput;
static int x = -1;
int xend;
int tabbed = 0;
const shortcut *t;
#ifndef NANO_SMALL
char *history = NULL;
char *currentbuf = NULL;
char *complete = NULL;
int last_kbinput = 0;
int use_cb = 0;
#endif
xend = strlen(def);
if (x == -1 || x > xend || resetstatuspos)
x = xend;
answer = charealloc(answer, xend + 1);
if (xend > 0)
strcpy(answer, def);
else
answer[0] = '\0';
#if !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
currshortcut = s;
#endif
nanoget_repaint(buf, answer, x);
wrefresh(edit);
while ((kbinput = wgetch(bottomwin)) != 13) {
for (t = s; t != NULL; t = t->next) {
#ifdef DEBUG
fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput, kbinput);
#endif
if (kbinput == t->val && kbinput < 32) {
#ifndef DISABLE_HELP
if (kbinput == NANO_HELP_KEY || kbinput == NANO_HELP_FKEY) {
do_help();
break;
}
#endif
return t->val;
}
}
assert(0 <= x && x <= xend && xend == strlen(answer));
if (kbinput != '\t')
tabbed = 0;
switch (kbinput) {
case 343:
ungetch(13);
break;
#ifdef PDCURSES
case 541:
case 542:
case 543:
case 544:
case 545:
break;
#endif
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
case KEY_MOUSE:
do_mouse();
break;
#endif
case NANO_HOME_KEY:
case KEY_HOME:
x = 0;
break;
case NANO_END_KEY:
case KEY_END:
x = xend;
break;
case KEY_RIGHT:
case NANO_FORWARD_KEY:
if (x < xend)
x++;
break;
case NANO_CONTROL_D:
if (x < xend) {
memmove(answer + x, answer + x + 1, xend - x);
xend--;
}
break;
case NANO_CONTROL_K:
case NANO_CONTROL_U:
null_at(&answer, 0);
xend = 0;
x = 0;
break;
case KEY_BACKSPACE:
case 127:
case NANO_CONTROL_H:
if (x > 0) {
memmove(answer + x - 1, answer + x, xend - x + 1);
x--;
xend--;
}
break;
case NANO_CONTROL_I:
#ifndef NANO_SMALL
if (history_list != NULL) {
if (!complete || last_kbinput != NANO_CONTROL_I) {
history_list->current = (historytype *)history_list;
history_list->len = strlen(answer);
}
if (history_list->len > 0) {
complete = get_history_completion(history_list, answer);
xend = strlen(complete);
x = xend;
answer = mallocstrcpy(answer, complete);
}
}
#ifndef DISABLE_TABCOMP
else
#endif
#endif
#ifndef DISABLE_TABCOMP
if (allowtabs) {
int shift = 0;
answer = input_tab(answer, x, &tabbed, &shift, list);
xend = strlen(answer);
x += shift;
if (x > xend)
x = xend;
}
#endif
break;
case KEY_LEFT:
case NANO_BACK_KEY:
if (x > 0)
x--;
break;
case KEY_UP:
case NANO_UP_KEY:
#ifndef NANO_SMALL
do_upkey:
if (history_list != NULL) {
if (currentbuf == NULL || (use_cb == 1 && strcmp(currentbuf, answer))) {
currentbuf = mallocstrcpy(currentbuf, answer);
use_cb = 0;
}
if (currentbuf != NULL && use_cb == 2 && strcmp(currentbuf, answer)) {
answer = mallocstrcpy(answer, currentbuf);
free(currentbuf);
currentbuf = NULL;
xend = strlen(answer);
use_cb = 0;
} else if ((history = get_history_older(history_list)) != NULL) {
answer = mallocstrcpy(answer, history);
xend = strlen(history);
} else {
answer = mallocstrcpy(answer, "");
xend = 0;
}
x = xend;
}
#endif
break;
case KEY_DOWN:
case NANO_DOWN_KEY:
#ifndef NANO_SMALL
do_downkey:
if (history_list != NULL) {
if ((history = get_history_newer(history_list)) != NULL) {
answer = mallocstrcpy(answer, history);
xend = strlen(history);
} else if (currentbuf != NULL && use_cb != 2) {
answer = mallocstrcpy(answer, currentbuf);
free(currentbuf);
currentbuf = NULL;
xend = strlen(answer);
use_cb = 1;
} else if (use_cb != 2) {
if (answer[0] != '\0') {
currentbuf = mallocstrcpy(currentbuf, answer);
answer = mallocstrcpy(answer, "");
}
xend = 0;
use_cb = 2;
}
x = xend;
}
#endif
break;
case KEY_DC:
goto do_deletekey;
case 27:
switch (kbinput = wgetch(edit)) {
case 'O':
switch (kbinput = wgetch(edit)) {
case 'F':
x = xend;
break;
case 'H':
x = 0;
break;
}
break;
case '[':
switch (kbinput = wgetch(edit)) {
case 'A':
#ifndef NANO_SMALL
goto do_upkey;
#else
break;
#endif
case 'B':
#ifndef NANO_SMALL
goto do_downkey;
#else
break;
#endif
case 'C':
if (x < xend)
x++;
break;
case 'D':
if (x > 0)
x--;
break;
case 'F':
x = xend;
break;
case 'H':
x = 0;
break;
case '1':
case '7':
x = 0;
goto skip_tilde;
case '3':
do_deletekey:
if (x < xend) {
memmove(answer + x, answer + x + 1, xend - x);
xend--;
}
goto skip_tilde;
case '4':
case '8':
x = xend;
skip_tilde:
nodelay(edit, TRUE);
kbinput = wgetch(edit);
if (kbinput == '~' || kbinput == ERR)
kbinput = -1;
nodelay(edit, FALSE);
break;
}
break;
default:
for (t = s; t != NULL; t = t->next) {
#ifdef DEBUG
fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
kbinput);
#endif
if (kbinput == t->val || kbinput == t->val - 32)
return t->val;
}
}
break;
default:
if (kbinput < 32)
break;
answer = charealloc(answer, xend + 2);
memmove(answer + x + 1, answer + x, xend - x + 1);
xend++;
answer[x] = kbinput;
x++;
#ifdef DEBUG
fprintf(stderr, "input \'%c\' (%d)\n", kbinput, kbinput);
#endif
}
#ifndef NANO_SMALL
last_kbinput = kbinput;
#endif
nanoget_repaint(buf, answer, x);
wrefresh(bottomwin);
}
x = -1;
if (answer[0] == '\0')
return -2;
else
return 0;
}
void set_modified(void)
{
if (!ISSET(MODIFIED)) {
SET(MODIFIED);
titlebar(NULL);
wrefresh(topwin);
}
}
void titlebar(const char *path)
{
int namelen, space;
const char *what = path;
if (path == NULL)
what = filename;
wattron(topwin, A_REVERSE);
mvwaddstr(topwin, 0, 0, hblank);
mvwaddnstr(topwin, 0, 2, VERMSG, COLS - 3);
space = COLS - sizeof(VERMSG) - 23;
namelen = strlen(what);
if (space > 0) {
if (what[0] == '\0')
mvwaddnstr(topwin, 0, COLS / 2 - 6, _("New Buffer"),
COLS / 2 + COLS % 2 - 6);
else if (namelen > space) {
if (path == NULL)
waddstr(topwin, _(" File: ..."));
else
waddstr(topwin, _(" DIR: ..."));
waddstr(topwin, &what[namelen - space]);
} else {
if (path == NULL)
mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
_("File: "));
else
mvwaddstr(topwin, 0, COLS / 2 - (namelen / 2 + 1),
_(" DIR: "));
waddstr(topwin, what);
}
}
if (ISSET(MODIFIED))
mvwaddnstr(topwin, 0, COLS - 11, _(" Modified "), 11);
else if (ISSET(VIEW_MODE))
mvwaddnstr(topwin, 0, COLS - 11, _(" View "), 11);
wattroff(topwin, A_REVERSE);
wrefresh(topwin);
reset_cursor();
}
void bottombars(const shortcut *s)
{
int i, j, numcols;
char keystr[9];
int slen;
if (ISSET(NO_HELP))
return;
if (s == main_list) {
slen = MAIN_VISIBLE;
assert(MAIN_VISIBLE <= length_of_list(s));
} else
slen = length_of_list(s);
numcols = (slen + (slen % 2)) / 2;
blank_bottomwin();
for (i = 0; i < numcols; i++) {
for (j = 0; j <= 1; j++) {
wmove(bottomwin, 1 + j, i * (COLS / numcols));
if (s->val == NANO_CONTROL_SPACE)
strcpy(keystr, "^ ");
#ifndef NANO_SMALL
else if (s->val == KEY_UP)
strncpy(keystr, _("Up"), 8);
#endif
else if (s->val > 0) {
if (s->val < 64)
sprintf(keystr, "^%c", s->val + 64);
else
sprintf(keystr, "M-%c", s->val - 32);
} else if (s->altval > 0)
sprintf(keystr, "M-%c", s->altval);
onekey(keystr, s->desc, COLS / numcols);
s = s->next;
if (s == NULL)
goto break_completely_out;
}
}
break_completely_out:
wrefresh(bottomwin);
}
void onekey(const char *keystroke, const char *desc, int len)
{
wattron(bottomwin, A_REVERSE);
waddnstr(bottomwin, keystroke, len);
wattroff(bottomwin, A_REVERSE);
len -= strlen(keystroke);
if (len > 0) {
waddch(bottomwin, ' ');
len--;
waddnstr(bottomwin, desc, len);
len -= strlen(desc);
for (; len > 0; len--)
waddch(bottomwin, ' ');
}
}
#ifndef NDEBUG
int check_linenumbers(const filestruct *fileptr)
{
int check_line = 0;
const filestruct *filetmp;
for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
check_line++;
return check_line;
}
#endif
int get_page_start(int column)
{
assert(COLS > 9);
return column < COLS - 1 ? 0 : column - 7 - (column - 8) % (COLS - 9);
}
void reset_cursor(void)
{
const filestruct *ptr = edittop;
size_t x;
if (edittop == NULL)
return;
current_y = 0;
while (ptr != current && ptr != editbot && ptr->next != NULL) {
ptr = ptr->next;
current_y++;
}
x = xplustabs();
wmove(edit, current_y, x - get_page_start(x));
}
void edit_add(const filestruct *fileptr, int yval, int start
#ifndef NANO_SMALL
, int virt_mark_beginx, int virt_cur_x
#endif
)
{
#ifdef DEBUG
fprintf(stderr, "Painting line %d, current is %d\n", fileptr->lineno,
current->lineno);
#endif
mvwaddnstr(edit, yval, 0, &fileptr->data[start], COLS);
#ifdef ENABLE_COLOR
if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
const colortype *tmpcolor = colorstrings;
for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
int x_start;
int paintlen;
regmatch_t startmatch;
regmatch_t endmatch;
if (tmpcolor->bright)
wattron(edit, A_BOLD);
wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
if (tmpcolor->end == NULL) {
size_t k = 0;
while (k < start + COLS) {
if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
&startmatch, k == 0 ? 0 : REG_NOTBOL))
break;
startmatch.rm_so += k;
startmatch.rm_eo += k;
if (startmatch.rm_so == startmatch.rm_eo) {
startmatch.rm_eo++;
statusbar(_("Refusing 0 length regex match"));
} else if (startmatch.rm_so < start + COLS &&
startmatch.rm_eo > start) {
x_start = startmatch.rm_so - start;
if (x_start < 0)
x_start = 0;
paintlen = startmatch.rm_eo - start - x_start;
if (paintlen > COLS - x_start)
paintlen = COLS - x_start;
assert(0 <= x_start && 0 < paintlen &&
x_start + paintlen <= COLS);
mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start, paintlen);
}
k = startmatch.rm_eo;
}
} else {
const filestruct *start_line = fileptr->prev;
regoff_t start_col;
const filestruct *end_line;
int searched_later_lines = 0;
while (start_line != NULL &&
regexec(&tmpcolor->start, start_line->data, 1,
&startmatch, 0)) {
if (!regexec(tmpcolor->end, start_line->data, 1,
&endmatch, 0))
goto step_two;
start_line = start_line->prev;
}
if (start_line == NULL)
goto step_two;
start_col = 0;
while (1) {
start_col += startmatch.rm_so;
startmatch.rm_eo -= startmatch.rm_so;
if (regexec(tmpcolor->end,
start_line->data + start_col + startmatch.rm_eo,
1, &endmatch,
start_col + startmatch.rm_eo == 0 ? 0 : REG_NOTBOL))
break;
start_col++;
if (regexec(&tmpcolor->start,
start_line->data + start_col, 1, &startmatch,
REG_NOTBOL))
goto step_two;
}
end_line = fileptr;
while (end_line != NULL &&
regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
end_line = end_line->next;
if (end_line == NULL || end_line->lineno < fileptr->lineno ||
(end_line == fileptr && endmatch.rm_eo <= start))
goto step_two;
paintlen = end_line != fileptr
? COLS : endmatch.rm_eo - start;
if (paintlen > COLS)
paintlen = COLS;
assert(0 < paintlen && paintlen <= COLS);
mvwaddnstr(edit, yval, 0, fileptr->data + start, paintlen);
if (paintlen == COLS)
goto skip_step_two;
step_two:
start_col = 0;
while (start_col < start + COLS) {
if (regexec(&tmpcolor->start, fileptr->data + start_col, 1,
&startmatch, start_col == 0 ? 0 : REG_NOTBOL)
|| start_col + startmatch.rm_so >= start + COLS)
break;
startmatch.rm_so += start_col;
startmatch.rm_eo += start_col;
x_start = startmatch.rm_so - start;
if (x_start < 0) {
x_start = 0;
startmatch.rm_so = start;
}
if (!regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
1, &endmatch,
startmatch.rm_eo == 0 ? 0 : REG_NOTBOL)) {
endmatch.rm_so += startmatch.rm_eo;
endmatch.rm_eo += startmatch.rm_eo;
if (endmatch.rm_eo > start &&
endmatch.rm_eo > startmatch.rm_so) {
paintlen = endmatch.rm_eo - start - x_start;
if (x_start + paintlen > COLS)
paintlen = COLS - x_start;
assert(0 <= x_start && 0 < paintlen &&
x_start + paintlen <= COLS);
mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start, paintlen);
}
} else if (!searched_later_lines) {
searched_later_lines = 1;
end_line = fileptr->next;
while (end_line != NULL && regexec(tmpcolor->end,
end_line->data, 1, &endmatch, 0))
end_line = end_line->next;
if (end_line != NULL) {
assert(0 <= x_start && x_start < COLS);
mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start,
COLS - x_start);
break;
}
}
start_col = startmatch.rm_so + 1;
}
}
skip_step_two:
wattroff(edit, A_BOLD);
wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
}
}
#endif
#ifndef NANO_SMALL
if (ISSET(MARK_ISSET)
&& (fileptr->lineno <= mark_beginbuf->lineno
|| fileptr->lineno <= current->lineno)
&& (fileptr->lineno >= mark_beginbuf->lineno
|| fileptr->lineno >= current->lineno)) {
int x_start;
int paintlen;
if (mark_beginbuf == fileptr && current == fileptr) {
x_start = virt_mark_beginx < virt_cur_x ? virt_mark_beginx
: virt_cur_x;
paintlen = abs(virt_mark_beginx - virt_cur_x);
} else {
if (mark_beginbuf->lineno < fileptr->lineno ||
current->lineno < fileptr->lineno)
x_start = 0;
else
x_start = mark_beginbuf == fileptr ? virt_mark_beginx
: virt_cur_x;
if (mark_beginbuf->lineno > fileptr->lineno ||
current->lineno > fileptr->lineno)
paintlen = start + COLS;
else
paintlen = mark_beginbuf == fileptr ? virt_mark_beginx
: virt_cur_x;
}
x_start -= start;
if (x_start < 0) {
paintlen += x_start;
x_start = 0;
}
if (x_start + paintlen > COLS)
paintlen = COLS - x_start;
if (paintlen > 0) {
wattron(edit, A_REVERSE);
assert(x_start >= 0 && paintlen > 0 && x_start + paintlen <= COLS);
mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start, paintlen);
wattroff(edit, A_REVERSE);
}
}
#endif
}
void update_line(filestruct *fileptr, int index)
{
int line;
#ifndef NANO_SMALL
int virt_cur_x;
int virt_mark_beginx;
#endif
char *original;
char *converted;
size_t pos;
size_t page_start;
if (fileptr == NULL)
return;
line = fileptr->lineno - edittop->lineno;
assert(line < 0 || line == check_linenumbers(fileptr));
if (line < 0 || line >= editwinrows)
return;
mvwaddstr(edit, line, 0, hblank);
original = fileptr->data;
converted = charalloc(strlenpt(original) + 1);
index = fileptr == current && index > 0 ? strnlenpt(original, index) : 0;
#ifndef NANO_SMALL
virt_cur_x = fileptr == current ? strnlenpt(original, current_x) : current_x;
virt_mark_beginx = fileptr == mark_beginbuf ? strnlenpt(original, mark_beginx) : mark_beginx;
#endif
pos = 0;
for (; *original != '\0'; original++) {
if (*original == '\t')
do {
converted[pos++] = ' ';
} while (pos % tabsize);
else if (is_cntrl_char(*original)) {
converted[pos++] = '^';
if (*original == 127)
converted[pos++] = '?';
else if (*original == '\n')
converted[pos++] = '@';
else
converted[pos++] = *original + 64;
} else
converted[pos++] = *original;
}
converted[pos] = '\0';
original = fileptr->data;
fileptr->data = converted;
page_start = get_page_start(index);
edit_add(fileptr, line, page_start
#ifndef NANO_SMALL
, virt_mark_beginx, virt_cur_x
#endif
);
free(converted);
fileptr->data = original;
if (page_start > 0)
mvwaddch(edit, line, 0, '$');
if (pos > page_start + COLS)
mvwaddch(edit, line, COLS - 1, '$');
}
void update_cursor(void)
{
int i = 0;
#ifdef DEBUG
fprintf(stderr, "Moved to (%d, %d) in edit buffer\n", current_y,
current_x);
#endif
current = edittop;
while (i < current_y && current->next != NULL) {
current = current->next;
i++;
}
#ifdef DEBUG
fprintf(stderr, "current->data = \"%s\"\n", current->data);
#endif
}
void center_cursor(void)
{
current_y = editwinrows / 2;
wmove(edit, current_y, current_x);
}
void edit_refresh(void)
{
if (current == NULL)
return;
if (edittop == NULL)
edittop = current;
if (current->lineno < edittop->lineno ||
current->lineno >= edittop->lineno + editwinrows)
edit_update(current, CENTER);
else {
int nlines = 0;
leaveok(edit, TRUE);
editbot = edittop;
while (nlines < editwinrows) {
update_line(editbot, current_x);
nlines++;
if (editbot->next == NULL)
break;
editbot = editbot->next;
}
while (nlines < editwinrows) {
mvwaddstr(edit, nlines, 0, hblank);
nlines++;
}
wrefresh(edit);
leaveok(edit, FALSE);
}
}
void edit_refresh_clearok(void)
{
clearok(edit, TRUE);
edit_refresh();
clearok(edit, FALSE);
}
void edit_update(filestruct *fileptr, topmidbotnone location)
{
if (fileptr == NULL)
return;
if (location != TOP) {
int goal = location == NONE ? current_y - 1 : editwinrows / 2;
for (; goal >= 0 && fileptr->prev != NULL; goal--)
fileptr = fileptr->prev;
}
edittop = fileptr;
fix_editbot();
edit_refresh();
}
int statusq(int tabs, const shortcut *s, const char *def,
#ifndef NANO_SMALL
historyheadtype *which_history,
#endif
const char *msg, ...)
{
va_list ap;
char *foo = charalloc(COLS - 3);
int ret;
#ifndef DISABLE_TABCOMP
int list = 0;
#endif
bottombars(s);
va_start(ap, msg);
vsnprintf(foo, COLS - 4, msg, ap);
va_end(ap);
foo[COLS - 4] = '\0';
ret = nanogetstr(tabs, foo, def,
#ifndef NANO_SMALL
which_history,
#endif
s
#ifndef DISABLE_TABCOMP
, &list
#endif
);
free(foo);
resetstatuspos = 0;
switch (ret) {
case NANO_FIRSTLINE_KEY:
do_first_line();
resetstatuspos = 1;
break;
case NANO_LASTLINE_KEY:
do_last_line();
resetstatuspos = 1;
break;
case NANO_CANCEL_KEY:
ret = -1;
resetstatuspos = 1;
break;
}
blank_statusbar();
#ifdef DEBUG
fprintf(stderr, "I got \"%s\"\n", answer);
#endif
#ifndef DISABLE_TABCOMP
if (list)
edit_refresh();
#endif
return ret;
}
int do_yesno(int all, int leavecursor, const char *msg, ...)
{
va_list ap;
char *foo;
int ok = -2;
const char *yesstr;
const char *nostr;
const char *allstr;
yesstr = _("Yy");
nostr = _("Nn");
allstr = _("Aa");
if (!ISSET(NO_HELP)) {
char shortstr[3];
blank_bottombars();
sprintf(shortstr, " %c", yesstr[0]);
wmove(bottomwin, 1, 0);
onekey(shortstr, _("Yes"), 16);
if (all) {
wmove(bottomwin, 1, 16);
shortstr[1] = allstr[0];
onekey(shortstr, _("All"), 16);
}
wmove(bottomwin, 2, 0);
shortstr[1] = nostr[0];
onekey(shortstr, _("No"), 16);
wmove(bottomwin, 2, 16);
onekey("^C", _("Cancel"), 16);
}
foo = charalloc(COLS);
va_start(ap, msg);
vsnprintf(foo, COLS, msg, ap);
va_end(ap);
foo[COLS - 1] = '\0';
wattron(bottomwin, A_REVERSE);
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, foo);
free(foo);
wattroff(bottomwin, A_REVERSE);
wrefresh(bottomwin);
do {
int kbinput = wgetch(edit);
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
MEVENT mevent;
#endif
if (kbinput == NANO_CONTROL_C)
ok = -1;
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
else if (kbinput == KEY_MOUSE && getmouse(&mevent) != ERR &&
wenclose(bottomwin, mevent.y, mevent.x) &&
!ISSET(NO_HELP) && mevent.x < 32 &&
mevent.y >= editwinrows + 3) {
int x = mevent.x /= 16;
int y = mevent.y - editwinrows - 3;
assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
ok = -2 * x * y + x - y + 1;
if (ok == 2 && !all)
ok = -2;
}
#endif
else if (strchr(yesstr, kbinput) != NULL)
ok = 1;
else if (strchr(nostr, kbinput) != NULL)
ok = 0;
else if (all && strchr(allstr, kbinput) != NULL)
ok = 2;
} while (ok == -2);
blank_statusbar_refresh();
return ok;
}
int total_refresh(void)
{
clearok(edit, TRUE);
clearok(topwin, TRUE);
clearok(bottomwin, TRUE);
wnoutrefresh(edit);
wnoutrefresh(topwin);
wnoutrefresh(bottomwin);
doupdate();
clearok(edit, FALSE);
clearok(topwin, FALSE);
clearok(bottomwin, FALSE);
edit_refresh();
titlebar(NULL);
return 1;
}
void display_main_list(void)
{
bottombars(main_list);
}
void statusbar(const char *msg, ...)
{
va_list ap;
char *foo;
int start_x = 0;
size_t foo_len;
va_start(ap, msg);
if (curses_ended) {
vfprintf(stderr, msg, ap);
va_end(ap);
return;
}
assert(COLS >= 4);
foo = charalloc(COLS - 3);
vsnprintf(foo, COLS - 3, msg, ap);
va_end(ap);
foo[COLS - 4] = '\0';
foo_len = strlen(foo);
start_x = (COLS - foo_len - 4) / 2;
blank_statusbar();
wmove(bottomwin, 0, start_x);
wattron(bottomwin, A_REVERSE);
waddstr(bottomwin, "[ ");
waddstr(bottomwin, foo);
free(foo);
waddstr(bottomwin, " ]");
wattroff(bottomwin, A_REVERSE);
wrefresh(bottomwin);
SET(DISABLE_CURPOS);
statblank = 26;
}
int do_cursorpos(int constant)
{
const filestruct *fileptr;
unsigned long i = 0;
static unsigned long old_i = 0;
static long old_totsize = -1;
assert(current != NULL && fileage != NULL && totlines != 0);
if (old_totsize == -1)
old_totsize = totsize;
for (fileptr = fileage; fileptr != current; fileptr = fileptr->next) {
assert(fileptr != NULL);
i += strlen(fileptr->data) + 1;
}
i += current_x;
if (constant && ISSET(DISABLE_CURPOS)) {
UNSET(DISABLE_CURPOS);
old_i = i;
old_totsize = totsize;
return 0;
}
if (!constant || old_i != i || old_totsize != totsize) {
unsigned long xpt = xplustabs() + 1;
unsigned long cur_len = strlenpt(current->data) + 1;
int linepct = 100 * current->lineno / totlines;
int colpct = 100 * xpt / cur_len;
int bytepct = totsize == 0 ? 0 : 100 * i / totsize;
statusbar(
_("line %ld/%ld (%d%%), col %lu/%lu (%d%%), char %lu/%ld (%d%%)"),
current->lineno, totlines, linepct,
xpt, cur_len, colpct,
i, totsize, bytepct);
UNSET(DISABLE_CURPOS);
}
old_i = i;
old_totsize = totsize;
reset_cursor();
return 0;
}
int do_cursorpos_void(void)
{
return do_cursorpos(0);
}
int line_len(const char *ptr)
{
int j = 0;
while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) {
ptr++;
j++;
}
if (j == COLS - 5) {
if (*ptr == ' ' && *(ptr + 1) == ' ')
j++;
while (*ptr != ' ' && j > 0) {
ptr--;
j--;
}
if (j == 0)
j = COLS - 5;
}
assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n'));
return j;
}
int do_help(void)
{
#ifndef DISABLE_HELP
int i, page = 0, kbinput = 0, no_more = 0, kp;
int no_help_flag = 0;
const shortcut *oldshortcut;
blank_edit();
curs_set(0);
wattroff(bottomwin, A_REVERSE);
blank_statusbar();
help_init();
assert(help_text != NULL);
oldshortcut = currshortcut;
currshortcut = help_list;
kp = keypad_on(edit, 1);
if (ISSET(NO_HELP)) {
no_help_flag = 1;
UNSET(NO_HELP);
window_init();
bottombars(help_list);
} else
bottombars(help_list);
do {
const char *ptr = help_text;
switch (kbinput) {
#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
case KEY_MOUSE:
do_mouse();
break;
#endif
case 27:
kbinput = wgetch(edit);
switch(kbinput) {
case '[':
kbinput = wgetch(edit);
switch(kbinput) {
case '5':
wgetch(edit);
goto do_pageupkey;
case 'V':
case 'I':
goto do_pageupkey;
case '6':
wgetch(edit);
goto do_pagedownkey;
case 'U':
case 'G':
goto do_pagedownkey;
}
break;
}
break;
case NANO_NEXTPAGE_KEY:
case NANO_NEXTPAGE_FKEY:
case KEY_NPAGE:
do_pagedownkey:
if (!no_more) {
blank_edit();
page++;
}
break;
case NANO_PREVPAGE_KEY:
case NANO_PREVPAGE_FKEY:
case KEY_PPAGE:
do_pageupkey:
if (page > 0) {
no_more = 0;
blank_edit();
page--;
}
break;
}
for (i = 1; i < page * (editwinrows - 1); i++) {
ptr += line_len(ptr);
if (*ptr == '\n')
ptr++;
}
for (i = 0; i < editwinrows && *ptr != '\0'; i++) {
int j = line_len(ptr);
mvwaddnstr(edit, i, 0, ptr, j);
ptr += j;
if (*ptr == '\n')
ptr++;
}
if (*ptr == '\0') {
no_more = 1;
continue;
}
} while ((kbinput = wgetch(edit)) != NANO_EXIT_KEY &&
kbinput != NANO_EXIT_FKEY);
currshortcut = oldshortcut;
if (no_help_flag) {
blank_bottombars();
wrefresh(bottomwin);
SET(NO_HELP);
window_init();
} else
bottombars(currshortcut);
curs_set(1);
edit_refresh();
kp = keypad_on(edit, kp);
free(help_text);
help_text = NULL;
#elif defined(DISABLE_HELP)
nano_disabled_msg();
#endif
return 1;
}
int keypad_on(WINDOW *win, int newval)
{
#ifdef HAVE_USEKEYPAD
int old = win->_use_keypad;
keypad(win, newval);
return old;
#else
keypad(win, newval);
return 1;
#endif
}
void do_replace_highlight(int highlight_flag, const char *word)
{
char *highlight_word = NULL;
int x, y, word_len;
highlight_word =
mallocstrcpy(highlight_word, ¤t->data[current_x]);
#ifdef HAVE_REGEX_H
if (ISSET(USE_REGEXP))
word_len = regmatches[0].rm_eo - regmatches[0].rm_so;
else
#endif
word_len = strlen(word);
highlight_word[word_len] = '\0';
x = xplustabs();
y = get_page_start(x) + COLS;
if ((COLS - (y - x) + word_len) > COLS) {
highlight_word[y - x - 1] = '$';
highlight_word[y - x] = '\0';
}
reset_cursor();
if (highlight_flag)
wattron(edit, A_REVERSE);
waddstr(edit, highlight_word);
if (highlight_flag)
wattroff(edit, A_REVERSE);
free(highlight_word);
}
void fix_editbot(void)
{
int i;
editbot = edittop;
for (i = 0; i < editwinrows && editbot->next != NULL; i++)
editbot = editbot->next;
}
#ifdef DEBUG
void dump_buffer(const filestruct *inptr) {
if (inptr == fileage)
fprintf(stderr, "Dumping file buffer to stderr...\n");
else if (inptr == cutbuffer)
fprintf(stderr, "Dumping cutbuffer to stderr...\n");
else
fprintf(stderr, "Dumping a buffer to stderr...\n");
while (inptr != NULL) {
fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data);
inptr = inptr->next;
}
}
#endif
#ifdef DEBUG
void dump_buffer_reverse(void) {
const filestruct *fileptr = filebot;
while (fileptr != NULL) {
fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data);
fileptr = fileptr->prev;
}
}
#endif
#ifdef NANO_EXTRA
#define CREDIT_LEN 53
#define XLCREDIT_LEN 8
void do_credits(void)
{
int i, j = 0, k, place = 0, start_x;
const char *what;
const char *xlcredits[XLCREDIT_LEN];
const char *credits[CREDIT_LEN] = {
"0",
"1",
VERSION,
"",
"2",
"Chris Allegretta",
"Jordi Mallach",
"Adam Rogoyski",
"Rob Siemborski",
"Rocco Corsi",
"David Lawrence Ramsey",
"David Benbennick",
"Ken Tyler",
"Sven Guckes",
"Florian König",
"Pauli Virtanen",
"Daniele Medri",
"Clement Laforet",
"Tedi Heriyanto",
"Bill Soudan",
"Christian Weisgerber",
"Erik Andersen",
"Big Gaute",
"Joshua Jensen",
"Ryan Krebs",
"Albert Chin",
"",
"3",
"Plattsburgh State University",
"Benet Laboratories",
"Amy Allegretta",
"Linda Young",
"Jeremy Robichaud",
"Richard Kolb II",
"4",
"Linus Torvalds",
"5",
"Thomas Dickey",
"Pavel Curtis",
"Zeyd Ben-Halim",
"Eric S. Raymond",
"6",
"7",
"", "", "", "",
"(c) 1999-2003 Chris Allegretta",
"", "", "", "",
"http://www.nano-editor.org/"
};
xlcredits[0] = _("The nano text editor");
xlcredits[1] = _("version ");
xlcredits[2] = _("Brought to you by:");
xlcredits[3] = _("Special thanks to:");
xlcredits[4] = _("The Free Software Foundation");
xlcredits[5] = _("For ncurses:");
xlcredits[6] = _("and anyone else we forgot...");
xlcredits[7] = _("Thank you for using nano!\n");
curs_set(0);
nodelay(edit, TRUE);
blank_bottombars();
mvwaddstr(topwin, 0, 0, hblank);
blank_edit();
wrefresh(edit);
wrefresh(bottomwin);
wrefresh(topwin);
while (wgetch(edit) == ERR) {
for (k = 0; k <= 1; k++) {
blank_edit();
for (i = editwinrows / 2 - 1; i >= (editwinrows / 2 - 1 - j);
i--) {
mvwaddstr(edit, i * 2 - k, 0, hblank);
if (place - (editwinrows / 2 - 1 - i) < CREDIT_LEN) {
what = credits[place - (editwinrows / 2 - 1 - i)];
if (strlen(what) == 1)
what = xlcredits[atoi(what)];
} else
what = "";
start_x = COLS / 2 - strlen(what) / 2 - 1;
mvwaddstr(edit, i * 2 - k, start_x, what);
}
usleep(700000);
wrefresh(edit);
}
if (j < editwinrows / 2 - 1)
j++;
place++;
if (place >= CREDIT_LEN + editwinrows / 2)
break;
}
nodelay(edit, FALSE);
curs_set(1);
display_main_list();
total_refresh();
}
#endif