This is edit.c in view mode; [Download] [Up]
/* $Id$ */
#include "edit.h"
/* #define EDB */
/* #define SHOWNL */
int edit(const char *filename, const MODE_T mode, const boolean noclobber,
const U_INT showmsgtime, const confrecordtyp *confrecord)
/*
Rueckgabewerte: 0 bei Quit (mit Abspeichern)
1 bei Abbruch (ohne Abspeichern)
-1 bei internem Fehler
*/
{
int y_p, x_p, zeilen, k, run, fd=-1, rw;
double t;
char *sp, zeile[STRLEN+2], prompt[STRLEN+2], key;
char *footline = "Editor";
termkeystruct termkeys[] = {
{"kr", NULL, CurRight},
{"kl", NULL, CurLeft},
{"kd", NULL, CurDown},
{"ku", NULL, CurUp},
{"kr", "\006", CurRight},
{"kl", "\002", CurLeft},
{"kd", "\016", CurDown},
{"ku", "\020", CurUp},
{"kr", "\033[C", CurRight},
{"kl", "\033[D", CurLeft},
{"kd", "\033[B", CurDown},
{"ku", "\033[A", CurUp},
{"??", "\033v", PageDown},
{"", (char *)0, NoCmd}
};
posstruct txt;
screenstruct scr;
tlistetyp *tliste;
keyboardcmd cmd, cmdcmd;
FILE *fp;
struct termios save_edit_termios;
tty_editstateenum ttyeditstate = TTY_EDIT_RESET;
rw = -1;
scr.cols = COLS;
scr.lines = LINES;
scr.curlines = LINES-1;
scr.showcmdline = TRUE;
if (scr.cols+2 > STRLEN) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"terminal with too many columns");
return -1;
}
gettermkeys(termkeys, confrecord);
txt.writeable = TRUE;
if (access(filename,F_OK) < 0) {
if ((fd=open(filename,O_RDWR|O_CREAT|O_EXCL,mode==0?0666:mode)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"cannot create %s: open: %m",filename);
return -1;
}
close(fd);
}
else if (access(filename,W_OK) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"WARNING: %s is readable only",filename);
txt.writeable = FALSE;
}
#ifdef USE_FLOCK
if ((fd=open(filename,O_RDONLY)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"open %s: %m",filename);
return -1;
}
if (flock(fd,LOCK_EX|LOCK_NB) < 0) {
if (errno == EWOULDBLOCK) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"WARNING: %s is locked, you cannot write to it",filename);
}
else {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"WARNING: cannot lock %s: %m, you cannot write to it ",filename);
}
txt.writeable = FALSE;
}
#endif
if ((fp=fopen(filename,"r")) == NULL) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"fopen %s: %m",filename);
return -1;
}
tliste = (tlistetyp *)0;
zeilen = 0;
while (fgets(zeile,scr.cols+1,fp) != NULL) {
addstrtoliste(&tliste,TRUE,zeilen++,TL_BLOCKLEN,zeile,confrecord);
}
fclose(fp);
if (zeilen == 0) {
strcpy(zeile,"\n");
addstrtoliste(&tliste,TRUE,zeilen++,TL_BLOCKLEN,zeile,confrecord);
}
else {
k = strlen(zeile) - 1;
if (k < 0) k = 0;
if (zeile[k] != '\n') {
zeile[k] = '\n';
zeile[k+1] = '\0';
addstrtoliste(&tliste,TRUE,zeilen-1,TL_BLOCKLEN,zeile,confrecord);
}
}
clear();
move(scr.lines-1,0);
standout();
addstr(footline);
standend();
refresh();
scrollok(stdscr,FALSE);
move(0,0);
txt.t_x = 0;
txt.t_y = 0;
txt.a_x = 0;
txt.a_y = 0;
txt.a_t = 0;
txt.a_offset = 0;
txt.a_zeilen = zeilen;
readliste(&tliste,FALSE,0,TL_BLOCKLEN,&sp,confrecord);
txt.a_zeile = sp;
txt.vscroll_a_x = 0;
txt.unsaved = FALSE;
printline(sp);
for (k=1; k<scr.curlines && k<txt.a_zeilen; k++) {
readliste(&tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
move(k,0);
printline(sp);
}
move(0,0);
refresh();
run = 0;
tty_editset(STDIN_FILENO,&save_edit_termios,&ttyeditstate);
cmdcmd = NoCmd;
do {
#ifdef EDB
sprintf(prompt,"a_x=%d a_y=%d t_x=%d t_y=%d off=%d zei=%d",
txt.a_x,txt.a_y,txt.t_x,txt.t_y,txt.a_offset,txt.a_zeilen);
getyx(stdscr,y_p,x_p);
move(scr.lines-1,0);
clrtoeol();
standout();
addstr(prompt);
standend();
move(y_p,x_p);
refresh();
#else
if (scr.showcmdline) {
getyx(stdscr,y_p,x_p);
move(scr.lines-1,0);
clrtoeol();
standout();
if (txt.writeable) {
addstr("Edit: press CTRL-X or Escape for commands");
}
else {
addstr("Edit [read only]: press CTRL-X or Escape for commands");
}
sprintf(prompt,"line %d, char %d",txt.t_y+1,txt.t_x+1);
move(scr.lines-1,scr.cols-strlen(prompt)-1);
addstr(prompt);
standend();
move(y_p,x_p);
}
#endif
t = microtime();
if (cmdcmd == NoCmd) {
cmd = keyboardin(&key,termkeys,confrecord);
run++;
}
else {
cmd = cmdcmd;
cmdcmd = NoCmd;
}
if (microtime()-t > KEYBOARDIN_R_TIME) run = 0;
if (run > 8) cmd = NoCmd;
switch (cmd) {
case InsChar:
ins_char(key,&txt,&scr,&tliste,confrecord);
break;
case ReturnChar:
return_char(&txt,&scr,&tliste,confrecord);
break;
case DelChar:
del_char(&txt,&scr,&tliste,confrecord);
break;
case KillLine:
kill_line(&txt,&scr,&tliste,confrecord);
break;
case CurUp:
if (run > 1) break;
cur_up(&txt,&scr,&tliste,confrecord);
break;
case CurDown:
if (run > 1) break;
cur_down(&txt,&scr,&tliste,confrecord);
break;
case CurLeft:
cur_left(&txt,&scr,&tliste,confrecord);
break;
case CurRight:
cur_right(&txt,&scr,&tliste,confrecord);
break;
case LineStart:
line_start(&txt,confrecord);
break;
case LineEnd:
line_end(&txt,confrecord);
break;
case PageUp:
page_screen(&txt,&scr,&tliste,scr.curlines-2,confrecord);
break;
case PageDown:
page_screen(&txt,&scr,&tliste,-scr.curlines+2,confrecord);
break;
case RedrawEdWin:
redraw_screen(&txt,&scr,&tliste,confrecord);
break;
case CmdLine:
cmdcmd = cmdline(&txt,&scr,&tliste,confrecord);
break;
case QuitEdit:
if (save_file(filename,mode,&txt,noclobber,&scr,&tliste,showmsgtime,
confrecord) == 0) {
key = '\0';
rw = 0;
}
break;
case SaveFile:
save_file(filename,mode,&txt,noclobber,&scr,&tliste,showmsgtime,
confrecord);
break;
case AbortEdit:
key = '\0';
rw = 1;
break;
case NoCmd:
break;
case ErrCmd:
errormsg(E_LOGFILE|E_USER,confrecord,"edit","edit",
"error on reading/controling terminal input: %m");
key = ESCAPE_KEY;
break;
}
} while (key != '\0');
tty_editreset(STDIN_FILENO,&save_edit_termios,&ttyeditstate);
removeliste(&tliste,TRUE,TL_BLOCKLEN);
#ifdef USE_FLOCK
flock(fd,LOCK_UN);
#endif
close(fd);
return rw;
}
int gettermkeys(termkeystruct termkeys[], const confrecordtyp *confrecord)
{
int n;
char *sp, tgetentbuf[TGETENTBUF];
const char *term;
static char buf[1024];
#ifdef EDIT_MAIN
if ((term=getenv("TERM")) == NULL) term = "unknown";
#else
term = confrecord->userrecord.term;
#endif
n = tgetent(tgetentbuf,term);
if (n < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","gettermkeys",
"cannot open terminal database");
return(-1);
}
else if (n == 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","gettermkeys",
"%s: unknown terminal type",term);
return(-1);
}
sp = buf;
for (n=0; *termkeys[n].id; n++) {
if (termkeys[n].sequenz == NULL) {
if ((termkeys[n].sequenz=tgetstr(termkeys[n].id,&sp)) == NULL) {
errormsg(E_LOGFILE,confrecord,"edit","gettermkeys",
"%s: not capable of %s",term,termkeys[n].id);
}
}
}
return 0;
}
keyboardcmd keyboardin(char *key, const termkeystruct termkeys[],
const confrecordtyp *confrecord)
{
int seq[100], seqanz, k, n;
static int p=0, len=0;
char c;
static char inbuf[INBUFLEN];
boolean termsequenz;
refresh();
termsequenz = FALSE;
for (k=0,seqanz=0; *termkeys[k].id; k++) {
if (termkeys[k].sequenz != NULL) seq[seqanz++] = k;
}
n = 0;
do {
if (p == len) {
len = read(STDIN_FILENO,inbuf,INBUFLEN);
p = 0;
}
c = inbuf[p++];
for (k=0; k<seqanz; k++) {
if (c != termkeys[seq[k]].sequenz[n]) {
seq[k] = seq[--seqanz];
k--;
}
}
if (seqanz == 1) {
if (termkeys[seq[0]].sequenz[n+1] == '\0') {
termsequenz = TRUE;
}
}
else if (seqanz > 0 && ! termsequenz && n == 0 && p == len) {
len = waitread(STDIN_FILENO,inbuf,INBUFLEN,KEYBOARDIN_SEQ_DELAY);
p = 0;
if (len == 0) seqanz = 0;
}
n++;
} while (! termsequenz && seqanz > 0 && len >= 0);
if (len < 0) return ErrCmd;
*key = c;
if (termsequenz) return termkeys[seq[0]].cmd;
if (c == BACKSPACE_KEY || c == DELETE_KEY) return DelChar;
if (c == KILL_LINE) return KillLine;
if (c == RETURN_KEY || c == NEWLINE_KEY) return ReturnChar;
if (c == PAGE_UP) return PageUp;
if (c == PAGE_DOWN) return PageDown;
if (c == LINE_START) return LineStart;
if (c == LINE_END) return LineEnd;
if (c == REDRAW_ED_WIN) return RedrawEdWin;
if (c == ESCAPE_KEY || c == CMDLINE) return CmdLine;
return InsChar;
}
#ifndef CUSTOM_EDITCMDLINE
keyboardcmd cmdline(posstruct *txt, screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int x_p, y_p, k;
char *sp, cmd[81];
const char keyset[] = {'S','G','Q','A','C','?',ESCAPE_KEY,RETURN_KEY,'\0'};
const char *prompt = "[S]ave [G]oto [Q]uit [A]bort [C]mdline_off [?]help";
getyx(stdscr,y_p,x_p);
scr->showcmdline = TRUE;
scr->curlines = scr->lines - 1;
if (y_p == scr->lines - 1) {
txt->a_offset++;
scrollok(stdscr,TRUE);
scroll(stdscr);
scrollok(stdscr,FALSE);
move(y_p-1,x_p);
}
if (getcmd_on_prompt(cmd,80,prompt,keyset,TRUE,scr)) {
switch (*cmd) {
case 'S':
return SaveFile;
break;
case 'G':
if (getcmd_on_prompt(cmd,80,"goto line:",NULL,FALSE,scr)) {
if (strcmp(cmd,"$") != 0) {
k = atoi(cmd);
}
else {
k = -1;
}
text_jump(k,txt,scr,tliste,confrecord);
}
break;
case 'Q':
return QuitEdit;
break;
case 'A':
if (! txt->unsaved) return AbortEdit;
if (getcmd_on_prompt(cmd,80,"really exit editor WITHOUT save [Y,N]? ",
"YJN",TRUE,scr)) {
if (*cmd != 'N') {
return AbortEdit;
}
}
break;
case 'C':
scr->showcmdline = FALSE;
scr->curlines = scr->lines;
move(scr->lines-1,0);
clrtoeol();
k = txt->a_offset + scr->lines - 1;
if ( k < txt->a_zeilen) {
readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
printline(sp);
}
move(y_p,x_p);
break;
case '?':
showhelp(scr,confrecord);
break;
}
}
waitread(STDIN_FILENO,cmd,80,KEYBOARDIN_SEQ_DELAY);
return NoCmd;
}
#endif
void cur_right(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int x_p, y_p;
char c;
c = txt->a_zeile[txt->a_x+1];
if ( c != '\0') {
txt->a_x++;
txt->t_x++;
txt->vscroll_a_x = txt->a_x;
getyx(stdscr,y_p,x_p);
move(y_p,++x_p);
}
else if (txt->a_y < txt->a_zeilen-1) {
if (txt->a_zeile[strlen(txt->a_zeile)-1] == '\n') {
txt->a_t = 0;
txt->t_y++;
}
else {
txt->a_t++;
}
txt->a_y++;
readliste(tliste,FALSE,txt->a_y,TL_BLOCKLEN,&txt->a_zeile,confrecord);
txt->a_x = 0;
txt->t_x = txt->a_t * scr->cols;
txt->vscroll_a_x = 0;
getyx(stdscr,y_p,x_p);
if (y_p < scr->curlines-1) {
y_p++;
}
else {
scrollok(stdscr,TRUE);
scroll(stdscr);
scrollok(stdscr,FALSE);
move(scr->curlines-1,0);
clrtoeol();
printline(txt->a_zeile);
txt->a_offset++;
}
move(y_p,0);
}
else {
ringbell();
}
return;
}
void cur_left(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int x_p, y_p, k;
char c;
char *sp;
if (txt->a_x > 0) {
txt->a_x--;
txt->t_x--;
txt->vscroll_a_x = txt->a_x;
getyx(stdscr,y_p,x_p);
move(y_p,--x_p);
}
else if (txt->a_y > 0) {
txt->a_y--;
readliste(tliste,FALSE,txt->a_y,TL_BLOCKLEN,&txt->a_zeile,confrecord);
c = txt->a_zeile[strlen(txt->a_zeile)-1];
if (c == '\n') txt->t_y--;
k = txt->a_y;
while (k>0 && c!='\n') {
readliste(tliste,FALSE,--k,TL_BLOCKLEN,&sp,confrecord);
c = sp[strlen(sp)-1];
}
txt->a_t = txt->a_y - k;
for (sp=txt->a_zeile,k=0; *sp && *sp!='\n' && k<scr->cols-1; sp++,k++) ;
txt->a_x = k;
txt->t_x = txt->a_t * scr->cols + txt->a_x;
txt->vscroll_a_x = txt->a_x;
getyx(stdscr,y_p,x_p);
if (y_p > 0) {
y_p--;
}
else {
scrollok(stdscr,TRUE);
insertln();
scrollok(stdscr,FALSE);
move(0,0);
printline(txt->a_zeile);
txt->a_offset--;
}
move(y_p,txt->a_x);
}
else {
ringbell();
}
return;
}
void cur_down(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int x_p, y_p, k;
char *sp;
if (txt->a_y < txt->a_zeilen-1) {
if (txt->a_zeile[strlen(txt->a_zeile)-1] == '\n') {
txt->a_t = 0;
txt->t_y++;
}
else {
txt->a_t++;
}
txt->a_y++;
readliste(tliste,FALSE,txt->a_y,TL_BLOCKLEN,&txt->a_zeile,confrecord);
getyx(stdscr,y_p,x_p);
for (k=0,sp=txt->a_zeile; k<txt->vscroll_a_x && *sp && *sp!='\n'; k++,sp++)
;
txt->a_x = k;
txt->t_x = txt->a_t * scr->cols + k;
if (y_p < scr->curlines-1) {
y_p++;
}
else {
scrollok(stdscr,TRUE);
scroll(stdscr);
scrollok(stdscr,FALSE);
move(scr->curlines-1,0);
clrtoeol();
printline(txt->a_zeile);
txt->a_offset++;
}
move(y_p,txt->a_x);
}
else {
ringbell();
}
return;
}
void cur_up(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int x_p, y_p, k;
char *sp, c;
if (txt->a_y > 0) {
txt->a_y--;
readliste(tliste,FALSE,txt->a_y,TL_BLOCKLEN,&txt->a_zeile,confrecord);
getyx(stdscr,y_p,x_p);
for (k=0,sp=txt->a_zeile; k<txt->vscroll_a_x && *sp && *sp!='\n'; k++,sp++)
;
txt->a_x = k;
c = txt->a_zeile[strlen(txt->a_zeile)-1];
if (c == '\n') txt->t_y--;
k = txt->a_y;
while (k>0 && c!='\n') {
readliste(tliste,FALSE,--k,TL_BLOCKLEN,&sp,confrecord);
c = sp[strlen(sp)-1];
}
txt->a_t = txt->a_y - k;
txt->t_x = txt->a_t * scr->cols + txt->a_x;
if (y_p > 0) {
y_p--;
}
else {
scrollok(stdscr,TRUE);
insertln();
scrollok(stdscr,FALSE);
move(0,0);
printline(txt->a_zeile);
txt->a_offset--;
}
move(y_p,txt->a_x);
}
else {
ringbell();
}
return;
}
void line_start(posstruct *txt, const confrecordtyp *confrecord)
{
int y_p, x_p;
getyx(stdscr,y_p,x_p);
txt->t_x -= txt->a_x;
txt->a_x = 0;
txt->vscroll_a_x = 0;
move(y_p,0);
return;
}
void line_end(posstruct *txt, const confrecordtyp *confrecord)
{
int y_p, x_p, k;
getyx(stdscr,y_p,x_p);
for (k=txt->a_x; txt->a_zeile[k] != '\n' && txt->a_zeile[k] != '\0'; k++) ;
txt->t_x += k - txt->a_x;
txt->a_x = k;
txt->vscroll_a_x = k;
move(y_p,k);
return;
}
void text_jump(const int znr, posstruct *txt, const screenstruct *scr,
tlistetyp **tliste, const confrecordtyp *confrecord)
{
int x_p, y_p, maxznr, nznr, k, n=0;
char *sp, *cp;
nznr = znr;
if (znr == -1) nznr = 1;
maxznr = 0;
for (k=0; k<txt->a_zeilen; k++) {
readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
for (cp=sp; *cp != '\n' && *cp; cp++) ;
if (*cp == '\n') {
maxznr++;
if (maxznr == nznr) n = k;
}
}
if (znr == -1) {
nznr = maxznr;
n = txt->a_zeilen - 1;
}
if (nznr <= 0) {
getyx(stdscr,y_p,x_p);
move(scr->lines-1,0);
addstr("negative or zero line numbers not allowed");
refresh();
sleep(2);
move(y_p,x_p);
}
else if (nznr > maxznr) {
getyx(stdscr,y_p,x_p);
move(scr->lines-1,0);
printw("there are only %d line numbers",maxznr);
refresh();
sleep(2);
move(y_p,x_p);
}
else {
txt->a_offset = n - scr->lines / 2;
if (txt->a_offset < 0) txt->a_offset = 0;
if (txt->a_offset > txt->a_zeilen - scr->curlines) {
txt->a_offset = txt->a_zeilen - scr->curlines;
}
txt->a_y = n;
txt->a_x = 0;
txt->t_y = nznr-1;
txt->t_x = 0;
txt->vscroll_a_x = 0;
redraw_screen(txt,scr,tliste,confrecord);
}
return;
}
void page_screen(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const int step, const confrecordtyp *confrecord)
{
txt->a_y += step;
if (txt->a_y > txt->a_zeilen - scr->curlines/2) {
txt->a_y = txt->a_zeilen - scr->curlines/2;
}
if (txt->a_y < 0) txt->a_y = 0;
txt->a_offset = txt->a_y - scr->curlines/2;
if (txt->a_offset < 0) txt->a_offset = 0;
redraw_screen(txt,scr,tliste,confrecord);
return;
}
int ins_char(const char c, posstruct *txt, const screenstruct *scr,
tlistetyp **tliste, const confrecordtyp *confrecord)
{
int y_p, x_p, n;
char *sp, carry;
if (! txt->writeable) {
showcmdlmsg("File is not writeable",1,scr);
ringbell();
return 0;
}
else {
txt->unsaved = TRUE;
}
getyx(stdscr,y_p,x_p);
if ((sp=strinsert_char(txt->a_zeile,c,txt->a_x,&carry,scr->cols,confrecord)) !=
txt->a_zeile) {
addstrtoliste(tliste,FALSE,txt->a_y,TL_BLOCKLEN,sp,confrecord);
txt->a_zeile = sp;
}
insch(c);
for (n=1; carry!='\0' && carry!='\n'; n++) {
if (y_p+n < scr->curlines) mvinsch(y_p+n,0,carry);
readliste(tliste,FALSE,txt->a_y+n,TL_BLOCKLEN,&sp,confrecord);
if ((sp=strinsert_char(sp,carry,0,&carry,scr->cols,confrecord)) != sp) {
addstrtoliste(tliste,FALSE,txt->a_y+n,TL_BLOCKLEN,sp,confrecord);
}
}
if (carry == '\n') {
insert_empty_line(txt,txt->a_y+n,y_p+n,scr,tliste,confrecord);
if (y_p == scr->curlines-1) y_p--;
}
move(y_p,x_p);
cur_right(txt,scr,tliste,confrecord);
return 0;
}
int return_char(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int y_p, x_p;
char *sp;
if (! txt->writeable) {
showcmdlmsg("File is not writeable",1,scr);
ringbell();
return 0;
}
else {
txt->unsaved = TRUE;
}
getyx(stdscr,y_p,x_p);
clrtoeol();
insert_empty_line(txt,txt->a_y+1,y_p+1,scr,tliste,confrecord);
readliste(tliste,FALSE,txt->a_y+1,TL_BLOCKLEN,&sp,confrecord);
addstrtoliste(tliste,TRUE,txt->a_y+1,TL_BLOCKLEN,&txt->a_zeile[txt->a_x],
confrecord);
txt->a_zeile[txt->a_x] = '\n';
txt->a_zeile[txt->a_x+1] = '\0';
readliste(tliste,FALSE,txt->a_y+1,TL_BLOCKLEN,&txt->a_zeile,confrecord);
if (y_p < scr->curlines-1) y_p++;
txt->a_x = 0;
txt->a_y++;
txt->t_x = 0;
txt->t_y++;
txt->vscroll_a_x = txt->a_x;
move(y_p,0);
printline(txt->a_zeile);
rebreak_t_line(txt,txt->a_y,y_p,scr,tliste,confrecord);
move(y_p,0);
txt->a_x = 0;
txt->t_x = 0;
return 0;
}
void del_char(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int y_p, x_p, n, len;
char *sp, carry;
if (! txt->writeable) {
showcmdlmsg("File is not writeable",1,scr);
ringbell();
return;
}
else {
txt->unsaved = TRUE;
}
if (txt->a_x == 0 && txt->a_y == 0) {
ringbell();
return;
}
if (txt->t_x == 0 && txt->a_y > 0) {
cur_left(txt,scr,tliste,confrecord);
getyx(stdscr,y_p,x_p);
join_lines(txt,txt->a_y,y_p,scr,tliste,confrecord);
}
else {
cur_left(txt,scr,tliste,confrecord);
getyx(stdscr,y_p,x_p);
sp = txt->a_zeile;
len = strlen(sp);
n = 0;
while (sp[len-1] != '\n') {
n++;
readliste(tliste,FALSE,txt->a_y+n,TL_BLOCKLEN,&sp,confrecord);
len = strlen(sp);
}
if (*sp == '\n') {
delete_line(txt,txt->a_y+n,y_p+n,scr,tliste,confrecord);
n--;
if (n > 0) readliste(tliste,FALSE,txt->a_y+n,TL_BLOCKLEN,&sp,confrecord);
carry = '\n';
}
else {
carry = '\0';
}
while (n > 0) {
if (y_p+n < scr->curlines) {
mvdelch(y_p+n,0);
len = strlen(sp);
if (carry == '\0') {
mvdelch(y_p+n,len-1);
}
else {
mvaddch(y_p+n,len-1,carry);
}
}
strdel_char(sp,0,&carry);
n--;
if (n > 0) readliste(tliste,FALSE,txt->a_y+n,TL_BLOCKLEN,&sp,confrecord);
}
if (n >= 0) {
mvdelch(y_p,txt->a_x);
len = strlen(txt->a_zeile);
if (carry == '\0') {
mvdelch(y_p,len-1);
}
else {
mvaddch(y_p,len-1,carry);
}
strdel_char(txt->a_zeile,txt->a_x,&carry);
}
}
move(y_p,x_p);
return;
}
int join_lines(posstruct *txt, const int a_y, const int s_y,
const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int y_p, x_p, n;
SIZE_T len;
char *sp;
if (! txt->writeable) {
showcmdlmsg("File is not writeable",1,scr);
ringbell();
return 0;
}
else {
txt->unsaved = TRUE;
}
getyx(stdscr,y_p,x_p);
if (a_y == txt->a_y) {
sp = txt->a_zeile;
}
else {
readliste(tliste,FALSE,a_y,TL_BLOCKLEN,&sp,confrecord);
}
len = strlen(sp);
n = 0;
while (a_y+n < txt->a_zeilen && sp[len-1] != '\n') {
n++;
readliste(tliste,FALSE,a_y+n,TL_BLOCKLEN,&sp,confrecord);
len = strlen(sp);
}
if (a_y+n < txt->a_zeilen-1) sp[len-1] = '\0';
rebreak_t_line(txt,a_y+n,y_p+n,scr,tliste,confrecord);
txt->vscroll_a_x = txt->a_x;
move(y_p,x_p);
return 0;
}
void kill_line(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int y_p, x_p;
char *sp, c;
if (! txt->writeable) {
showcmdlmsg("File is not writeable",1,scr);
ringbell();
return;
}
else {
txt->unsaved = TRUE;
}
getyx(stdscr,y_p,x_p);
c = txt->a_zeile[strlen(txt->a_zeile)-1];
if (txt->a_zeile[txt->a_x] != '\n') {
txt->a_zeile[txt->a_x] = '\n';
txt->a_zeile[txt->a_x+1] = '\0';
clrtoeol();
while (c != '\n' && txt->a_y < txt->a_zeilen) {
readliste(tliste,FALSE,txt->a_y+1,TL_BLOCKLEN,&sp,confrecord);
c = sp[strlen(sp)-1];
delete_line(txt,txt->a_y+1,y_p+1,scr,tliste,confrecord);
}
}
else {
join_lines(txt,txt->a_y,y_p,scr,tliste,confrecord);
}
if (txt->a_y == txt->a_zeilen-1 && *txt->a_zeile == '\n' &&
txt->a_zeilen > 1) {
readliste(tliste,FALSE,txt->a_y-1,TL_BLOCKLEN,&sp,confrecord);
if (*sp == '\n') {
txt->a_y--;
delete_line(txt,txt->a_y+1,y_p,scr,tliste,confrecord);
}
}
txt->vscroll_a_x = txt->a_x;
move(y_p,x_p);
return;
}
int insert_empty_line(posstruct *txt, const int a_y, const int s_y,
const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
if (a_y < 0 || a_y > txt->a_zeilen) return -1;
inserttoliste(tliste,TRUE,a_y,&txt->a_zeilen,TL_BLOCKLEN,"\n",confrecord);
if (s_y < 0 || s_y > scr->curlines) return 0;
scrollok(stdscr,TRUE);
if (s_y < scr->curlines) {
move(s_y,0);
insertln();
}
else {
scroll(stdscr);
move(scr->curlines-1,0);
clrtoeol();
txt->a_offset++;
}
scrollok(stdscr,FALSE);
return 0;
}
int delete_line(posstruct *txt, const int a_y, const int s_y,
const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int k;
char *sp;
if (a_y < 0 || a_y >= txt->a_zeilen) return -1;
delfromliste(tliste,TRUE,a_y,&txt->a_zeilen,TL_BLOCKLEN,confrecord);
if (a_y == txt->a_y) {
readliste(tliste,FALSE,a_y,TL_BLOCKLEN,&txt->a_zeile,confrecord);
}
if (s_y < 0 || s_y > scr->curlines-1) return 0;
move(scr->curlines,0);
clrtoeol();
k = scr->curlines -1 + txt->a_offset;
if (k < txt->a_zeilen) {
readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
printline(sp);
}
move(s_y,0);
scrollok(stdscr,TRUE);
deleteln();
scrollok(stdscr,FALSE);
return 0;
}
char *rebreak_t_line(posstruct *txt, const int a_y, const int s_y,
const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int k, q, n, zeile;
SIZE_T len;
char *sp, *sp2, *nsp;
n = 0;
do {
if (a_y+n == txt->a_y) {
sp = txt->a_zeile;
}
else {
readliste(tliste,FALSE,a_y+n,TL_BLOCKLEN,&sp,confrecord);
}
len = strlen(sp);
n++;
} while (len == scr->cols && a_y+n < txt->a_zeilen);
if (a_y+n >= txt->a_zeilen) return sp;
if (len > 0 && sp[len-1] == '\n') return sp;
if ((nsp=(char *)realloc((void *)sp,scr->cols+1)) == NULL) {
errormsg(E_LOGFILE|E_CONSOLE,confrecord,"edit","rebreak_t_line",
"realloc: %m");
return(NULL);
}
addstrtoliste(tliste,FALSE,a_y+n-1,TL_BLOCKLEN,nsp,confrecord);
sp = nsp;
if (a_y+n-1 == txt->a_y) {
txt->a_zeile = sp;
}
if (len > 0 && sp[len-1] == '\n') len--;
k = len;
q = 0;
zeile = s_y + n - 1;
readliste(tliste,FALSE,a_y+n,TL_BLOCKLEN,&sp2,confrecord);
do {
if (q == scr->cols) {
n++;
readliste(tliste,FALSE,a_y+n,TL_BLOCKLEN,&sp2,confrecord);
q = 0;
}
if (k == scr->cols) {
sp[k] = '\0';
if (zeile < scr->curlines) {
move(zeile,0);
printline(sp);
zeile++;
}
sp = sp2;
k = 0;
}
sp[k++] = sp2[q++];
} while (q > 0 && sp2[q-1] != '\n');
sp[k] = '\0';
if (zeile < scr->curlines) {
move(zeile,0);
printline(sp);
clrtoeol();
}
if (sp != sp2) delete_line(txt,a_y+n,s_y+n,scr,tliste,confrecord);
return nsp;
}
char *strinsert_char(char *str, const char ichar, const SIZE_T ipos,
char *carry, const SIZE_T mlen,
const confrecordtyp *confrecord)
{
int k;
SIZE_T len;
len = strlen(str);
if (len < mlen) {
len++;
if ((str=(char *)realloc((void *)str,len+1)) == NULL) {
errormsg(E_LOGFILE|E_CONSOLE,confrecord,"edit","strinsert_char",
"realloc: %m");
return(NULL);
}
str[len] = '\0';
}
*carry = str[len-1];
for (k=len-1; k>ipos; k--) str[k] = str[k-1];
str[ipos] = ichar;
return str;
}
char *strdel_char(char *str, const SIZE_T dpos, char *carry)
{
int k;
SIZE_T len;
char c;
len = strlen(str);
c = str[dpos];
for (k=dpos+1; k<len; k++) str[k-1] = str[k];
str[len-1] = *carry;
*carry = c;
return str;
}
void redraw_screen(posstruct *txt, const screenstruct *scr, tlistetyp **tliste,
const confrecordtyp *confrecord)
{
int x_p, y_p, k;
char *sp, *cp;
getyx(stdscr,y_p,x_p);
if (txt->a_offset >= txt->a_zeilen) txt->a_offset = txt->a_zeilen - 1;
if (txt->a_offset < 0) txt->a_offset = 0;
if (txt->a_x < 0) txt->a_x = 0;
if (txt->a_x > scr->cols-1) txt->a_x = scr->cols-1;
if (txt->a_y < 0) txt->a_y = 0;
if (txt->a_y > txt->a_zeilen-1) txt->a_y = txt->a_zeilen-1;
if (txt->a_y < txt->a_offset) txt->a_offset = txt->a_y;
if (txt->a_y > txt->a_offset+scr->curlines-1) {
txt->a_offset = txt->a_y - scr->curlines + 1;
}
y_p = txt->a_y - txt->a_offset;
txt->t_y = 0;
txt->t_x = 0;
txt->vscroll_a_x = txt->a_x;
for (k=0; k<txt->a_offset; k++) {
readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
for (cp=sp; *cp != '\n' && *cp; cp++) ;
if (*cp == '\n') {
txt->t_y++;
txt->t_x = 0;
}
else {
txt->t_x += scr->cols;
}
}
clear();
for (k=txt->a_offset; k<txt->a_y; k++) {
readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
move(k-txt->a_offset,0);
printline(sp);
for (cp=sp; *cp != '\n' && *cp; cp++) ;
if (*cp == '\n') {
txt->t_y++;
txt->t_x = 0;
}
else {
txt->t_x += scr->cols;
}
}
readliste(tliste,FALSE,txt->a_y,TL_BLOCKLEN,&txt->a_zeile,confrecord);
txt->t_x += x_p;
move(txt->a_y-txt->a_offset,0);
printline(txt->a_zeile);
for (k=txt->a_y+1; k<txt->a_offset+scr->curlines && k<txt->a_zeilen; k++) {
readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord);
move(k-txt->a_offset,0);
printline(sp);
}
move(y_p,x_p);
refresh();
return;
}
void printline(const char *line)
{
while (*line && *line!='\n') {
addch(*line++);
}
#ifdef SHOWNL
if (*line == '\n') {
standout();
addch('#');
standend();
}
#endif
return;
}
void ringbell()
{
const char bell=BELL_KEY;
writen(STDERR_FILENO,(void *)&bell,(SIZE_T)sizeof(char));
return;
}
boolean getcmd_on_prompt(char *cmd, const SIZE_T mlen, const char *prompt,
const char *keyset, const boolean maptoupper,
const screenstruct *scr)
{
int y_p, x_p;
int errs;
boolean ok;
getyx(stdscr,y_p,x_p);
move(scr->lines-1,0);
clrtoeol();
standout();
addstr(prompt);
standend();
addch(' ');
refresh();
if (keyset == NULL) {
ok = (readcommand(cmd,mlen) > 0);
}
else {
errs = 0;
do {
read(STDIN_FILENO,cmd,sizeof(char));
if (errs > 2) {
*cmd = ESCAPE_KEY;
}
if (maptoupper && islower(*cmd)) *cmd = toupper(*cmd);
} while (strchr(keyset,*cmd) == NULL && *cmd != ESCAPE_KEY);
ok = (*cmd != ESCAPE_KEY);
}
move(scr->lines-1,0);
clrtoeol();
move(y_p,x_p);
return ok;
}
int readcommand(char str[], const int mlen)
{
int k = 0;
int n, p;
char c;
do {
refresh();
read(STDIN_FILENO,&c,sizeof(char));
if (c == ESCAPE_KEY) {
str[0] = '\0';
return(0);
}
if (k>0 && (c==BACKSPACE_KEY || c==DELETE_KEY)) {
getyx(stdscr,n,p);
mvdelch(n,--p);
k--;
}
else {
addch(c);
str[k++] = c;
}
} while (c!=RETURN_KEY && c!=NEWLINE_KEY && k<mlen);
if (c==RETURN_KEY || c==NEWLINE_KEY) k--;
str[k] = '\0';
return(k);
}
int save_file(const char *filename, const MODE_T mode, posstruct *txt,
const boolean noclobber, const screenstruct *scr,
tlistetyp **tliste, const U_INT showmsgtime,
const confrecordtyp *confrecord)
{
int k, fp=-1;
char *sp, path[PATH_MAX+2];
boolean err = FALSE, newfile = FALSE, samefile = FALSE;
if (! txt->unsaved) {
showcmdlmsg("File is already saved",showmsgtime,scr);
return 0;
}
if (access(filename,W_OK) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","save_file",
"File is not writeable.\nYou may save in a new file.");
do {
newfile = getcmd_on_prompt(path,PATH_MAX,"Enter new filename:",NULL,
FALSE,scr);
if (newfile) {
if ((fp=open(path,O_WRONLY|O_CREAT|O_EXCL,mode)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","save_file",
"open %s: %m",path);
err = TRUE;
}
else {
err = FALSE;
}
}
} while (err && newfile);
err = ! newfile;
}
else {
strcpy(path,filename);
strcat(path,"~");
if (copyfile(filename,path,noclobber,confrecord) < 0) {
if (getcmd_on_prompt(path,1,"delete file befor save <Y,N> ?","YJN",
TRUE,scr)) {
if (*path == 'Y' || *path == 'J') {
strcpy(path,filename);
samefile = TRUE;
}
}
err = ! samefile;
}
if (!err && (fp=open(path,O_WRONLY|O_TRUNC)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","save_file",
"open %s: %m",path);
err = TRUE;
}
}
for (k=0; k<txt->a_zeilen && !err; k++) {
if (readliste(tliste,FALSE,k,TL_BLOCKLEN,&sp,confrecord) < 0) {
err = TRUE;
}
else {
if (writen(fp,sp,strlen(sp)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","save_file",
"write %s: %m",path);
err = TRUE;
}
}
}
if (close(fp) < 0 && !err) {
errormsg(E_USER,confrecord,"edit","save_file","close %s: %m",path);
err = TRUE;
}
if (! newfile && ! samefile && ! err) {
if (rename(path,filename) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","save_file",
"rename %s to %s: %m",path,filename);
err = TRUE;
}
}
if (err) {
showcmdlmsg("SAVE FAILED",showmsgtime,scr);
ringbell();
}
else {
showcmdlmsg("File saved",showmsgtime,scr);
txt->unsaved = FALSE;
}
if (err) return -1;
return 0;
}
int copyfile(const char *from, const char *to, const boolean noclobber,
const confrecordtyp *confrecord)
{
int from_fp, to_fp;
SSIZE_T nr;
char dir[PATH_MAX], buf[8192];
boolean err = FALSE;
pathnamedir(to,dir);
if (access(dir,W_OK) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","copyfile",
"you have no write permittion in directory %s",dir);
return -1;
}
if (noclobber) {
if ((to_fp=open(to,O_WRONLY|O_CREAT|O_EXCL,0600)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","copyfile","open %s: %m",to);
return -1;
}
}
else {
if ((to_fp=open(to,O_WRONLY|O_CREAT,0600)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","copyfile","open %s: %m",to);
return -1;
}
}
#ifdef USE_FLOCK
flock(to_fp,LOCK_EX|LOCK_NB);
#endif
if ((from_fp=open(from,O_RDONLY)) < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","copyfile","open %s: %m",from);
#ifdef USE_FLOCK
flock(to_fp,LOCK_UN);
#endif
close(to_fp);
unlink(to);
return -1;
}
else {
while (! err && (nr=readn(from_fp,buf,8192)) > 0) {
if (writen(to_fp,buf,nr) != nr) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","copyfile",
"write %s: %m",to);
err = TRUE;
}
}
if (! err && nr < 0) {
errormsg(E_LOGFILE|E_USER,confrecord,"edit","copyfile",
"read %s: %m",from);
err = TRUE;
}
}
close(from_fp);
#ifdef USE_FLOCK
flock(to_fp,LOCK_UN);
#endif
close(to_fp);
if (err) return -1;
return 0;
}
void showcmdlmsg(const char *msg, const U_INT showmsgtime,
const screenstruct *scr)
{
int x_p, y_p;
if (showmsgtime == 0) return;
getyx(stdscr,y_p,x_p);
move(scr->lines-1,0);
clrtoeol();
standout();
addstr(msg);
standend();
refresh();
sleep(showmsgtime);
move(scr->lines-1,0);
clrtoeol();
move(y_p,x_p);
return;
}
int tty_editset(int fd, struct termios *save_edit_termios,
tty_editstateenum *ttyeditstate)
{
struct termios buf;
if (tcgetattr(fd, save_edit_termios) < 0) {
return -1;
}
buf = *save_edit_termios;
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
buf.c_cflag &= ~(CSIZE | PARENB);
buf.c_cflag |= CS8;
buf.c_cc[VMIN] = 1;
buf.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSAFLUSH, &buf) < 0) {
return -1;
}
*ttyeditstate = TTY_EDIT_SET;
return 0;
}
int tty_editreset(int fd, struct termios *save_edit_termios,
tty_editstateenum *ttyeditstate)
{
if (*ttyeditstate == TTY_EDIT_RESET) {
return 0;
}
if (tcsetattr(fd, TCSAFLUSH, save_edit_termios) < 0) {
return -1;
}
*ttyeditstate = TTY_EDIT_RESET;
return 0;
}
int waitread(const int fd, char *buf, const SIZE_T mlen, const int wtime)
{
SIZE_T len;
struct termios termst, termbuf;
if (tcgetattr(fd, &termbuf) < 0) {
return -1;
}
termst = termbuf;
termst.c_cc[VMIN] = 0;
termst.c_cc[VTIME] = wtime;
if (tcsetattr(fd, TCSANOW, &termst) < 0) {
return -1;
}
len = read(fd, buf, mlen);
if (tcsetattr(fd, TCSANOW, &termbuf) < 0) {
return -1;
}
return len;
}
#ifndef CUSTOM_EDITCMDLINE
void showhelp(const screenstruct *scr, const confrecordtyp *confrecord)
{
int x_p, y_p;
char cmd[81];
const char *keyset = "LM";
const char *prompt = "help on command-line [L] or on cursor-movement [M] ?";
const char *cmd_msg = "\
[S]ave : save current state in file\n\
[G]oto : goto line, line no will be asked for\n\
[Q]uit : save current state in file and quit editor\n\
[A]bort : quit editor without saving in file\n\
[C]mdline_off : switch command-line off. It can be switched on by\n\
pressing CTRL-X or Escape\n";
const char *cur_msg = "\
Besides terminal depended cursor-key movement:\n\
cursor-left : CTRL-B\n\
cursor-right : CTRL-F\n\
cursor-up : CTRL-P\n\
cursor-down : CTRL-N\n\
cursor to line start: CTRL-A\n\
cursor to line end : CTRL-E\n\
page-up : CTRL-V\n\
page-down : CTRL-W or ESC-v\n\
delete char left from cursor: DEL or Backspace\n\
clear (kill) line: CTRL-K\n\
redraw screen: CTLR-R";
getyx(stdscr,y_p,x_p);
if (getcmd_on_prompt(cmd,80,prompt,keyset,TRUE,scr)) {
switch (*cmd) {
case 'L':
windowtext(cmd_msg," EDIT: ",0,confrecord);
break;
case 'M':
windowtext(cur_msg," EDIT: ",0,confrecord);
break;
}
}
move(y_p,x_p);
return;
}
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.