ftp.nice.ch/pub/next/unix/communication/ft_bbs.1.0.s.tar.gz#/ft_bbs-1.0/edit.c

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.