home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
most423.zip
/
window.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-28
|
20KB
|
896 lines
#include <stdio.h>
#ifndef VMS
#include <sys/types.h>
#include <unistd.h>
#include <malloc.h>
#endif
#include <stdlib.h>
#include "externs.h"
#include "window.h"
#include "line.h"
#include "display.h"
#include "sysdep.h"
#include "file.h"
#include "buffer.h"
Window *WIN;
Window *TOP_WIN;
int COLUMN = 1;
int BEEP_MINI_B = 0;
int MINIBUFFER_SELECTED = 0;
int CURS_ROW;
int CURS_COL;
int RESTORE_WIDTH_TO = 0;
unsigned char *CURS_POS;
int read_string(char *str)
{
char ch;
int i;
i = strlen(str);
do
{
ch = getkey();
if (ch == 2) /* ^B erases line */
{
while(i)
{
ch = str[--i];
if ((ch < 32) || ((unsigned char) ch >= 127))
send_string_to_term("\b \b"); /* erase the ^ */
send_string_to_term("\b \b");
}
}
else if ((ch == '\b') || (ch == 127))
{
if (i > 0)
{
ch = str[--i];
if ((ch < 32) || ((unsigned char) ch >= 127))
send_string_to_term("\b \b"); /* erase the ^ */
send_string_to_term("\b \b");
}
else beep();
}
else if ((ch < 32) && (ch != 10) && (ch != 13))
{
if ((ch == '\007') || (ch == '\025')) /* ^G or ^U aborts */
{
beep();
return(-1); /* ^G quits */
}
if (ch == '\033') /* Allow KP ENTER as a terminator */
{
ch = getkey();
if (ch == 'O')
{
ch = getkey();
if (ch == 'M')
{
str[i] = '\0';
return(i);
}
else
{
send_string_to_term("^[O");
tt_putchar(ch);
str[i++] = 27;
str[i++] = 'O';
str[i++] = ch;
}
}
else
{
send_string_to_term("^[");
tt_putchar(ch);
str[i++] = 27;
str[i++] = ch;
}
}
else
{
str[i++] = ch;
tt_putchar('^');
tt_putchar(ch + '@');
}
}
else if (ch == '`') /* quoted insert */
{
ch = getkey();
str[i++] = ch;
if ((ch < ' ') || (ch == 127))
{
if (ch == 127) ch = '?'; else ch = ch + '@';
tt_putchar('^');
}
tt_putchar(ch);
}
else if ((ch != 10) && (ch != 13))
{
str[i++] = ch;
tt_putchar(ch);
}
fflush(stdout);
}
while ((ch != 10) && (ch != 13));
str[i] = '\0';
return(i);
}
void message(char *what, int how)
{
strcpy(MINI_BUF,what);
if (how) BEEP_MINI_B = 1; else BEEP_MINI_B = 0;
}
void select_minibuffer()
{
if (MINIBUFFER_SELECTED) return;
MINIBUFFER_SELECTED = 1;
/* set_scroll_region(1,SCREEN_HEIGHT); */
goto_rc(SCREEN_HEIGHT,1);
fflush(stdout);
}
void exit_minibuffer()
{
if (!MINIBUFFER_SELECTED) return;
MINIBUFFER_SELECTED = 0;
/* set_scroll_region(WIN->top,WIN->bot); */
fflush(stdout);
}
/* put out string, expanding control chars */
void nicely_puts(char *str)
{
unsigned char ch;
while ((ch = (unsigned char) *str++) != 0)
{
if ((ch < ' ') || (ch >= 127))
{
tt_putchar('^');
if (ch != 127) ch = ch + '@'; else ch = '?';
}
tt_putchar((char) ch);
}
}
void put_message()
{
select_minibuffer();
tt_erase_line();
if (BEEP_MINI_B) beep();
BEEP_MINI_B = 0;
if (*MINI_BUF != '\0') nicely_puts((char *) MINI_BUF);
exit_minibuffer();
}
/* puts 'what in the minibuffer to be edited. */
/* returns number of chars read */
int read_from_minibuffer(char *prompt, char *what)
{
int i;
char str[132];
char p[132];
if (*what)
{
sprintf(p, "%s (^B kills): ", prompt);
}
else sprintf(p, "%s: ", prompt);
select_minibuffer();
send_string_to_term(p);
if (*what != '\0')
nicely_puts(what);
strcpy(str,what);
i = read_string(str);
if (i > 0) strcpy(what,str);
tt_erase_line();
exit_minibuffer();
return(i);
}
void clear_minibuffer()
{
MINI_BUF[0] = '\0';
BEEP_MINI_B = 0;
put_message();
}
int get_scroll(int *line)
{
/* line is the line we want at the topo of the window if possible */
int dtop, dbot,n,top,bot,wsize;
top = WIN->beg_line;
wsize = WIN->bot - WIN->top; /* actually 1 less than window size */
bot = top + wsize;
if ((*line == 1) && (top == 1))
{
message("Top of Buffer.",1);
return(0);
}
/* handles endof file in a window */
if ((bot > NUM_LINES) && *line > C_LINE)
{
*line = top;
message("End of Buffer.",1);
return(0);
}
if (NUM_LINES <= wsize) /* short file */
{
*line = 1;
return(0);
}
dtop = top - 1;
dbot = NUM_LINES - bot;
n = *line - top;
if ((n>0) && (dbot < n))
{
n = dbot;
*line = top + n;
if (!n) message("End of buffer.",1);
}
else if ((n < 0) && (dtop + n < 0))
{
n = -dtop;
if (!n) message("Top of buffer.",1);
*line = n + top;
}
return(n);
}
void update_window(int line)
{
int n,max_n, save_line, save_col, npos;
unsigned char *save_pos;
read_to_line(line);
if (COLUMN != WIN->col)
{
if (COLUMN < 1) COLUMN = 1;
if (COLUMN != WIN->col)
{
save_pos = CURS_POS; save_line = CURS_ROW; save_col = CURS_COL;
redraw_window();
update_status(0);
WIN->curs_pos = CURS_POS = save_pos;
WIN->curs_line = CURS_ROW = save_line;
WIN->curs_col = CURS_COL = save_col;
}
return;
}
n = get_scroll(&line);
max_n = WIN->bot - WIN->top;
if (Term_Cannot_Scroll || (abs(n) > max_n))
{
goto_line(line);
redraw_window();
update_status(0);
return;
}
if (!n) return;
set_scroll_region(WIN->top, WIN->bot);
goto_rc(1, 1);
forward_line(n);
WIN->beg_pos = C_POS;
WIN->beg_line = C_LINE;
if (n>0)
{
npos = 1;
tt_delete_nlines(n);
set_scroll_region(1, SCREEN_HEIGHT);
goto_rc(WIN->bot - n + 1,1);
forward_line(max_n - n + 1);
}
else
{
npos = 0;
CURS_ROW = 1; CURS_COL = 1; CURS_POS = C_POS;
n = -n;
reverse_index(n);
set_scroll_region(1, SCREEN_HEIGHT);
goto_rc(WIN->top, 1);
}
n = n - 1;
display_line();
while(n--)
{
forward_line(1);
tt_putchar('\n');
display_line();
}
if (npos)
{
CURS_ROW = C_LINE - WIN->beg_line + 1;
CURS_COL = 1; CURS_POS = C_POS;
}
C_POS = WIN->beg_pos;
C_LINE = WIN->beg_line;
/* set_scroll_region(1, SCREEN_HEIGHT); */
update_status(0);
fflush(stdout);
}
/* updates current window as well as scroll lock ones */
/* Although current window is update in an absolute fashion, scroll locked
ones are updated in a relative fashion */
void update_windows(int line)
{
int dline,flg;
Window *w;
dline = line - C_LINE;
update_window(line);
if (!WIN->lock) return;
flg = 0;
w = WIN;
while(WIN = WIN->next, WIN != w)
{
if (WIN->lock)
{
flg = 1;
set_window(WIN);
line = C_LINE + dline;
update_window(line);
}
}
WIN = w;
if (flg) set_window(WIN);
}
void redraw_window()
{
int n,t;
if (Term_Cannot_Scroll) t = 0; else t = WIN->top;
if (t == 1) clear_window();
goto_rc(WIN->top, 1);
n = WIN->bot - WIN->top;
if ((C_LINE + n) > NUM_LINES) goto_line(NUM_LINES - n);
WIN->curs_pos = CURS_POS = WIN->beg_pos = C_POS;
WIN->beg_line = C_LINE;
WIN->col = COLUMN;
WIN->curs_col = CURS_COL = 1;
WIN->curs_line = CURS_ROW = 1;
if (t != 1)
{
tt_erase_line();
}
display_line();
while(n--)
{
tt_putchar('\n');
if (t != 1) tt_erase_line();
if (forward_line(1)) display_line();
}
C_POS = WIN->beg_pos;
C_LINE = WIN->beg_line;
}
/* associates current window with current buffer */
void save_win_flags(Window *w)
{
w->flags = 0;
if (MOST_V_OPT) w->flags |= _MOST_V_OPT;
if (MOST_B_OPT) w->flags |= _MOST_B_OPT;
if (MOST_T_OPT) w->flags |= _MOST_T_OPT;
if (MOST_W_OPT) w->flags |= _MOST_W_OPT;
if (SQUEEZE_LINES) w->flags |= _MOST_SQ_OPT;
w->n_lines = NUM_LINES;
w->display = MOST_S_OPT;
}
void window_buffer()
{
WIN->beg_line = C_LINE;
WIN->beg_pos = C_POS;
WIN->col = COLUMN;
WIN->buf = BUF;
MOST_S_OPT = 0;
save_win_flags(WIN);
}
void clear_window()
{
int i,n;
i = WIN->top;
n = WIN->bot - WIN->top;
set_scroll_region(WIN->top, WIN->bot);
if ((i == 1) && !Term_Cannot_Scroll)
{
/* goto_rc(WIN->bot - WIN->top + 1,SCREEN_WIDTH); */
tt_delete_nlines(1 + WIN->bot - WIN->top);
/* clr_bos(); */
}
else
{
goto_rc(i - WIN->top + 1,1);
tt_erase_line();
while(n--)
{
tt_putchar('\n');
tt_erase_line();
}
}
goto_rc(i - WIN->top + 1,1);
set_scroll_region(1, SCREEN_HEIGHT);
fflush(stdout);
}
void restore_win_flags()
{
MOST_V_OPT = WIN->flags & _MOST_V_OPT;
MOST_B_OPT = WIN->flags & _MOST_B_OPT;
MOST_T_OPT = WIN->flags & _MOST_T_OPT;
MOST_W_OPT = WIN->flags & _MOST_W_OPT;
SQUEEZE_LINES = WIN->flags & _MOST_SQ_OPT;
NUM_LINES = WIN->n_lines;
MOST_S_OPT = WIN->display;
}
Window *make_window(int r1,int r2)
{
int i;
Window *new;
new = (Window *) MALLOC(sizeof(Window));
new->status = (char *) MALLOC(135);
for (i = 0; i <= SCREEN_WIDTH; i++) new->status[i] = '\0';
new->col = COLUMN;
new->top = r1;
new->bot = r2;
new->lock = 0;
save_win_flags(new);
return(new);
}
void init_display()
{
TOP_WIN = WIN = make_window(1,SCREEN_HEIGHT - 2);
WIN->prev = WIN->next = WIN;
cls();
set_scroll_region(1, SCREEN_HEIGHT);
goto_rc(WIN->top,1);
fflush(stdout);
}
void reset_display()
{
set_scroll_region(1,SCREEN_HEIGHT);
goto_rc(SCREEN_HEIGHT,1);
if (RESTORE_WIDTH_TO)
{
set_width(RESTORE_WIDTH_TO, 0);
RESTORE_WIDTH_TO = 0;
}
fflush(stdout);
}
void update_status1(int new_status)
{
char str[30], ch, *strp;
static char new[135];
int i,ii,r,x,line_p = 60;
Buffer *buf = WIN->buf;
r = WIN->bot + 1;
goto_rc(r,1);
i = ii = 0;
new[ii++] = '-';
if (WIN->lock) new[ii++] = '*'; else new[ii++] = '-';
strp = " MOST: ";
while(*strp != '\0') new[ii++] = *strp++;
while(ch = buf->file[i++], ch != '\0') new[ii++] = ch;
while(ii < line_p) new[ii++] = ' ';
x = (C_POS - BEG) * 100;
if (buf->fd == -1)
{
if (EOB == BEG) x = 100; else x = x / (EOB - BEG);
if (C_LINE + (WIN->bot - WIN->top + 1) >= NUM_LINES) x = 100;
}
else
{
x = x / (buf->size);
}
/* x = (C_LINE + WIN->bot - WIN->top) * 100; x = x / NUM_LINES; */
/* for files with end of file above the bottom row (due to window manipulations) */
if (x > 100) x = 100;
/* stdin may not be read in yet and I do not know how big it is. */
if (buf->fd == 0) sprintf(str,"(%d,%d) ",C_LINE,COLUMN);
else
sprintf(str,"(%d,%d) %d%%",C_LINE,COLUMN,x);
i = 0; while(ch = str[i++], ch != '\0') new[ii++] = ch;
while(ii < SCREEN_WIDTH) new[ii++] = '-';
new[SCREEN_WIDTH] = '\0';
tt_reverse_video();
if (new_status)
send_string_to_term(new);
else
smart_puts((char *) new,(char *) WIN->status, r, 1);
tt_normal_video();
strcpy(WIN->status,new);
}
void update_status(int new_status)
{
C_LINE = WIN->beg_line;
C_POS = WIN->beg_pos;
/* set_scroll_region(1,SCREEN_HEIGHT); */
update_status1(new_status);
/* set_scroll_region(WIN->top,WIN->bot); */
fflush(stdout);
}
/* splits window-- no screen update, does not affect scrolling region */
int split_window()
{
Window *new, *old;
int b2,t2,b1, line;
b2 = WIN->bot;
b1 = (WIN->bot + WIN->top) / 2 - 1;
t2 = b1 + 2;
if ((b1 == WIN->top) || (t2 == b2)) return(0);
/* line is top line of new window. */
line = WIN->beg_line + t2 - WIN->top;
old = WIN;
WIN->bot = b1;
new = make_window(t2,b2);
/* add to ring */
WIN->next->prev = new;
new->next = WIN->next;
new->prev = WIN;
WIN->next = new;
new->beg_line = line;
new->buf = BUF;
/* new window status line is at same position as old */
strcpy(new->status,WIN->status);
return(1);
}
void two_windows()
{
int line;
Window *new, *old;
if (!split_window()) return;
old = WIN;
new = WIN->next;
line = new->beg_line;
if (line + new->bot - new->top > NUM_LINES)
{
other_window(1);
/* since split window left new window undefined... */
C_POS = old->beg_pos;
C_LINE = old->beg_line;
if (NUM_LINES <= new->bot - new->top + 1)
{
C_LINE = new->beg_line = 1;
C_POS = new->beg_pos = BUF->beg;
redraw_window();
update_status(0);
}
else if (line > NUM_LINES)
{
goto_line(NUM_LINES - new->bot + new->top);
WIN->beg_pos = C_POS;
WIN->beg_line = C_LINE;
redraw_window();
update_status(0);
}
else
{
goto_line(line);
WIN->beg_pos = C_POS;
WIN->beg_line = C_LINE;
update_window(NUM_LINES - new->bot + new->top);
}
WIN->curs_line = 1;
WIN->curs_col = COLUMN;
WIN->curs_pos = C_POS;
other_window(-1);
}
else
{
WIN = new;
(void) forward_line(line - old->beg_line);
new->beg_pos = C_POS;
new->beg_line = C_LINE;
new->curs_line = 1;
new->curs_col = COLUMN;
new->curs_pos = C_POS;
update_status(0);
WIN = old;
}
update_status(1);
}
void expand_window1(int dn)
{
int l, save_top, save_line;
unsigned char *save_pos;
/* l is line after last line of current window (where status line is) */
l = WIN->beg_line + WIN->bot - WIN->top + 1;
save_top = WIN->top;
WIN->top = WIN->bot + 1;
WIN->bot = WIN->bot + dn;
/* set_scroll_region(WIN->top, WIN->bot); */
if (l > NUM_LINES)
{
clear_window();
}
else
{
/* should add something here for smarter scrolling...
if ((WIN->next->BUF == BUF) && (l >= WIN->next->beg_line)
&& (l <= (WIN->next->beg_line + WIN->next)
*/
save_line = C_LINE;
save_pos = C_POS;
goto_line(l);
redraw_window();
WIN->beg_line = C_LINE = save_line;
WIN->beg_pos = C_POS = save_pos;
}
WIN->top = save_top;
/* set_scroll_region(WIN->top, WIN->bot); */
}
void one_window()
{
Window *w, *tmp;
int diff;
if (WIN->next == WIN) return;
w = WIN;
WIN = WIN->next;
/* delete other windows preserving the ring! */
while(WIN != w)
{
free_window_buffer(); /* needs a ring */
tmp = WIN->next;
/* if this is the bottom window, save its status line */
if (tmp == TOP_WIN) strcpy(w->status,WIN->status);
tmp->prev = WIN->prev;
WIN->prev->next = tmp;
free(WIN);
WIN = tmp;
}
WIN = w;
if (Term_Cannot_Scroll)
{
WIN->top = 1;
WIN->bot = SCREEN_HEIGHT - 2;
redraw_window();
}
else
{
/* slide the window to the top and expand it */
diff = WIN->top - 1;
if (diff)
{
set_scroll_region(1,SCREEN_HEIGHT - 2);
goto_rc(1,1);
tt_delete_nlines(diff);
WIN->top = 1;
WIN->bot -= diff;
TOP_WIN = WIN;
}
expand_window1(SCREEN_HEIGHT - 2 - WIN->bot);
set_scroll_region(1, SCREEN_HEIGHT);
}
update_status(0);
}
void set_window(Window *w)
{
WIN = w;
CURS_ROW = WIN->curs_line;
CURS_COL = WIN->curs_col;
CURS_POS = WIN->curs_pos;
C_LINE = WIN->beg_line;
C_POS = WIN->beg_pos;
COLUMN = WIN->col;
BUF = WIN->buf;
switch_to_buffer(BUF);
/* set_scroll_region(WIN->top,WIN->bot); */
restore_win_flags();
fflush(stdout);
}
void other_window(int n)
{
if (!n) return;
WIN->beg_pos = C_POS;
WIN->curs_pos = CURS_POS;
WIN->curs_line = CURS_ROW;
WIN->curs_col = CURS_COL;
WIN->beg_line = C_LINE;
save_win_flags(WIN);
if (n < 0)
while (n++) WIN = WIN->prev;
else
while (n--) WIN = WIN->next;
set_window(WIN);
}
/* kills window by moving lower window up */
void delete_as_top_window()
{
int t1,t2,b1,b2;
t1 = WIN->top;
t2 = WIN->next->top;
b1 = WIN->bot;
b2 = WIN->next->bot;
WIN->prev->next = WIN->next;
WIN->next->prev = WIN->prev;
if (Term_Cannot_Scroll)
{
other_window(1);
WIN->top = t1;
redraw_window();
}
else
{
/* scroll contents of window below to top */
set_scroll_region(t1,b2);
goto_rc(1,1);
tt_delete_nlines(t2 - t1);
other_window(1);
WIN->top = t1;
WIN->bot = b2 - t2 + t1;
expand_window1(b2 - WIN->bot);
}
update_status(0);
}
/* free buffer for this window if no other windows are viewing it. */
void free_window_buffer()
{
Window *w;
Buffer *b;
w = WIN->next;
while(WIN != w)
{
if (!strcmp(WIN->buf->file,w->buf->file)) return;
w = w->next;
}
b = w->buf;
if (b->fd != -1) close(b->fd);
free(b->beg);
free(b);
}
void delete_window()
{
int new_b, old_b;
Window *w;
w = WIN;
if (WIN->next == WIN) return;
free_window_buffer();
if (WIN->next != TOP_WIN)
{
if (WIN == TOP_WIN)
{
delete_as_top_window();
TOP_WIN = WIN; /* not anymore, this one is */
}
else
delete_as_top_window();
free(w);
return;
}
old_b = WIN->top - 2;
new_b = WIN->bot;
other_window(-1);
if (Term_Cannot_Scroll)
{
WIN->bot = new_b;
redraw_window();
}
else expand_window1(new_b - old_b);
strcpy(WIN->status,w->status); /* share the same line */
WIN->next = w->next;
WIN->next->prev = WIN;
free(w);
update_status(0);
}
void redraw_display()
{
Window *w;
int n,t;
set_scroll_region(1,SCREEN_HEIGHT);
cls();
save_win_flags(WIN);
w = WIN;
do
{
WIN = WIN->next;
t = WIN->top;
goto_rc(t, 1);
C_POS = WIN->beg_pos;
C_LINE = WIN->beg_line;
COLUMN = WIN->col;
switch_to_buffer(WIN->buf);
restore_win_flags();
n = WIN->bot - WIN->top;
display_line();
while(n--)
{
tt_putchar('\n');
if (forward_line(1)) display_line();
}
C_LINE = WIN->beg_line;
C_POS = WIN->beg_pos;
update_status1(1);
}
while(WIN != w);
set_window(w);
}
void toggle_lock()
{
WIN->lock = !(WIN->lock);
update_status(0);
}