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.