Subversion Repositories SvarDOS

Rev

Rev 1565 | Rev 1572 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1565 Rev 1568
1
/* Sved, the SvarDOS editor
1
/* Sved, the SvarDOS editor
2
 *
2
 *
3
 * Copyright (C) 2023 Mateusz Viste
3
 * Copyright (C) 2023 Mateusz Viste
4
 *
4
 *
5
 * Sved is released under the terms of the MIT license.
5
 * Sved is released under the terms of the MIT license.
6
 *
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to
8
 * of this software and associated documentation files (the "Software"), to
9
 * deal in the Software without restriction, including without limitation the
9
 * deal in the Software without restriction, including without limitation the
10
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11
 * sell copies of the Software, and to permit persons to whom the Software is
11
 * sell copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
12
 * furnished to do so, subject to the following conditions:
13
 *
13
 *
14
 * The above copyright notice and this permission notice shall be included in
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
15
 * all copies or substantial portions of the Software.
16
 *
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23
 * IN THE SOFTWARE.
23
 * IN THE SOFTWARE.
24
 */
24
 */
25
 
25
 
26
#include <i86.h> /* MK_FP() */
26
#include <i86.h> /* MK_FP() */
27
 
27
 
28
#include "libc.h"
28
#include "libc.h"
29
 
29
 
30
#include "mdr\bios.h"
30
#include "mdr\bios.h"
31
#include "mdr\cout.h"
31
#include "mdr\cout.h"
32
#include "mdr\dos.h"
32
#include "mdr\dos.h"
33
 
33
 
34
#include "svarlang\svarlang.h"
34
#include "svarlang\svarlang.h"
35
 
35
 
36
 
36
 
37
#define PVER "2023.5"
37
#define PVER "2023.5"
38
#define PDATE "2023"
38
#define PDATE "2023"
39
 
39
 
40
/*****************************************************************************
40
/*****************************************************************************
41
 * global variables and definitions                                          *
41
 * global variables and definitions                                          *
42
 *****************************************************************************/
42
 *****************************************************************************/
43
 
43
 
44
/* preload the mono scheme (to be overloaded at runtime if color adapter present) */
44
/* preload the mono scheme (to be overloaded at runtime if color adapter present) */
45
static unsigned char SCHEME_TEXT   = 0x07,
45
static unsigned char SCHEME_TEXT   = 0x07,
46
                     SCHEME_MENU   = 0x70,
46
                     SCHEME_MENU   = 0x70,
47
                     SCHEME_MENU_CUR= 0x0f,
47
                     SCHEME_MENU_CUR= 0x0f,
48
                     SCHEME_MENU_SEL= 0x00,
48
                     SCHEME_MENU_SEL= 0x00,
49
                     SCHEME_STBAR1 = 0x70,
49
                     SCHEME_STBAR1 = 0x70,
50
                     SCHEME_STBAR2 = 0x70, /* greyed out information */
50
                     SCHEME_STBAR2 = 0x70, /* greyed out information */
51
                     SCHEME_STBAR3 = 0x70, /* query */
51
                     SCHEME_STBAR3 = 0x70, /* query */
52
                     SCHEME_SCROLL = 0x70,
52
                     SCHEME_SCROLL = 0x70,
53
                     SCHEME_MSG    = 0x70,
53
                     SCHEME_MSG    = 0x70,
54
                     SCHEME_ERR    = 0x70;
54
                     SCHEME_ERR    = 0x70;
55
 
55
 
56
static unsigned char screenw, screenh, screenlastrow, screenlastcol;
56
static unsigned char screenw, screenh, screenlastrow, screenlastcol;
57
static unsigned char glob_monomode, glob_tablessmode;
57
static unsigned char glob_monomode, glob_tablessmode;
58
 
58
 
59
static char buff[512]; /* short lived buffer for whatever needed */
59
static char buff[512]; /* short lived buffer for whatever needed */
60
 
60
 
61
static struct {
61
static struct {
62
    unsigned char from;
62
    unsigned char from;
63
    unsigned char to;
63
    unsigned char to;
64
    unsigned char statusbar;
64
    unsigned char statusbar;
65
} uidirty = {0, 0xff, 1}; /* make sure to redraw entire UI at first run */
65
} uidirty = {0, 0xff, 1}; /* make sure to redraw entire UI at first run */
66
 
66
 
67
#define SCROLL_CURSOR 0xB1
67
#define SCROLL_CURSOR 0xB1
68
 
68
 
69
struct line {
69
struct line {
70
  unsigned short len;
70
  unsigned short len;
71
  struct line far *next;
71
  struct line far *next;
72
  struct line far *prev;
72
  struct line far *prev;
73
  char payload[1];
73
  char payload[1];
74
};
74
};
75
 
75
 
76
struct file {
76
struct file {
77
  struct line far *cursor;
77
  struct line far *cursor;
78
  unsigned short xoffset;
78
  unsigned short xoffset;
79
  unsigned short cursorposx;
79
  unsigned short cursorposx;
80
  unsigned short cursorposy;
80
  unsigned short cursorposy;
81
  unsigned short totlines;
81
  unsigned short totlines;
82
  unsigned short curline;
82
  unsigned short curline;
83
  unsigned short curline_prev;
83
  unsigned short curline_prev;
84
  char lfonly;   /* set if line endings are LF (CR/LF otherwise) */
84
  char lfonly;   /* set if line endings are LF (CR/LF otherwise) */
85
  char modflag;  /* non-zero if file has been modified since last save */
85
  char modflag;  /* non-zero if file has been modified since last save */
86
  char modflagprev;
86
  char modflagprev;
87
  char slotid; /* 0..9 */
87
  char slotid; /* 0..9 */
88
  char fname[128];
88
  char fname[128];
89
};
89
};
90
 
90
 
91
 
91
 
92
/*****************************************************************************
92
/*****************************************************************************
93
 * functions                                                                 *
93
 * functions                                                                 *
94
 *****************************************************************************/
94
 *****************************************************************************/
95
 
95
 
96
static struct line far *line_calloc(unsigned short siz) {
96
static struct line far *line_calloc(unsigned short siz) {
97
  struct line far *res;
97
  struct line far *res;
98
  unsigned short seg;
98
  unsigned short seg;
99
 
99
 
100
  seg = mdr_dos_allocmem((sizeof(struct line) + siz + 15) / 16);
100
  seg = mdr_dos_allocmem((sizeof(struct line) + siz + 15) / 16);
101
  if (seg == 0) return(NULL);
101
  if (seg == 0) return(NULL);
102
  res = MK_FP(seg, 0);
102
  res = MK_FP(seg, 0);
103
  res->len = 0;
103
  res->len = 0;
104
  res->next = NULL;
104
  res->next = NULL;
105
  res->prev = NULL;
105
  res->prev = NULL;
106
 
106
 
107
  return(res);
107
  return(res);
108
}
108
}
109
 
109
 
110
 
110
 
111
static void line_free(struct line far *ptr) {
111
static void line_free(struct line far *ptr) {
112
  _dos_freemem(FP_SEG(ptr));
112
  _dos_freemem(FP_SEG(ptr));
113
}
113
}
114
 
114
 
115
 
115
 
116
static int curline_resize(struct file *db, unsigned short newsiz) {
116
static int curline_resize(struct file *db, unsigned short newsiz) {
117
  struct line far *newptr;
117
  struct line far *newptr;
118
 
118
 
119
  /* try resizing the block (much faster) */
119
  /* try resizing the block (much faster) */
120
  if (mdr_dos_resizeblock((sizeof(struct line) + newsiz + 15) / 16, FP_SEG(db->cursor)) == 0) return(0);
120
  if (mdr_dos_resizeblock((sizeof(struct line) + newsiz + 15) / 16, FP_SEG(db->cursor)) == 0) return(0);
121
 
121
 
122
  /* create a new block and copy data over */
122
  /* create a new block and copy data over */
123
  newptr = line_calloc(newsiz);
123
  newptr = line_calloc(newsiz);
124
  if (newptr == NULL) return(-1);
124
  if (newptr == NULL) return(-1);
125
  _fmemmove(newptr, db->cursor, sizeof(struct line) + db->cursor->len);
125
  fmemmove(newptr, db->cursor, sizeof(struct line) + db->cursor->len);
126
 
126
 
127
  /* rewire the linked list */
127
  /* rewire the linked list */
128
  db->cursor = newptr;
128
  db->cursor = newptr;
129
  if (newptr->next) newptr->next->prev = newptr;
129
  if (newptr->next) newptr->next->prev = newptr;
130
  if (newptr->prev) newptr->prev->next = newptr;
130
  if (newptr->prev) newptr->prev->next = newptr;
131
 
131
 
132
  return(0);
132
  return(0);
133
}
133
}
134
 
134
 
135
 
135
 
136
/* adds a new line at cursor position into file linked list and advance cursor
136
/* adds a new line at cursor position into file linked list and advance cursor
137
 * returns non-zero on error */
137
 * returns non-zero on error */
138
static int line_add(struct file *db, const char far *line, unsigned short slen) {
138
static int line_add(struct file *db, const char far *line, unsigned short slen) {
139
  struct line far *l;
139
  struct line far *l;
140
 
140
 
141
  l = line_calloc(slen);
141
  l = line_calloc(slen);
142
  if (l == NULL) return(-1);
142
  if (l == NULL) return(-1);
143
 
143
 
144
  l->prev = db->cursor;
144
  l->prev = db->cursor;
145
  if (db->cursor) {
145
  if (db->cursor) {
146
    l->next = db->cursor->next;
146
    l->next = db->cursor->next;
147
    db->cursor->next = l;
147
    db->cursor->next = l;
148
    l->next->prev = l;
148
    l->next->prev = l;
149
  }
149
  }
150
  db->cursor = l;
150
  db->cursor = l;
151
  if (slen > 0) {
151
  if (slen > 0) {
152
    _fmemmove(l->payload, line, slen);
152
    fmemmove(l->payload, line, slen);
153
    l->len = slen;
153
    l->len = slen;
154
  }
154
  }
155
 
155
 
156
  db->totlines += 1;
156
  db->totlines += 1;
157
  db->curline += 1;
157
  db->curline += 1;
158
 
158
 
159
  return(0);
159
  return(0);
160
}
160
}
161
 
161
 
162
 
162
 
163
static void ui_getstring(const char *query, char *s, unsigned short maxlen) {
163
static void ui_getstring(const char *query, char *s, unsigned short maxlen) {
164
  unsigned short len = 0;
164
  unsigned short len = 0;
165
  unsigned char x;
165
  unsigned char x;
166
  int k;
166
  int k;
167
 
167
 
168
  if (maxlen == 0) return;
168
  if (maxlen == 0) return;
169
  maxlen--; /* make room for the nul terminator */
169
  maxlen--; /* make room for the nul terminator */
170
 
170
 
171
  /* print query string */
171
  /* print query string */
172
  x = mdr_cout_str(screenlastrow, 0, query, SCHEME_STBAR3, 40);
172
  x = mdr_cout_str(screenlastrow, 0, query, SCHEME_STBAR3, 40);
173
  mdr_cout_char_rep(screenlastrow, x++, ' ', SCHEME_STBAR3, screenw - x);
173
  mdr_cout_char_rep(screenlastrow, x++, ' ', SCHEME_STBAR3, screenw - x);
174
 
174
 
175
  for (;;) {
175
  for (;;) {
176
    mdr_cout_locate(screenlastrow, x + len);
176
    mdr_cout_locate(screenlastrow, x + len);
177
    k = mdr_dos_getkey2();
177
    k = mdr_dos_getkey2();
178
 
178
 
179
    switch (k) {
179
    switch (k) {
180
      case 0x1b: /* ESC */
180
      case 0x1b: /* ESC */
181
        s[0] = 0;
181
        s[0] = 0;
182
        return;
182
        return;
183
      case '\r':
183
      case '\r':
184
        s[len] = 0;
184
        s[len] = 0;
185
        return;
185
        return;
186
      case 0x08: /* BKSPC */
186
      case 0x08: /* BKSPC */
187
        if (len > 0) {
187
        if (len > 0) {
188
          len--;
188
          len--;
189
          mdr_cout_char(screenlastrow, x + len, ' ', SCHEME_STBAR3);
189
          mdr_cout_char(screenlastrow, x + len, ' ', SCHEME_STBAR3);
190
        }
190
        }
191
        break;
191
        break;
192
      default:
192
      default:
193
        if ((k <= 0xff) && (k >= ' ') && (len < maxlen)) {
193
        if ((k <= 0xff) && (k >= ' ') && (len < maxlen)) {
194
          mdr_cout_char(screenlastrow, x + len, k, SCHEME_STBAR3);
194
          mdr_cout_char(screenlastrow, x + len, k, SCHEME_STBAR3);
195
          s[len++] = k;
195
          s[len++] = k;
196
        }
196
        }
197
    }
197
    }
198
  }
198
  }
199
 
199
 
200
}
200
}
201
 
201
 
202
 
202
 
203
/* append a nul-terminated string to line at cursor position */
203
/* append a nul-terminated string to line at cursor position */
204
static int line_append(struct file *f, const char *buf, unsigned short len) {
204
static int line_append(struct file *f, const char *buf, unsigned short len) {
205
  if (sizeof(struct line) + f->cursor->len + len < len) goto ERR; /* overflow check */
205
  if (sizeof(struct line) + f->cursor->len + len < len) goto ERR; /* overflow check */
206
  if (curline_resize(f, f->cursor->len + len) != 0) goto ERR;
206
  if (curline_resize(f, f->cursor->len + len) != 0) goto ERR;
207
 
207
 
208
  _fmemmove(f->cursor->payload + f->cursor->len, buf, len);
208
  fmemmove(f->cursor->payload + f->cursor->len, buf, len);
209
  f->cursor->len += len;
209
  f->cursor->len += len;
210
 
210
 
211
  return(0);
211
  return(0);
212
  ERR:
212
  ERR:
213
  return(-1);
213
  return(-1);
214
}
214
}
215
 
215
 
216
 
216
 
217
static void db_rewind(struct file *db) {
217
static void db_rewind(struct file *db) {
218
  if (db->cursor == NULL) return;
218
  if (db->cursor == NULL) return;
219
  while (db->cursor->prev) db->cursor = db->cursor->prev;
219
  while (db->cursor->prev) db->cursor = db->cursor->prev;
220
  db->curline = 0;
220
  db->curline = 0;
221
}
221
}
222
 
222
 
223
 
223
 
224
/* saves db file, resets db->modflag on success and overwrites the filename
224
/* saves db file, resets db->modflag on success and overwrites the filename
225
 * field if saveas is not NULL */
225
 * field if saveas is not NULL */
226
static int savefile(struct file *db, const char *saveas) {
226
static int savefile(struct file *db, const char *saveas) {
227
  int fd = 0;
227
  int fd = 0;
228
  const struct line far *l;
228
  const struct line far *l;
229
  unsigned short bytes;
229
  unsigned short bytes;
230
  unsigned char eollen = 2;
230
  unsigned char eollen = 2;
231
  const unsigned char *eolbuf = "\r\n";
231
  const unsigned char *eolbuf = "\r\n";
232
  int errflag = 0;
232
  int errflag = 0;
233
 
233
 
234
  /* if filename not overloaded then use the fname in db */
234
  /* if filename not overloaded then use the fname in db */
235
  if (saveas == NULL) saveas = db->fname;
235
  if (saveas == NULL) saveas = db->fname;
236
 
236
 
237
  _asm {
237
  _asm {
238
    push ax
238
    push ax
239
    push cx
239
    push cx
240
    push dx
240
    push dx
241
 
241
 
242
    mov ah, 0x3C    /* create or truncate file */
242
    mov ah, 0x3C    /* create or truncate file */
243
    xor cx, cx      /* file attributes */
243
    xor cx, cx      /* file attributes */
244
    mov dx, saveas  /* works only in SMALL/TINY mode */
244
    mov dx, saveas  /* works only in SMALL/TINY mode */
245
    int 0x21
245
    int 0x21
246
    jnc DONE
246
    jnc DONE
247
    mov errflag, ax
247
    mov errflag, ax
248
    DONE:
248
    DONE:
249
    mov fd, ax
249
    mov fd, ax
250
 
250
 
251
    pop dx
251
    pop dx
252
    pop cx
252
    pop cx
253
    pop ax
253
    pop ax
254
  }
254
  }
255
 
255
 
256
  if (errflag != 0) return(-1);
256
  if (errflag != 0) return(-1);
257
 
257
 
258
  l = db->cursor;
258
  l = db->cursor;
259
  while (l->prev) l = l->prev;
259
  while (l->prev) l = l->prev;
260
 
260
 
261
  /* preset line terminators */
261
  /* preset line terminators */
262
  if (db->lfonly) {
262
  if (db->lfonly) {
263
    eolbuf++;
263
    eolbuf++;
264
    eollen--;
264
    eollen--;
265
  }
265
  }
266
 
266
 
267
  while (l) {
267
  while (l) {
268
    /* do not write the last empty line, it is only useful for edition */
268
    /* do not write the last empty line, it is only useful for edition */
269
    if (l->len != 0) {
269
    if (l->len != 0) {
270
      errflag |= mdr_dos_write(fd, l->payload, l->len, &bytes);
270
      errflag |= mdr_dos_write(fd, l->payload, l->len, &bytes);
271
    } else if (l->next == NULL) {
271
    } else if (l->next == NULL) {
272
      break;
272
      break;
273
    }
273
    }
274
    errflag |= mdr_dos_write(fd, eolbuf, eollen, &bytes);
274
    errflag |= mdr_dos_write(fd, eolbuf, eollen, &bytes);
275
    l = l->next;
275
    l = l->next;
276
  }
276
  }
277
 
277
 
278
  errflag |= mdr_dos_fclose(fd);
278
  errflag |= mdr_dos_fclose(fd);
279
 
279
 
280
  /* did it all work? */
280
  /* did it all work? */
281
  if (errflag == 0) {
281
  if (errflag == 0) {
282
    db->modflag = 0;
282
    db->modflag = 0;
283
    if (saveas != db->fname) mdr_dos_truename(db->fname, saveas);
283
    if (saveas != db->fname) mdr_dos_truename(db->fname, saveas);
284
  }
284
  }
285
 
285
 
286
  return(errflag);
286
  return(errflag);
287
}
287
}
288
 
288
 
289
 
289
 
290
static void ui_statusbar(const struct file *db) {
290
static void ui_statusbar(const struct file *db) {
291
  const char *s = svarlang_strid(0); /* ESC=MENU */
291
  const char *s = svarlang_strid(0); /* ESC=MENU */
292
  unsigned short helpcol = screenw - strlen(s);
292
  unsigned short helpcol = screenw - strlen(s);
293
  unsigned short col;
293
  unsigned short col;
294
 
294
 
295
  /* slot number (guaranteed to be 0-9) */
295
  /* slot number (guaranteed to be 0-9) */
296
  {
296
  {
297
    char slot[4] = "#00";
297
    char slot[4] = "#00";
298
    if (db->slotid == 9) {
298
    if (db->slotid == 9) {
299
      slot[1] = '1';
299
      slot[1] = '1';
300
    } else {
300
    } else {
301
      slot[2] += db->slotid + 1;
301
      slot[2] += db->slotid + 1;
302
    }
302
    }
303
    mdr_cout_str(screenlastrow, 0, slot, SCHEME_STBAR2, 3);
303
    mdr_cout_str(screenlastrow, 0, slot, SCHEME_STBAR2, 3);
304
  }
304
  }
305
 
305
 
306
  /* fill rest of status bar with background */
306
  /* fill rest of status bar with background */
307
  mdr_cout_char_rep(screenlastrow, 3, ' ', SCHEME_STBAR1, helpcol - 3);
307
  mdr_cout_char_rep(screenlastrow, 3, ' ', SCHEME_STBAR1, helpcol - 3);
308
 
308
 
309
  /* eol type */
309
  /* eol type */
310
  {
310
  {
311
    const char *eoltype = "CRLF";
311
    const char *eoltype = "CRLF";
312
    if (db->lfonly) eoltype += 2;
312
    if (db->lfonly) eoltype += 2;
313
    mdr_cout_str(screenlastrow, helpcol - 5, eoltype, SCHEME_STBAR1, 5);
313
    mdr_cout_str(screenlastrow, helpcol - 5, eoltype, SCHEME_STBAR1, 5);
314
  }
314
  }
315
 
315
 
316
  /* line numbers */
316
  /* line numbers */
317
  {
317
  {
318
    unsigned short x;
318
    unsigned short x;
319
    unsigned char count = 0;
319
    unsigned char count = 0;
320
    col = helpcol - 7;
320
    col = helpcol - 7;
321
 
321
 
322
    x = db->totlines;
322
    x = db->totlines;
323
    AGAIN:
323
    AGAIN:
324
    do {
324
    do {
325
      mdr_cout_char(screenlastrow, col--, '0' + (x % 10), SCHEME_STBAR1);
325
      mdr_cout_char(screenlastrow, col--, '0' + (x % 10), SCHEME_STBAR1);
326
      x /= 10;
326
      x /= 10;
327
    } while (x);
327
    } while (x);
328
    /* redo same exercise, but printing the current line now */
328
    /* redo same exercise, but printing the current line now */
329
    if (count == 0) {
329
    if (count == 0) {
330
      count = 1;
330
      count = 1;
331
      mdr_cout_char(screenlastrow, col--, '/', SCHEME_STBAR1);
331
      mdr_cout_char(screenlastrow, col--, '/', SCHEME_STBAR1);
332
      x = 1 + db->curline;
332
      x = 1 + db->curline;
333
      goto AGAIN;
333
      goto AGAIN;
334
    }
334
    }
335
  }
335
  }
336
 
336
 
337
  /* filename and modflag */
337
  /* filename and modflag */
338
  {
338
  {
339
    const char *fn;
339
    const char *fn;
340
    unsigned short x;
340
    unsigned short x;
341
    unsigned short maxfnlen = col - 6;
341
    unsigned short maxfnlen = col - 6;
342
    if (db->fname[0] == 0) {
342
    if (db->fname[0] == 0) {
343
      fn = svarlang_str(0, 1); /* "UNTITLED" */
343
      fn = svarlang_str(0, 1); /* "UNTITLED" */
344
    } else {
344
    } else {
345
      /* display filename up to maxfnlen chars */
345
      /* display filename up to maxfnlen chars */
346
      fn = db->fname;
346
      fn = db->fname;
347
      x = strlen(fn);
347
      x = strlen(fn);
348
      if (x > maxfnlen) fn += x - maxfnlen;
348
      if (x > maxfnlen) fn += x - maxfnlen;
349
    }
349
    }
350
    x = mdr_cout_str(screenlastrow, 4, fn, SCHEME_STBAR1, maxfnlen);
350
    x = mdr_cout_str(screenlastrow, 4, fn, SCHEME_STBAR1, maxfnlen);
351
    if (db->modflag) mdr_cout_char(screenlastrow, 5 + x, '!', SCHEME_STBAR2);
351
    if (db->modflag) mdr_cout_char(screenlastrow, 5 + x, '!', SCHEME_STBAR2);
352
  }
352
  }
353
 
353
 
354
  mdr_cout_str(screenlastrow, helpcol, s, SCHEME_STBAR2, 40);
354
  mdr_cout_str(screenlastrow, helpcol, s, SCHEME_STBAR2, 40);
355
}
355
}
356
 
356
 
357
 
357
 
358
static void ui_msg(unsigned short msgid1, unsigned short msgid2, unsigned short msgid3, unsigned char attr) {
358
static void ui_msg(unsigned short msgid1, unsigned short msgid2, unsigned short msgid3, unsigned char attr) {
359
  unsigned short x, y, maxmsglen, i;
359
  unsigned short x, y, maxmsglen, i;
360
  unsigned short msgcount = 1;
360
  unsigned short msgcount = 1;
361
  const char *msg[3];
361
  const char *msg[3];
362
 
362
 
363
  msg[0] = svarlang_strid(msgid1);
363
  msg[0] = svarlang_strid(msgid1);
364
 
364
 
365
  if (msgid2 != 0) {
365
  if (msgid2 != 0) {
366
    msgcount = 2;
366
    msgcount = 2;
367
    msg[1] = svarlang_strid(msgid2);
367
    msg[1] = svarlang_strid(msgid2);
368
  }
368
  }
369
  if (msgid3 != 0) {
369
  if (msgid3 != 0) {
370
    msgcount = 3;
370
    msgcount = 3;
371
    msg[2] = svarlang_strid(msgid3);
371
    msg[2] = svarlang_strid(msgid3);
372
  }
372
  }
373
 
373
 
374
  /* find longest msg */
374
  /* find longest msg */
375
  maxmsglen = 0;
375
  maxmsglen = 0;
376
  for (i = 0; i < msgcount; i++) {
376
  for (i = 0; i < msgcount; i++) {
377
    y = strlen(msg[i]);
377
    y = strlen(msg[i]);
378
    if (y > maxmsglen) maxmsglen = y;
378
    if (y > maxmsglen) maxmsglen = y;
379
  }
379
  }
380
 
380
 
381
  y = (screenh - 6) >> 1;
381
  y = (screenh - 6) >> 1;
382
  x = (screenw - maxmsglen - 3) >> 1;
382
  x = (screenw - maxmsglen - 3) >> 1;
383
  for (i = y+1+msgcount; i >= y; i--) mdr_cout_char_rep(i, x, ' ', attr, maxmsglen + 2);
383
  for (i = y+1+msgcount; i >= y; i--) mdr_cout_char_rep(i, x, ' ', attr, maxmsglen + 2);
384
  x++;
384
  x++;
385
 
385
 
386
  for (i = 0; i < msgcount; i++) {
386
  for (i = 0; i < msgcount; i++) {
387
    mdr_cout_str(y+1+i, x, msg[i], attr, maxmsglen);
387
    mdr_cout_str(y+1+i, x, msg[i], attr, maxmsglen);
388
  }
388
  }
389
 
389
 
390
  if (uidirty.from > y) uidirty.from = y;
390
  if (uidirty.from > y) uidirty.from = y;
391
  if (uidirty.to < y+4) uidirty.to = y+4;
391
  if (uidirty.to < y+4) uidirty.to = y+4;
392
}
392
}
393
 
393
 
394
 
394
 
395
/* returns 0 if operation may proceed, non-zero to cancel */
395
/* returns 0 if operation may proceed, non-zero to cancel */
396
static unsigned char ui_confirm_if_unsaved(struct file *db) {
396
static unsigned char ui_confirm_if_unsaved(struct file *db) {
397
  int k;
397
  int k;
398
 
398
 
399
  if (db->modflag == 0) return(0);
399
  if (db->modflag == 0) return(0);
400
 
400
 
401
  mdr_cout_cursor_hide();
401
  mdr_cout_cursor_hide();
402
 
402
 
403
  /* if file has been modified then ask for confirmation:
403
  /* if file has been modified then ask for confirmation:
404
   * ENTER        : agree to data loss
404
   * ENTER        : agree to data loss
405
   * SPACE        : SAVE file before quit (only if valid filename present)
405
   * SPACE        : SAVE file before quit (only if valid filename present)
406
   * anything else: ABORT */
406
   * anything else: ABORT */
407
  ui_msg(4, 5, (db->fname[0])?9:8, SCHEME_MSG);
407
  ui_msg(4, 5, (db->fname[0])?9:8, SCHEME_MSG);
408
 
408
 
409
  k = mdr_dos_getkey2();
409
  k = mdr_dos_getkey2();
410
  mdr_cout_cursor_show();
410
  mdr_cout_cursor_show();
411
 
411
 
412
  /* ENTER = agree to loose unsaved data */
412
  /* ENTER = agree to loose unsaved data */
413
  if (k == '\r') return(0);
413
  if (k == '\r') return(0);
414
 
414
 
415
  /* SPACE = save file and continue */
415
  /* SPACE = save file and continue */
416
  if ((k == ' ') && (db->fname[0] != 0) && (savefile(db, NULL) == 0)) return(0);
416
  if ((k == ' ') && (db->fname[0] != 0) && (savefile(db, NULL) == 0)) return(0);
417
 
417
 
418
  /* any other key = cancel operation */
418
  /* any other key = cancel operation */
419
  return(1);
419
  return(1);
420
}
420
}
421
 
421
 
422
 
422
 
423
static void ui_refresh(const struct file *db) {
423
static void ui_refresh(const struct file *db) {
424
  unsigned char x;
424
  unsigned char x;
425
  const struct line far *l;
425
  const struct line far *l;
426
  unsigned char y = db->cursorposy;
426
  unsigned char y = db->cursorposy;
427
 
427
 
428
  /* quit early if nothing to refresh */
428
  /* quit early if nothing to refresh */
429
  if (uidirty.from == 0xff) return;
429
  if (uidirty.from == 0xff) return;
430
 
430
 
431
#ifdef DBG_REFRESH
431
#ifdef DBG_REFRESH
432
  static char m = 'a';
432
  static char m = 'a';
433
  m++;
433
  m++;
434
  if (m > 'z') m = 'a';
434
  if (m > 'z') m = 'a';
435
#endif
435
#endif
436
 
436
 
437
  /* rewind cursor line to first line that needs redrawing */
437
  /* rewind cursor line to first line that needs redrawing */
438
  for (l = db->cursor; y > uidirty.from; y--) l = l->prev;
438
  for (l = db->cursor; y > uidirty.from; y--) l = l->prev;
439
 
439
 
440
  /* iterate over lines and redraw whatever needs to be redrawn */
440
  /* iterate over lines and redraw whatever needs to be redrawn */
441
  for (; l != NULL; l = l->next, y++) {
441
  for (; l != NULL; l = l->next, y++) {
442
 
442
 
443
    /* skip lines that do not need to be refreshed */
443
    /* skip lines that do not need to be refreshed */
444
    if (y < uidirty.from) continue;
444
    if (y < uidirty.from) continue;
445
    if (y > uidirty.to) break;
445
    if (y > uidirty.to) break;
446
 
446
 
447
    x = 0;
447
    x = 0;
448
    if (db->xoffset < l->len) {
448
    if (db->xoffset < l->len) {
449
      unsigned char i, limit;
449
      unsigned char i, limit;
450
      if (l->len - db->xoffset < screenw) {
450
      if (l->len - db->xoffset < screenw) {
451
        limit = l->len;
451
        limit = l->len;
452
      } else {
452
      } else {
453
        limit = db->xoffset + screenlastcol;
453
        limit = db->xoffset + screenlastcol;
454
      }
454
      }
455
      for (i = db->xoffset; i < limit; i++) mdr_cout_char(y, x++, l->payload[i], SCHEME_TEXT);
455
      for (i = db->xoffset; i < limit; i++) mdr_cout_char(y, x++, l->payload[i], SCHEME_TEXT);
456
    }
456
    }
457
 
457
 
458
    /* write empty spaces until end of line */
458
    /* write empty spaces until end of line */
459
    if (x < screenlastcol) mdr_cout_char_rep(y, x, ' ', SCHEME_TEXT, screenlastcol - x);
459
    if (x < screenlastcol) mdr_cout_char_rep(y, x, ' ', SCHEME_TEXT, screenlastcol - x);
460
 
460
 
461
#ifdef DBG_REFRESH
461
#ifdef DBG_REFRESH
462
    mdr_cout_char(y, 0, m, SCHEME_STBAR1);
462
    mdr_cout_char(y, 0, m, SCHEME_STBAR1);
463
#endif
463
#endif
464
 
464
 
465
    if (y == screenh - 2) break;
465
    if (y == screenh - 2) break;
466
  }
466
  }
467
 
467
 
468
  /* fill all lines below if empty (and they need to be redrawn) */
468
  /* fill all lines below if empty (and they need to be redrawn) */
469
  if (l == NULL) {
469
  if (l == NULL) {
470
    while ((y < screenlastrow) && (y < uidirty.to)) {
470
    while ((y < screenlastrow) && (y < uidirty.to)) {
471
      mdr_cout_char_rep(y++, 0, ' ', SCHEME_TEXT, screenlastcol);
471
      mdr_cout_char_rep(y++, 0, ' ', SCHEME_TEXT, screenlastcol);
472
    }
472
    }
473
  }
473
  }
474
 
474
 
475
  /* scroll bar */
475
  /* scroll bar */
476
  for (y = 0; y < screenlastrow; y++) {
476
  for (y = 0; y < screenlastrow; y++) {
477
    mdr_cout_char(y, screenlastcol, SCROLL_CURSOR, SCHEME_SCROLL);
477
    mdr_cout_char(y, screenlastcol, SCROLL_CURSOR, SCHEME_SCROLL);
478
  }
478
  }
479
 
479
 
480
  /* scroll cursor */
480
  /* scroll cursor */
481
  if (db->totlines >= screenh) {
481
  if (db->totlines >= screenh) {
482
    unsigned short topline = db->curline - db->cursorposy;
482
    unsigned short topline = db->curline - db->cursorposy;
483
    unsigned short col;
483
    unsigned short col;
484
    unsigned short totlines = db->totlines - screenh + 1;
484
    unsigned short totlines = db->totlines - screenh + 1;
485
    if (db->totlines - screenh > screenh) {
485
    if (db->totlines - screenh > screenh) {
486
      col = topline / (totlines / screenlastrow);
486
      col = topline / (totlines / screenlastrow);
487
    } else {
487
    } else {
488
      col = topline * screenlastrow / totlines;
488
      col = topline * screenlastrow / totlines;
489
    }
489
    }
490
    if (col >= screenlastrow) col = screenh - 2;
490
    if (col >= screenlastrow) col = screenh - 2;
491
    mdr_cout_char(col, screenlastcol, ' ', SCHEME_SCROLL);
491
    mdr_cout_char(col, screenlastcol, ' ', SCHEME_SCROLL);
492
  }
492
  }
493
 
493
 
494
  /* clear out the dirty flag */
494
  /* clear out the dirty flag */
495
  uidirty.from = 0xff;
495
  uidirty.from = 0xff;
496
}
496
}
497
 
497
 
498
 
498
 
499
static void check_cursor_not_after_eol(struct file *db) {
499
static void check_cursor_not_after_eol(struct file *db) {
500
  if (db->xoffset + db->cursorposx <= db->cursor->len) return;
500
  if (db->xoffset + db->cursorposx <= db->cursor->len) return;
501
 
501
 
502
  if (db->cursor->len < db->xoffset) {
502
  if (db->cursor->len < db->xoffset) {
503
    db->cursorposx = 0;
503
    db->cursorposx = 0;
504
    db->xoffset = db->cursor->len;
504
    db->xoffset = db->cursor->len;
505
    uidirty.from = 0;
505
    uidirty.from = 0;
506
    uidirty.to = 0xff;
506
    uidirty.to = 0xff;
507
  } else {
507
  } else {
508
    db->cursorposx = db->cursor->len - db->xoffset;
508
    db->cursorposx = db->cursor->len - db->xoffset;
509
  }
509
  }
510
}
510
}
511
 
511
 
512
 
512
 
513
static void cursor_up(struct file *db) {
513
static void cursor_up(struct file *db) {
514
  if (db->cursor->prev == NULL) return;
514
  if (db->cursor->prev == NULL) return;
515
 
515
 
516
  db->curline -= 1;
516
  db->curline -= 1;
517
  db->cursor = db->cursor->prev;
517
  db->cursor = db->cursor->prev;
518
  if (db->cursorposy == 0) {
518
  if (db->cursorposy == 0) {
519
    uidirty.from = 0;
519
    uidirty.from = 0;
520
    uidirty.to = 0xff;
520
    uidirty.to = 0xff;
521
  } else {
521
  } else {
522
    db->cursorposy -= 1;
522
    db->cursorposy -= 1;
523
  }
523
  }
524
}
524
}
525
 
525
 
526
 
526
 
527
static void cursor_eol(struct file *db) {
527
static void cursor_eol(struct file *db) {
528
  /* adjust xoffset to make sure eol is visible on screen */
528
  /* adjust xoffset to make sure eol is visible on screen */
529
  if (db->xoffset > db->cursor->len) {
529
  if (db->xoffset > db->cursor->len) {
530
    db->xoffset = db->cursor->len - 1;
530
    db->xoffset = db->cursor->len - 1;
531
    uidirty.from = 0;
531
    uidirty.from = 0;
532
    uidirty.to = 0xff;
532
    uidirty.to = 0xff;
533
  }
533
  }
534
 
534
 
535
  if (db->xoffset + screenlastcol <= db->cursor->len) {
535
  if (db->xoffset + screenlastcol <= db->cursor->len) {
536
    db->xoffset = db->cursor->len - screenw + 2;
536
    db->xoffset = db->cursor->len - screenw + 2;
537
    uidirty.from = 0;
537
    uidirty.from = 0;
538
    uidirty.to = 0xff;
538
    uidirty.to = 0xff;
539
  }
539
  }
540
  db->cursorposx = db->cursor->len - db->xoffset;
540
  db->cursorposx = db->cursor->len - db->xoffset;
541
}
541
}
542
 
542
 
543
 
543
 
544
static void cursor_down(struct file *db) {
544
static void cursor_down(struct file *db) {
545
  if (db->cursor->next == NULL) return;
545
  if (db->cursor->next == NULL) return;
546
 
546
 
547
  db->curline += 1;
547
  db->curline += 1;
548
  db->cursor = db->cursor->next;
548
  db->cursor = db->cursor->next;
549
  if (db->cursorposy < screenh - 2) {
549
  if (db->cursorposy < screenh - 2) {
550
    db->cursorposy += 1;
550
    db->cursorposy += 1;
551
  } else {
551
  } else {
552
    uidirty.from = 0;
552
    uidirty.from = 0;
553
    uidirty.to = 0xff;
553
    uidirty.to = 0xff;
554
  }
554
  }
555
}
555
}
556
 
556
 
557
 
557
 
558
static void cursor_left(struct file *db) {
558
static void cursor_left(struct file *db) {
559
  if (db->cursorposx > 0) {
559
  if (db->cursorposx > 0) {
560
    db->cursorposx -= 1;
560
    db->cursorposx -= 1;
561
  } else if (db->xoffset > 0) {
561
  } else if (db->xoffset > 0) {
562
    db->xoffset -= 1;
562
    db->xoffset -= 1;
563
    uidirty.from = 0;
563
    uidirty.from = 0;
564
    uidirty.to = 0xff;
564
    uidirty.to = 0xff;
565
  } else if (db->cursor->prev != NULL) { /* jump to end of line above */
565
  } else if (db->cursor->prev != NULL) { /* jump to end of line above */
566
    cursor_up(db);
566
    cursor_up(db);
567
    cursor_eol(db);
567
    cursor_eol(db);
568
  }
568
  }
569
}
569
}
570
 
570
 
571
 
571
 
572
static void cursor_home(struct file *db) {
572
static void cursor_home(struct file *db) {
573
  db->cursorposx = 0;
573
  db->cursorposx = 0;
574
  if (db->xoffset != 0) {
574
  if (db->xoffset != 0) {
575
    db->xoffset = 0;
575
    db->xoffset = 0;
576
    uidirty.from = 0;
576
    uidirty.from = 0;
577
    uidirty.to = 0xff;
577
    uidirty.to = 0xff;
578
  }
578
  }
579
}
579
}
580
 
580
 
581
 
581
 
582
static void cursor_right(struct file *db) {
582
static void cursor_right(struct file *db) {
583
  if (db->cursor->len > db->xoffset + db->cursorposx) {
583
  if (db->cursor->len > db->xoffset + db->cursorposx) {
584
    if (db->cursorposx < screenw - 2) {
584
    if (db->cursorposx < screenw - 2) {
585
      db->cursorposx += 1;
585
      db->cursorposx += 1;
586
    } else {
586
    } else {
587
      db->xoffset += 1;
587
      db->xoffset += 1;
588
      uidirty.from = 0;
588
      uidirty.from = 0;
589
      uidirty.to = 0xff;
589
      uidirty.to = 0xff;
590
    }
590
    }
591
  } else if (db->cursor->next != NULL) { /* jump to start of next line */
591
  } else if (db->cursor->next != NULL) { /* jump to start of next line */
592
    cursor_down(db);
592
    cursor_down(db);
593
    cursor_home(db);
593
    cursor_home(db);
594
  }
594
  }
595
}
595
}
596
 
596
 
597
 
597
 
598
static void del(struct file *db) {
598
static void del(struct file *db) {
599
  if (db->cursorposx + db->xoffset < db->cursor->len) {
599
  if (db->cursorposx + db->xoffset < db->cursor->len) {
600
    _fmemmove(db->cursor->payload + db->cursorposx + db->xoffset, db->cursor->payload + db->cursorposx + db->xoffset + 1, db->cursor->len - db->cursorposx - db->xoffset);
600
    fmemmove(db->cursor->payload + db->cursorposx + db->xoffset, db->cursor->payload + db->cursorposx + db->xoffset + 1, db->cursor->len - db->cursorposx - db->xoffset);
601
    db->cursor->len -= 1; /* do this AFTER memmove so the copy includes the nul terminator */
601
    db->cursor->len -= 1; /* do this AFTER memmove so the copy includes the nul terminator */
602
    uidirty.from = db->cursorposy;
602
    uidirty.from = db->cursorposy;
603
    uidirty.to = db->cursorposy;
603
    uidirty.to = db->cursorposy;
604
    db->modflag = 1;
604
    db->modflag = 1;
605
  } else if (db->cursor->next != NULL) { /* cursor is at end of line: merge current line with next one (if there is a next one) */
605
  } else if (db->cursor->next != NULL) { /* cursor is at end of line: merge current line with next one (if there is a next one) */
606
    struct line far *nextline = db->cursor->next;
606
    struct line far *nextline = db->cursor->next;
607
    if (db->cursor->next->len > 0) {
607
    if (db->cursor->next->len > 0) {
608
      if (curline_resize(db, db->cursor->len + db->cursor->next->len + 1) == 0) {
608
      if (curline_resize(db, db->cursor->len + db->cursor->next->len + 1) == 0) {
609
        _fmemmove(db->cursor->payload + db->cursor->len, db->cursor->next->payload, db->cursor->next->len + 1);
609
        fmemmove(db->cursor->payload + db->cursor->len, db->cursor->next->payload, db->cursor->next->len + 1);
610
        db->cursor->len += db->cursor->next->len;
610
        db->cursor->len += db->cursor->next->len;
611
      }
611
      }
612
    }
612
    }
613
 
613
 
614
    db->cursor->next = db->cursor->next->next;
614
    db->cursor->next = db->cursor->next->next;
615
    db->cursor->next->prev = db->cursor;
615
    db->cursor->next->prev = db->cursor;
616
 
616
 
617
    line_free(nextline);
617
    line_free(nextline);
618
    uidirty.from = db->cursorposy;
618
    uidirty.from = db->cursorposy;
619
    uidirty.to = 0xff;
619
    uidirty.to = 0xff;
620
    db->totlines -= 1;
620
    db->totlines -= 1;
621
    db->modflag = 1;
621
    db->modflag = 1;
622
  }
622
  }
623
}
623
}
624
 
624
 
625
 
625
 
626
static void bkspc(struct file *db) {
626
static void bkspc(struct file *db) {
627
  /* backspace is basically "left + del", not applicable only if cursor is on 1st byte of the file */
627
  /* backspace is basically "left + del", not applicable only if cursor is on 1st byte of the file */
628
  if ((db->cursorposx + db->xoffset == 0) && (db->cursor->prev == NULL)) return;
628
  if ((db->cursorposx + db->xoffset == 0) && (db->cursor->prev == NULL)) return;
629
 
629
 
630
  cursor_left(db);
630
  cursor_left(db);
631
  del(db);
631
  del(db);
632
}
632
}
633
 
633
 
634
 
634
 
635
#define LOADFILE_FILENOTFOUND 2
635
#define LOADFILE_FILENOTFOUND 2
636
 
636
 
637
/* returns 0 on success, 1 on file not found, 2 on other error */
637
/* returns 0 on success, 1 on file not found, 2 on other error */
638
static unsigned char loadfile(struct file *db, const char *fname) {
638
static unsigned char loadfile(struct file *db, const char *fname) {
639
  char *buffptr;
639
  char *buffptr;
640
  unsigned short len, llen;
640
  unsigned short len, llen;
641
  unsigned short fd;
641
  unsigned short fd;
642
  unsigned char eolfound;
642
  unsigned char eolfound;
643
  unsigned char err = 0;
643
  unsigned char err = 0;
644
 
644
 
645
  /* free the entire linked list of lines */
645
  /* free the entire linked list of lines */
646
  db_rewind(db);
646
  db_rewind(db);
647
  while (db->cursor) {
647
  while (db->cursor) {
648
    struct line far *victim;
648
    struct line far *victim;
649
    victim = db->cursor;
649
    victim = db->cursor;
650
    db->cursor = db->cursor->next;
650
    db->cursor = db->cursor->next;
651
    line_free(victim);
651
    line_free(victim);
652
  }
652
  }
653
 
653
 
654
  /* zero out the struct (take care to preserve the id of the slot, though) */
654
  /* zero out the struct (take care to preserve the id of the slot, though) */
655
  {
655
  {
656
    unsigned char slotid = db->slotid;
656
    unsigned char slotid = db->slotid;
657
    bzero(db, sizeof(struct file));
657
    bzero(db, sizeof(struct file));
658
    db->slotid = slotid;
658
    db->slotid = slotid;
659
  }
659
  }
660
 
660
 
661
  /* start by adding an empty line */
661
  /* start by adding an empty line */
662
  if (line_add(db, NULL, 0) != 0) return(2);
662
  if (line_add(db, NULL, 0) != 0) return(2);
663
 
663
 
664
  if (fname == NULL) goto SKIPLOADING;
664
  if (fname == NULL) goto SKIPLOADING;
665
 
665
 
666
  /* make the filename canonical (DOS 3+ only, on earlier versions it just copies the filename) */
666
  /* make the filename canonical (DOS 3+ only, on earlier versions it just copies the filename) */
667
  mdr_dos_truename(db->fname, fname);
667
  mdr_dos_truename(db->fname, fname);
668
 
668
 
669
  /* fopen file */
669
  /* fopen file */
670
  fd = 0;
670
  fd = 0;
671
  _asm {
671
  _asm {
672
    push cx
672
    push cx
673
    push dx
673
    push dx
674
 
674
 
675
    mov ax, 0x3d00
675
    mov ax, 0x3d00
676
    mov dx, fname   // works only in SMALL memory model!
676
    mov dx, fname   // works only in SMALL memory model!
677
    xor cl, cl
677
    xor cl, cl
678
    int 0x21
678
    int 0x21
679
    mov fd, ax
679
    mov fd, ax
680
    jnc done
680
    jnc done
681
    mov err, al
681
    mov err, al
682
    done:
682
    done:
683
 
683
 
684
    pop dx
684
    pop dx
685
    pop cx
685
    pop cx
686
  }
686
  }
687
 
687
 
688
  if (err != 0) goto SKIPLOADING;
688
  if (err != 0) goto SKIPLOADING;
689
 
689
 
690
  db->lfonly = 1;
690
  db->lfonly = 1;
691
 
691
 
692
  for (eolfound = 0;;) {
692
  for (eolfound = 0;;) {
693
    unsigned short consumedbytes;
693
    unsigned short consumedbytes;
694
 
694
 
695
    if ((mdr_dos_read(fd, buff, sizeof(buff), &len) != 0) || (len == 0)) break;
695
    if ((mdr_dos_read(fd, buff, sizeof(buff), &len) != 0) || (len == 0)) break;
696
    buffptr = buff;
696
    buffptr = buff;
697
 
697
 
698
    FINDLINE:
698
    FINDLINE:
699
 
699
 
700
    /* look for nearest \n (also expand tabs) */
700
    /* look for nearest \n (also expand tabs) */
701
    for (consumedbytes = 0;; consumedbytes++) {
701
    for (consumedbytes = 0;; consumedbytes++) {
702
 
702
 
703
      if (buffptr[consumedbytes] == '\t') {
703
      if (buffptr[consumedbytes] == '\t') {
704
        llen = consumedbytes;
704
        llen = consumedbytes;
705
        break;
705
        break;
706
      }
706
      }
707
 
707
 
708
      if (consumedbytes == len) {
708
      if (consumedbytes == len) {
709
        llen = consumedbytes;
709
        llen = consumedbytes;
710
        break;
710
        break;
711
      }
711
      }
712
      if (buffptr[consumedbytes] == '\r') {
712
      if (buffptr[consumedbytes] == '\r') {
713
        llen = consumedbytes;
713
        llen = consumedbytes;
714
        consumedbytes++;
714
        consumedbytes++;
715
        db->lfonly = 0;
715
        db->lfonly = 0;
716
        break;
716
        break;
717
      }
717
      }
718
      if (buffptr[consumedbytes] == '\n') {
718
      if (buffptr[consumedbytes] == '\n') {
719
        eolfound = 1;
719
        eolfound = 1;
720
        llen = consumedbytes;
720
        llen = consumedbytes;
721
        consumedbytes++;
721
        consumedbytes++;
722
        break;
722
        break;
723
      }
723
      }
724
    }
724
    }
725
 
725
 
726
    /* consumedbytes is the amount of bytes processed from buffptr,
726
    /* consumedbytes is the amount of bytes processed from buffptr,
727
     * llen is the length of line's payload (without its line terminator) */
727
     * llen is the length of line's payload (without its line terminator) */
728
 
728
 
729
    /* append content, if line is non-empty */
729
    /* append content, if line is non-empty */
730
    if ((llen > 0) && (line_append(db, buffptr, llen) != 0)) {
730
    if ((llen > 0) && (line_append(db, buffptr, llen) != 0)) {
731
      goto IOERR;
731
      goto IOERR;
732
    }
732
    }
733
 
733
 
734
    /* allocate the next line if current line ended */
734
    /* allocate the next line if current line ended */
735
    if (eolfound) {
735
    if (eolfound) {
736
      if (line_add(db, NULL, 0) != 0) {
736
      if (line_add(db, NULL, 0) != 0) {
737
        goto IOERR;
737
        goto IOERR;
738
      }
738
      }
739
      eolfound = 0;
739
      eolfound = 0;
740
    }
740
    }
741
 
741
 
742
    /* append 8 spaces if tab char found */
742
    /* append 8 spaces if tab char found */
743
    if ((consumedbytes < len) && (buffptr[consumedbytes] == '\t') && (glob_tablessmode == 0)) {
743
    if ((consumedbytes < len) && (buffptr[consumedbytes] == '\t') && (glob_tablessmode == 0)) {
744
      consumedbytes++;
744
      consumedbytes++;
745
      if (line_append(db, "        ", 8) != 0) {
745
      if (line_append(db, "        ", 8) != 0) {
746
        goto IOERR;
746
        goto IOERR;
747
      }
747
      }
748
    }
748
    }
749
 
749
 
750
    /* anything left? process the buffer leftover again */
750
    /* anything left? process the buffer leftover again */
751
    if (consumedbytes < len) {
751
    if (consumedbytes < len) {
752
      len -= consumedbytes;
752
      len -= consumedbytes;
753
      buffptr += consumedbytes;
753
      buffptr += consumedbytes;
754
      goto FINDLINE;
754
      goto FINDLINE;
755
    }
755
    }
756
 
756
 
757
  }
757
  }
758
 
758
 
759
  mdr_dos_fclose(fd);
759
  mdr_dos_fclose(fd);
760
 
760
 
761
  SKIPLOADING:
761
  SKIPLOADING:
762
 
762
 
763
  /* rewind cursor to top of file because it has been used by line_add() */
763
  /* rewind cursor to top of file because it has been used by line_add() */
764
  db_rewind(db);
764
  db_rewind(db);
765
 
765
 
766
  return(err);
766
  return(err);
767
 
767
 
768
  IOERR:
768
  IOERR:
769
  mdr_dos_fclose(fd);
769
  mdr_dos_fclose(fd);
770
  return(1);
770
  return(1);
771
}
771
}
772
 
772
 
773
 
773
 
774
/* a custom argv-parsing routine that looks directly inside the PSP, avoids the need
774
/* a custom argv-parsing routine that looks directly inside the PSP, avoids the need
775
 * of argc and argv, saves some 330 bytes of binary size
775
 * of argc and argv, saves some 330 bytes of binary size
776
 * returns non-zero on error */
776
 * returns non-zero on error */
777
static int parseargv(struct file *dbarr) {
777
static int parseargv(struct file *dbarr) {
778
  char *tail = (void *)0x81; /* THIS WORKS ONLY IN SMALL MEMORY MODEL */
778
  char *tail = (void *)0x81; /* THIS WORKS ONLY IN SMALL MEMORY MODEL */
779
  unsigned short count = 0;
779
  unsigned short count = 0;
780
  char *arg;
780
  char *arg;
781
  unsigned short lastarg = 0;
781
  unsigned short lastarg = 0;
782
  unsigned char err;
782
  unsigned char err;
783
 
783
 
784
  while (!lastarg) {
784
  while (!lastarg) {
785
    /* jump to nearest arg */
785
    /* jump to nearest arg */
786
    while (*tail == ' ') {
786
    while (*tail == ' ') {
787
      *tail = 0;
787
      *tail = 0;
788
      tail++;
788
      tail++;
789
    }
789
    }
790
 
790
 
791
    if (*tail == '\r') {
791
    if (*tail == '\r') {
792
      *tail = 0;
792
      *tail = 0;
793
      break;
793
      break;
794
    }
794
    }
795
 
795
 
796
    arg = tail;
796
    arg = tail;
797
 
797
 
798
    /* jump to next delimiter */
798
    /* jump to next delimiter */
799
    while ((*tail != ' ') && (*tail != '\r')) tail++;
799
    while ((*tail != ' ') && (*tail != '\r')) tail++;
800
 
800
 
801
    /* if \r then remember this is the last arg */
801
    /* if \r then remember this is the last arg */
802
    if (*tail == '\r') lastarg = 1;
802
    if (*tail == '\r') lastarg = 1;
803
 
803
 
804
    *tail = 0;
804
    *tail = 0;
805
    tail++;
805
    tail++;
806
 
806
 
807
    /* look at the arg now */
807
    /* look at the arg now */
808
    if (*arg == '/') {
808
    if (*arg == '/') {
809
      if (arg[1] == 't') { /* /t = do not expand tabs */
809
      if (arg[1] == 't') { /* /t = do not expand tabs */
810
        glob_tablessmode = 1;
810
        glob_tablessmode = 1;
811
 
811
 
812
      } else if (arg[1] == 'm') { /* /m = force mono mode */
812
      } else if (arg[1] == 'm') { /* /m = force mono mode */
813
        glob_monomode = 1;
813
        glob_monomode = 1;
814
 
814
 
815
      } else {  /* help screen */
815
      } else {  /* help screen */
816
        mdr_coutraw_str(svarlang_str(1,3)); /* Sved, the SvarDOS editor */
816
        mdr_coutraw_str(svarlang_str(1,3)); /* Sved, the SvarDOS editor */
817
        mdr_coutraw_str(" [");
817
        mdr_coutraw_str(" [");
818
        mdr_coutraw_str(svarlang_str(1,4)); /* ver */
818
        mdr_coutraw_str(svarlang_str(1,4)); /* ver */
819
        mdr_coutraw_puts(" " PVER "]");
819
        mdr_coutraw_puts(" " PVER "]");
820
        mdr_coutraw_puts("Copyright (C) " PDATE " Mateusz Viste");
820
        mdr_coutraw_puts("Copyright (C) " PDATE " Mateusz Viste");
821
        mdr_coutraw_crlf();
821
        mdr_coutraw_crlf();
822
        mdr_coutraw_str("sved [/m] [/t] ");
822
        mdr_coutraw_str("sved [/m] [/t] ");
823
        mdr_coutraw_puts(svarlang_str(1,1)); /* args syntax */
823
        mdr_coutraw_puts(svarlang_str(1,1)); /* args syntax */
824
        mdr_coutraw_crlf();
824
        mdr_coutraw_crlf();
825
        mdr_coutraw_puts(svarlang_str(1,10)); /* /m */
825
        mdr_coutraw_puts(svarlang_str(1,10)); /* /m */
826
        mdr_coutraw_puts(svarlang_str(1,11)); /* /t */
826
        mdr_coutraw_puts(svarlang_str(1,11)); /* /t */
827
        return(-1);
827
        return(-1);
828
      }
828
      }
829
      continue;
829
      continue;
830
    }
830
    }
831
 
831
 
832
    /* looks to be a filename */
832
    /* looks to be a filename */
833
    if (count == 10) {
833
    if (count == 10) {
834
      mdr_coutraw_puts(svarlang_str(0,12)); /* too many files */
834
      mdr_coutraw_puts(svarlang_str(0,12)); /* too many files */
835
      return(-1);
835
      return(-1);
836
    }
836
    }
837
 
837
 
838
    /* try loading it */
838
    /* try loading it */
839
    mdr_coutraw_str(svarlang_str(1,2));
839
    mdr_coutraw_str(svarlang_str(1,2));
840
    mdr_coutraw_char(' ');
840
    mdr_coutraw_char(' ');
841
    mdr_coutraw_puts(arg);
841
    mdr_coutraw_puts(arg);
842
    err = loadfile(&(dbarr[count]), arg);
842
    err = loadfile(&(dbarr[count]), arg);
843
    if (err) {
843
    if (err) {
844
      if (err == LOADFILE_FILENOTFOUND) { /* file not found */
844
      if (err == LOADFILE_FILENOTFOUND) { /* file not found */
845
        if ((count == 0) && (lastarg != 0)) { /* a 'file not found' is fine if only one file was given */
845
        if ((count == 0) && (lastarg != 0)) { /* a 'file not found' is fine if only one file was given */
846
          err = 0;
846
          err = 0;
847
        } else {
847
        } else {
848
          err = 11;
848
          err = 11;
849
        }
849
        }
850
      } else { /* general error */
850
      } else { /* general error */
851
        err = 10;
851
        err = 10;
852
      }
852
      }
853
      if (err) {
853
      if (err) {
854
        mdr_coutraw_puts(svarlang_str(0,err));
854
        mdr_coutraw_puts(svarlang_str(0,err));
855
        return(-1);
855
        return(-1);
856
      }
856
      }
857
    }
857
    }
858
    count++;
858
    count++;
859
  }
859
  }
860
 
860
 
861
  return(0);
861
  return(0);
862
}
862
}
863
 
863
 
864
 
864
 
865
static void insert_in_line(struct file *db, const char *databuf, unsigned short len) {
865
static void insert_in_line(struct file *db, const char *databuf, unsigned short len) {
866
  if (curline_resize(db, db->cursor->len + len) == 0) {
866
  if (curline_resize(db, db->cursor->len + len) == 0) {
867
    unsigned short off = db->xoffset + db->cursorposx;
867
    unsigned short off = db->xoffset + db->cursorposx;
868
    db->modflag = 1;
868
    db->modflag = 1;
869
    _fmemmove(db->cursor->payload + off + len, db->cursor->payload + off, db->cursor->len - off + 1);
869
    fmemmove(db->cursor->payload + off + len, db->cursor->payload + off, db->cursor->len - off + 1);
870
    db->cursor->len += len;
870
    db->cursor->len += len;
871
    uidirty.from = db->cursorposy;
871
    uidirty.from = db->cursorposy;
872
    uidirty.to = db->cursorposy;
872
    uidirty.to = db->cursorposy;
873
    while (len--) {
873
    while (len--) {
874
      db->cursor->payload[off++] = *databuf;
874
      db->cursor->payload[off++] = *databuf;
875
      databuf++;
875
      databuf++;
876
      cursor_right(db);
876
      cursor_right(db);
877
    }
877
    }
878
  }
878
  }
879
}
879
}
880
 
880
 
881
 
881
 
882
/* recompute db->curline by counting nodes in linked list */
882
/* recompute db->curline by counting nodes in linked list */
883
static void recompute_curline(struct file *db) {
883
static void recompute_curline(struct file *db) {
884
  const struct line far *l = db->cursor;
884
  const struct line far *l = db->cursor;
885
 
885
 
886
  db->curline = 0;
886
  db->curline = 0;
887
  while (l->prev != NULL) {
887
  while (l->prev != NULL) {
888
    db->curline += 1;
888
    db->curline += 1;
889
    l = l->prev;
889
    l = l->prev;
890
  }
890
  }
891
}
891
}
892
 
892
 
893
 
893
 
894
enum MENU_ACTION {
894
enum MENU_ACTION {
895
  MENU_NONE   = 0,
895
  MENU_NONE   = 0,
896
  MENU_OPEN   = 1,
896
  MENU_OPEN   = 1,
897
  MENU_SAVE   = 2,
897
  MENU_SAVE   = 2,
898
  MENU_SAVEAS = 3,
898
  MENU_SAVEAS = 3,
899
  MENU_CLOSE  = 4,
899
  MENU_CLOSE  = 4,
900
  MENU_CHGEOL = 5,
900
  MENU_CHGEOL = 5,
901
  MENU_QUIT   = 6
901
  MENU_QUIT   = 6
902
};
902
};
903
 
903
 
904
static enum MENU_ACTION ui_menu(void) {
904
static enum MENU_ACTION ui_menu(void) {
905
  unsigned short i, curchoice, attr, x, slen;
905
  unsigned short i, curchoice, attr, x, slen;
906
  unsigned short xorigin, yorigin;
906
  unsigned short xorigin, yorigin;
907
 
907
 
908
  /* find out the longest string */
908
  /* find out the longest string */
909
  slen = 0;
909
  slen = 0;
910
  for (i = MENU_OPEN; i <= MENU_QUIT; i++) {
910
  for (i = MENU_OPEN; i <= MENU_QUIT; i++) {
911
    x = strlen(svarlang_str(8, i));
911
    x = strlen(svarlang_str(8, i));
912
    if (x > slen) slen = x;
912
    if (x > slen) slen = x;
913
  }
913
  }
914
 
914
 
915
  /* calculate where to draw the menu on screen */
915
  /* calculate where to draw the menu on screen */
916
  xorigin = (screenw - (slen + 5)) / 2;
916
  xorigin = (screenw - (slen + 5)) / 2;
917
  yorigin = (screenh - (MENU_QUIT - MENU_OPEN + 6)) / 2;
917
  yorigin = (screenh - (MENU_QUIT - MENU_OPEN + 6)) / 2;
918
 
918
 
919
  /* */
919
  /* */
920
  uidirty.from = yorigin;
920
  uidirty.from = yorigin;
921
  uidirty.to = 0xff;
921
  uidirty.to = 0xff;
922
  uidirty.statusbar = 1;
922
  uidirty.statusbar = 1;
923
 
923
 
924
  /* hide the cursor */
924
  /* hide the cursor */
925
  mdr_cout_cursor_hide();
925
  mdr_cout_cursor_hide();
926
 
926
 
927
  curchoice = MENU_OPEN;
927
  curchoice = MENU_OPEN;
928
  for (;;) {
928
  for (;;) {
929
    /* render menu */
929
    /* render menu */
930
    for (i = MENU_NONE; i <= MENU_QUIT + 1; i++) {
930
    for (i = MENU_NONE; i <= MENU_QUIT + 1; i++) {
931
      mdr_cout_char_rep(yorigin + i, xorigin, ' ', SCHEME_MENU, slen+4);
931
      mdr_cout_char_rep(yorigin + i, xorigin, ' ', SCHEME_MENU, slen+4);
932
      if (i == curchoice) {
932
      if (i == curchoice) {
933
        attr = SCHEME_MENU_CUR;
933
        attr = SCHEME_MENU_CUR;
934
        mdr_cout_char_rep(yorigin + i, xorigin + 1, ' ', SCHEME_MENU_SEL, slen + 2);
934
        mdr_cout_char_rep(yorigin + i, xorigin + 1, ' ', SCHEME_MENU_SEL, slen + 2);
935
      } else {
935
      } else {
936
        attr = SCHEME_MENU;
936
        attr = SCHEME_MENU;
937
      }
937
      }
938
      mdr_cout_str(yorigin + i, xorigin + 2, svarlang_str(8, i), attr, slen);
938
      mdr_cout_str(yorigin + i, xorigin + 2, svarlang_str(8, i), attr, slen);
939
    }
939
    }
940
    /* wait for key */
940
    /* wait for key */
941
    switch (mdr_dos_getkey2()) {
941
    switch (mdr_dos_getkey2()) {
942
      case 0x150: /* down */
942
      case 0x150: /* down */
943
        if (curchoice == MENU_QUIT) {
943
        if (curchoice == MENU_QUIT) {
944
          curchoice = MENU_OPEN;
944
          curchoice = MENU_OPEN;
945
        } else {
945
        } else {
946
          curchoice++;
946
          curchoice++;
947
        }
947
        }
948
        break;
948
        break;
949
      case 0x148: /* up */
949
      case 0x148: /* up */
950
        if (curchoice == MENU_OPEN) {
950
        if (curchoice == MENU_OPEN) {
951
          curchoice = MENU_QUIT;
951
          curchoice = MENU_QUIT;
952
        } else {
952
        } else {
953
          curchoice--;
953
          curchoice--;
954
        }
954
        }
955
        break;
955
        break;
956
      default:
956
      default:
957
        curchoice = MENU_NONE;
957
        curchoice = MENU_NONE;
958
        /* FALLTHRU */
958
        /* FALLTHRU */
959
      case '\r': /* ENTER */
959
      case '\r': /* ENTER */
960
        mdr_cout_cursor_show();
960
        mdr_cout_cursor_show();
961
        return(curchoice);
961
        return(curchoice);
962
    }
962
    }
963
  }
963
  }
964
}
964
}
965
 
965
 
966
 
966
 
967
static struct file *select_slot(struct file *dbarr, unsigned short curfile) {
967
static struct file *select_slot(struct file *dbarr, unsigned short curfile) {
968
  uidirty.from = 0;
968
  uidirty.from = 0;
969
  uidirty.to = 0xff;
969
  uidirty.to = 0xff;
970
  uidirty.statusbar = 1;
970
  uidirty.statusbar = 1;
971
 
971
 
972
  dbarr = &(dbarr[curfile]);
972
  dbarr = &(dbarr[curfile]);
973
 
973
 
974
  /* force redraw now, because the main() routine might not if this is exit
974
  /* force redraw now, because the main() routine might not if this is exit
975
   * time and we want to show the user which file has unsaved changes */
975
   * time and we want to show the user which file has unsaved changes */
976
  ui_statusbar(dbarr);
976
  ui_statusbar(dbarr);
977
  ui_refresh(dbarr);
977
  ui_refresh(dbarr);
978
  return(dbarr);
978
  return(dbarr);
979
}
979
}
980
 
980
 
981
 
981
 
982
/* main returns nothing, ie. sved always exits with a zero exit code
982
/* main returns nothing, ie. sved always exits with a zero exit code
983
 * (this saves 20 bytes of executable footprint) */
983
 * (this saves 20 bytes of executable footprint) */
984
void main(void) {
984
void main(void) {
985
  static struct file dbarr[10];
985
  static struct file dbarr[10];
986
  struct file *db = dbarr; /* visible file is the first slot by default */
986
  struct file *db = dbarr; /* visible file is the first slot by default */
987
  static struct line far *clipboard;
987
  static struct line far *clipboard;
988
  static unsigned char original_breakflag;
988
  static unsigned char original_breakflag;
989
 
989
 
990
  { /* load NLS resource */
990
  { /* load NLS resource */
991
    unsigned short i = 0;
991
    unsigned short i = 0;
992
    const char far *selfptr;
992
    const char far *selfptr;
993
    char lang[8];
993
    char lang[8];
994
    selfptr = mdr_dos_selfexe();
994
    selfptr = mdr_dos_selfexe();
995
    if (selfptr != NULL) {
995
    if (selfptr != NULL) {
996
      do {
996
      do {
997
        buff[i] = selfptr[i];
997
        buff[i] = selfptr[i];
998
      } while (buff[i++] != 0);
998
      } while (buff[i++] != 0);
999
      svarlang_autoload_exepath(buff, mdr_dos_getenv(lang, "LANG", sizeof(lang)));
999
      svarlang_autoload_exepath(buff, mdr_dos_getenv(lang, "LANG", sizeof(lang)));
1000
    }
1000
    }
1001
  }
1001
  }
1002
 
1002
 
1003
  /* preload all slots with empty files */
1003
  /* preload all slots with empty files */
1004
  {
1004
  {
1005
    unsigned short i;
1005
    unsigned short i;
1006
    for (i = 0; i < 10; i++) {
1006
    for (i = 0; i < 10; i++) {
1007
      loadfile(&(dbarr[i]), NULL);
1007
      loadfile(&(dbarr[i]), NULL);
1008
      dbarr[i].slotid = i;
1008
      dbarr[i].slotid = i;
1009
    }
1009
    }
1010
  }
1010
  }
1011
 
1011
 
1012
  /* parse argv (and load files, if any passed on) */
1012
  /* parse argv (and load files, if any passed on) */
1013
  if (parseargv(dbarr) != 0) return;
1013
  if (parseargv(dbarr) != 0) return;
1014
 
1014
 
1015
  if ((mdr_cout_init(&screenw, &screenh) != 0) && (glob_monomode == 0)) {
1015
  if ((mdr_cout_init(&screenw, &screenh) != 0) && (glob_monomode == 0)) {
1016
    /* load color scheme if mdr_cout_init returns a color flag */
1016
    /* load color scheme if mdr_cout_init returns a color flag */
1017
    SCHEME_TEXT = 0x17;
1017
    SCHEME_TEXT = 0x17;
1018
    SCHEME_MENU = 0x70;
1018
    SCHEME_MENU = 0x70;
1019
    SCHEME_MENU_CUR = 0x6f;
1019
    SCHEME_MENU_CUR = 0x6f;
1020
    SCHEME_MENU_SEL = 0x66;
1020
    SCHEME_MENU_SEL = 0x66;
1021
    SCHEME_STBAR1 = 0x70;
1021
    SCHEME_STBAR1 = 0x70;
1022
    SCHEME_STBAR2 = 0x78;
1022
    SCHEME_STBAR2 = 0x78;
1023
    SCHEME_STBAR3 = 0x3f;
1023
    SCHEME_STBAR3 = 0x3f;
1024
    SCHEME_SCROLL = 0x70;
1024
    SCHEME_SCROLL = 0x70;
1025
    SCHEME_MSG = 0x6f;
1025
    SCHEME_MSG = 0x6f;
1026
    SCHEME_ERR = 0x4f;
1026
    SCHEME_ERR = 0x4f;
1027
  }
1027
  }
1028
  screenlastrow = screenh - 1;
1028
  screenlastrow = screenh - 1;
1029
  screenlastcol = screenw - 1;
1029
  screenlastcol = screenw - 1;
1030
 
1030
 
1031
  /* instruct DOS to stop detecting CTRL+C because user needs it for
1031
  /* instruct DOS to stop detecting CTRL+C because user needs it for
1032
   * copy/paste operations. also remember the original status of the BREAK
1032
   * copy/paste operations. also remember the original status of the BREAK
1033
   * flag so I can restore it as it was before quitting. */
1033
   * flag so I can restore it as it was before quitting. */
1034
  original_breakflag = mdr_dos_ctrlc_disable();
1034
  original_breakflag = mdr_dos_ctrlc_disable();
1035
 
1035
 
1036
  for (;;) {
1036
  for (;;) {
1037
    int k;
1037
    int k;
1038
 
1038
 
1039
    /* add an extra empty line if cursor is on last line and this line is not empty */
1039
    /* add an extra empty line if cursor is on last line and this line is not empty */
1040
    if ((db->cursor->next == NULL) && (db->cursor->len != 0)) {
1040
    if ((db->cursor->next == NULL) && (db->cursor->len != 0)) {
1041
      if (line_add(db, NULL, 0) == 0) {
1041
      if (line_add(db, NULL, 0) == 0) {
1042
        db->cursor = db->cursor->prev; /* line_add() changes the cursor pointer */
1042
        db->cursor = db->cursor->prev; /* line_add() changes the cursor pointer */
1043
        db->curline -= 1;
1043
        db->curline -= 1;
1044
      }
1044
      }
1045
    }
1045
    }
1046
 
1046
 
1047
    check_cursor_not_after_eol(db);
1047
    check_cursor_not_after_eol(db);
1048
    mdr_cout_locate(db->cursorposy, db->cursorposx);
1048
    mdr_cout_locate(db->cursorposy, db->cursorposx);
1049
 
1049
 
1050
    ui_refresh(db);
1050
    ui_refresh(db);
1051
 
1051
 
1052
    if ((uidirty.statusbar != 0) || (db->modflagprev != db->modflag) || (db->curline_prev != db->curline)) {
1052
    if ((uidirty.statusbar != 0) || (db->modflagprev != db->modflag) || (db->curline_prev != db->curline)) {
1053
      ui_statusbar(db);
1053
      ui_statusbar(db);
1054
      uidirty.statusbar = 0;
1054
      uidirty.statusbar = 0;
1055
      db->modflagprev = db->modflag;
1055
      db->modflagprev = db->modflag;
1056
      db->curline_prev = db->curline;
1056
      db->curline_prev = db->curline;
1057
    }
1057
    }
1058
#ifdef DBG_LINENUM
1058
#ifdef DBG_LINENUM
1059
      {
1059
      {
1060
        char ddd[10];
1060
        char ddd[10];
1061
        db->curline += 1;
1061
        db->curline += 1;
1062
        ddd[0] = '0' + db->curline / 100;
1062
        ddd[0] = '0' + db->curline / 100;
1063
        ddd[1] = '0' + (db->curline % 100) / 10;
1063
        ddd[1] = '0' + (db->curline % 100) / 10;
1064
        ddd[2] = '0' + (db->curline % 10);
1064
        ddd[2] = '0' + (db->curline % 10);
1065
        db->curline -= 1;
1065
        db->curline -= 1;
1066
        ddd[3] = '/';
1066
        ddd[3] = '/';
1067
        ddd[4] = '0' + db->totlines / 100;
1067
        ddd[4] = '0' + db->totlines / 100;
1068
        ddd[5] = '0' + (db->totlines % 100) / 10;
1068
        ddd[5] = '0' + (db->totlines % 100) / 10;
1069
        ddd[6] = '0' + (db->totlines % 10);
1069
        ddd[6] = '0' + (db->totlines % 10);
1070
        ddd[7] = 0;
1070
        ddd[7] = 0;
1071
        mdr_cout_str(screenh - 1, 40, ddd, SCHEME_STBAR1, sizeof(ddd));
1071
        mdr_cout_str(screenh - 1, 40, ddd, SCHEME_STBAR1, sizeof(ddd));
1072
      }
1072
      }
1073
#endif
1073
#endif
1074
 
1074
 
1075
    k = mdr_dos_getkey2();
1075
    k = mdr_dos_getkey2();
1076
 
1076
 
1077
    if (k == 0x150) { /* down */
1077
    if (k == 0x150) { /* down */
1078
      cursor_down(db);
1078
      cursor_down(db);
1079
 
1079
 
1080
    } else if (k == 0x148) { /* up */
1080
    } else if (k == 0x148) { /* up */
1081
      cursor_up(db);
1081
      cursor_up(db);
1082
 
1082
 
1083
    } else if (k == 0x14D) { /* right */
1083
    } else if (k == 0x14D) { /* right */
1084
      cursor_right(db);
1084
      cursor_right(db);
1085
 
1085
 
1086
    } else if (k == 0x14B) { /* left */
1086
    } else if (k == 0x14B) { /* left */
1087
      cursor_left(db);
1087
      cursor_left(db);
1088
 
1088
 
1089
    } else if (k == 0x149) { /* pgup */
1089
    } else if (k == 0x149) { /* pgup */
1090
      unsigned char dist = db->cursorposy + screenh - 1;
1090
      unsigned char dist = db->cursorposy + screenh - 1;
1091
      while ((dist != 0) && (db->cursor->prev != NULL)) {
1091
      while ((dist != 0) && (db->cursor->prev != NULL)) {
1092
        db->cursor = db->cursor->prev;
1092
        db->cursor = db->cursor->prev;
1093
        dist--;
1093
        dist--;
1094
      }
1094
      }
1095
      if (dist != 0) {
1095
      if (dist != 0) {
1096
        db->cursorposy = 0;
1096
        db->cursorposy = 0;
1097
        db->cursorposx = 0;
1097
        db->cursorposx = 0;
1098
      } else {
1098
      } else {
1099
        dist = db->cursorposy;
1099
        dist = db->cursorposy;
1100
        while ((dist--) && (db->cursor->next)) db->cursor = db->cursor->next;
1100
        while ((dist--) && (db->cursor->next)) db->cursor = db->cursor->next;
1101
      }
1101
      }
1102
      uidirty.from = 0;
1102
      uidirty.from = 0;
1103
      uidirty.to = 0xff;
1103
      uidirty.to = 0xff;
1104
      recompute_curline(db);
1104
      recompute_curline(db);
1105
 
1105
 
1106
    } else if (k == 0x151) { /* pgdown */
1106
    } else if (k == 0x151) { /* pgdown */
1107
      unsigned char dist = screenh + screenh - db->cursorposy - 3;
1107
      unsigned char dist = screenh + screenh - db->cursorposy - 3;
1108
      while ((dist != 0) && (db->cursor->next != NULL)) {
1108
      while ((dist != 0) && (db->cursor->next != NULL)) {
1109
        db->cursor = db->cursor->next;
1109
        db->cursor = db->cursor->next;
1110
        dist--;
1110
        dist--;
1111
      }
1111
      }
1112
      if (dist != 0) {
1112
      if (dist != 0) {
1113
        db->cursorposy = screenh - 2;
1113
        db->cursorposy = screenh - 2;
1114
        if (db->totlines <= db->cursorposy) db->cursorposy = db->totlines - 1;
1114
        if (db->totlines <= db->cursorposy) db->cursorposy = db->totlines - 1;
1115
        db->cursorposx = 0;
1115
        db->cursorposx = 0;
1116
      } else {
1116
      } else {
1117
        dist = screenh - 2 - db->cursorposy;
1117
        dist = screenh - 2 - db->cursorposy;
1118
        while ((dist--) && (db->cursor->prev)) db->cursor = db->cursor->prev;
1118
        while ((dist--) && (db->cursor->prev)) db->cursor = db->cursor->prev;
1119
      }
1119
      }
1120
      uidirty.from = 0;
1120
      uidirty.from = 0;
1121
      uidirty.to = 0xff;
1121
      uidirty.to = 0xff;
1122
      recompute_curline(db);
1122
      recompute_curline(db);
1123
 
1123
 
1124
    } else if (k == 0x147) { /* home */
1124
    } else if (k == 0x147) { /* home */
1125
       cursor_home(db);
1125
       cursor_home(db);
1126
 
1126
 
1127
    } else if (k == 0x14F) { /* end */
1127
    } else if (k == 0x14F) { /* end */
1128
       cursor_eol(db);
1128
       cursor_eol(db);
1129
 
1129
 
1130
    } else if (k == 0x1B) { /* ESC */
1130
    } else if (k == 0x1B) { /* ESC */
1131
      int quitnow = 0;
1131
      int quitnow = 0;
1132
      char fname[64];
1132
      char fname[64];
1133
      int saveflag = 0;
1133
      int saveflag = 0;
1134
      enum MENU_ACTION ui_action;
1134
      enum MENU_ACTION ui_action;
1135
 
1135
 
1136
      /* collect the exact menu action and clear the screen */
1136
      /* collect the exact menu action and clear the screen */
1137
      ui_action = ui_menu();
1137
      ui_action = ui_menu();
1138
      ui_refresh(db);
1138
      ui_refresh(db);
1139
 
1139
 
1140
      switch (ui_action) {
1140
      switch (ui_action) {
1141
 
1141
 
1142
        case MENU_NONE:
1142
        case MENU_NONE:
1143
          break;
1143
          break;
1144
 
1144
 
1145
        case MENU_OPEN:
1145
        case MENU_OPEN:
1146
          /* display a warning if unsaved changes are pending */
1146
          /* display a warning if unsaved changes are pending */
1147
          if (db->modflag != 0) ui_msg(4, 8, 0, SCHEME_MSG);
1147
          if (db->modflag != 0) ui_msg(4, 8, 0, SCHEME_MSG);
1148
 
1148
 
1149
          /* ask for filename */
1149
          /* ask for filename */
1150
          ui_getstring(svarlang_str(0,7), fname, sizeof(fname));
1150
          ui_getstring(svarlang_str(0,7), fname, sizeof(fname));
1151
          if (fname[0] != 0) {
1151
          if (fname[0] != 0) {
1152
            unsigned char err;
1152
            unsigned char err;
1153
            err = loadfile(db, fname);
1153
            err = loadfile(db, fname);
1154
            if (err != 0) {
1154
            if (err != 0) {
1155
              if (err == LOADFILE_FILENOTFOUND) {
1155
              if (err == LOADFILE_FILENOTFOUND) {
1156
                ui_msg(11, 0, 0, SCHEME_ERR); /* file not found */
1156
                ui_msg(11, 0, 0, SCHEME_ERR); /* file not found */
1157
              } else {
1157
              } else {
1158
                ui_msg(10, 0, 0, SCHEME_ERR);  /* ERROR */
1158
                ui_msg(10, 0, 0, SCHEME_ERR);  /* ERROR */
1159
              }
1159
              }
1160
              mdr_bios_tickswait(44); /* 3s */
1160
              mdr_bios_tickswait(44); /* 3s */
1161
              loadfile(db, NULL);
1161
              loadfile(db, NULL);
1162
            }
1162
            }
1163
          }
1163
          }
1164
          uidirty.from = 0;
1164
          uidirty.from = 0;
1165
          uidirty.to = 0xff;
1165
          uidirty.to = 0xff;
1166
          uidirty.statusbar = 1;
1166
          uidirty.statusbar = 1;
1167
          break;
1167
          break;
1168
 
1168
 
1169
        case MENU_SAVEAS:
1169
        case MENU_SAVEAS:
1170
          saveflag = 1;
1170
          saveflag = 1;
1171
          /* FALLTHRU */
1171
          /* FALLTHRU */
1172
        case MENU_SAVE:
1172
        case MENU_SAVE:
1173
          if ((saveflag != 0) || (db->fname[0] == 0)) { /* save as... */
1173
          if ((saveflag != 0) || (db->fname[0] == 0)) { /* save as... */
1174
            ui_getstring(svarlang_str(0,6), fname, sizeof(fname));
1174
            ui_getstring(svarlang_str(0,6), fname, sizeof(fname));
1175
            if (*fname == 0) break;
1175
            if (*fname == 0) break;
1176
            saveflag = savefile(db, fname);
1176
            saveflag = savefile(db, fname);
1177
          } else {
1177
          } else {
1178
            saveflag = savefile(db, NULL);
1178
            saveflag = savefile(db, NULL);
1179
          }
1179
          }
1180
 
1180
 
1181
          mdr_cout_cursor_hide();
1181
          mdr_cout_cursor_hide();
1182
 
1182
 
1183
          if (saveflag == 0) {
1183
          if (saveflag == 0) {
1184
            ui_msg(2, 0, 0, SCHEME_MSG);
1184
            ui_msg(2, 0, 0, SCHEME_MSG);
1185
            mdr_bios_tickswait(11); /* 11 ticks is about 600 ms */
1185
            mdr_bios_tickswait(11); /* 11 ticks is about 600 ms */
1186
          } else {
1186
          } else {
1187
            ui_msg(10, 0, 0, SCHEME_ERR);
1187
            ui_msg(10, 0, 0, SCHEME_ERR);
1188
            mdr_bios_tickswait(36); /* 2s */
1188
            mdr_bios_tickswait(36); /* 2s */
1189
          }
1189
          }
1190
          mdr_cout_cursor_show();
1190
          mdr_cout_cursor_show();
1191
          break;
1191
          break;
1192
 
1192
 
1193
        case MENU_CLOSE:
1193
        case MENU_CLOSE:
1194
          if (ui_confirm_if_unsaved(db) == 0) {
1194
          if (ui_confirm_if_unsaved(db) == 0) {
1195
            loadfile(db, NULL);
1195
            loadfile(db, NULL);
1196
          }
1196
          }
1197
          uidirty.from = 0;
1197
          uidirty.from = 0;
1198
          uidirty.to = 0xff;
1198
          uidirty.to = 0xff;
1199
          uidirty.statusbar = 1;
1199
          uidirty.statusbar = 1;
1200
          break;
1200
          break;
1201
 
1201
 
1202
        case MENU_CHGEOL:
1202
        case MENU_CHGEOL:
1203
          db->modflag = 1;
1203
          db->modflag = 1;
1204
          db->lfonly ^= 1;
1204
          db->lfonly ^= 1;
1205
          break;
1205
          break;
1206
 
1206
 
1207
        case MENU_QUIT:
1207
        case MENU_QUIT:
1208
          quitnow = 1;
1208
          quitnow = 1;
1209
          {
1209
          {
1210
            unsigned short curfile;
1210
            unsigned short curfile;
1211
            for (curfile = 0; curfile < 10; curfile++) {
1211
            for (curfile = 0; curfile < 10; curfile++) {
1212
              if (dbarr[curfile].modflag == 0) continue; /* skip unmodified slots */
1212
              if (dbarr[curfile].modflag == 0) continue; /* skip unmodified slots */
1213
              db = select_slot(dbarr, curfile);
1213
              db = select_slot(dbarr, curfile);
1214
              if (ui_confirm_if_unsaved(db) != 0) {
1214
              if (ui_confirm_if_unsaved(db) != 0) {
1215
                quitnow = 0;
1215
                quitnow = 0;
1216
                break;
1216
                break;
1217
              }
1217
              }
1218
            }
1218
            }
1219
          }
1219
          }
1220
          break;
1220
          break;
1221
      }
1221
      }
1222
 
1222
 
1223
      if (quitnow) break;
1223
      if (quitnow) break;
1224
 
1224
 
1225
    } else if (k == 0x0D) { /* ENTER */
1225
    } else if (k == 0x0D) { /* ENTER */
1226
      unsigned short off = db->xoffset + db->cursorposx;
1226
      unsigned short off = db->xoffset + db->cursorposx;
1227
      /* add a new line */
1227
      /* add a new line */
1228
      if (line_add(db, db->cursor->payload + off, db->cursor->len - off) == 0) {
1228
      if (line_add(db, db->cursor->payload + off, db->cursor->len - off) == 0) {
1229
        db->modflag = 1;
1229
        db->modflag = 1;
1230
        db->cursor = db->cursor->prev; /* back to original line */
1230
        db->cursor = db->cursor->prev; /* back to original line */
1231
        db->curline -= 1;
1231
        db->curline -= 1;
1232
        /* trim the line above */
1232
        /* trim the line above */
1233
        db->cursor->len = off;
1233
        db->cursor->len = off;
1234
        /* move cursor to the (new) line below */
1234
        /* move cursor to the (new) line below */
1235
        uidirty.from = db->cursorposy;
1235
        uidirty.from = db->cursorposy;
1236
        uidirty.to = 0xff;
1236
        uidirty.to = 0xff;
1237
        cursor_down(db);
1237
        cursor_down(db);
1238
        cursor_home(db);
1238
        cursor_home(db);
1239
      } else {
1239
      } else {
1240
        /* ERROR: OUT OF MEMORY */
1240
        /* ERROR: OUT OF MEMORY */
1241
      }
1241
      }
1242
 
1242
 
1243
    } else if (k == 0x153) {  /* DEL */
1243
    } else if (k == 0x153) {  /* DEL */
1244
      del(db);
1244
      del(db);
1245
 
1245
 
1246
    } else if (k == 0x008) { /* BKSPC */
1246
    } else if (k == 0x008) { /* BKSPC */
1247
      bkspc(db);
1247
      bkspc(db);
1248
 
1248
 
1249
    } else if ((k >= 0x20) && (k <= 0xff)) { /* "normal" character */
1249
    } else if ((k >= 0x20) && (k <= 0xff)) { /* "normal" character */
1250
      char c = k;
1250
      char c = k;
1251
      insert_in_line(db, &c, 1);
1251
      insert_in_line(db, &c, 1);
1252
 
1252
 
1253
    } else if (k == 0x009) { /* TAB */
1253
    } else if (k == 0x009) { /* TAB */
1254
      if (glob_tablessmode == 0) {
1254
      if (glob_tablessmode == 0) {
1255
        insert_in_line(db, "        ", 8);
1255
        insert_in_line(db, "        ", 8);
1256
      } else {
1256
      } else {
1257
        insert_in_line(db, "\t", 1);
1257
        insert_in_line(db, "\t", 1);
1258
      }
1258
      }
1259
 
1259
 
1260
    } else if ((k >= 0x13b) && (k <= 0x144)) { /* F1..F10 */
1260
    } else if ((k >= 0x13b) && (k <= 0x144)) { /* F1..F10 */
1261
      db = select_slot(dbarr, k - 0x13b);
1261
      db = select_slot(dbarr, k - 0x13b);
1262
 
1262
 
1263
    } else if (k == 0x174) { /* CTRL+ArrRight - jump to next word */
1263
    } else if (k == 0x174) { /* CTRL+ArrRight - jump to next word */
1264
      /* if currently cursor is on a non-space, then fast-forward to nearest space or EOL */
1264
      /* if currently cursor is on a non-space, then fast-forward to nearest space or EOL */
1265
      for (;;) {
1265
      for (;;) {
1266
        if (db->xoffset + db->cursorposx == db->cursor->len) break;
1266
        if (db->xoffset + db->cursorposx == db->cursor->len) break;
1267
        if (db->cursor->payload[db->xoffset + db->cursorposx] == ' ') break;
1267
        if (db->cursor->payload[db->xoffset + db->cursorposx] == ' ') break;
1268
        cursor_right(db);
1268
        cursor_right(db);
1269
      }
1269
      }
1270
      /* now skip to next non-space or end of file */
1270
      /* now skip to next non-space or end of file */
1271
      for (;;) {
1271
      for (;;) {
1272
        cursor_right(db);
1272
        cursor_right(db);
1273
        if (db->cursor->payload[db->xoffset + db->cursorposx] != ' ') break;
1273
        if (db->cursor->payload[db->xoffset + db->cursorposx] != ' ') break;
1274
        if ((db->cursor->next == NULL) && (db->cursorposx + db->xoffset == db->cursor->len)) break;
1274
        if ((db->cursor->next == NULL) && (db->cursorposx + db->xoffset == db->cursor->len)) break;
1275
      }
1275
      }
1276
 
1276
 
1277
    } else if (k == 0x173) { /* CTRL+ArrLeft - jump to prev word */
1277
    } else if (k == 0x173) { /* CTRL+ArrLeft - jump to prev word */
1278
      cursor_left(db);
1278
      cursor_left(db);
1279
      /* if currently cursor is on a space, then fast-forward to nearest non-space or start of line */
1279
      /* if currently cursor is on a space, then fast-forward to nearest non-space or start of line */
1280
      for (;;) {
1280
      for (;;) {
1281
        if ((db->xoffset == 0) && (db->cursorposx == 0)) break;
1281
        if ((db->xoffset == 0) && (db->cursorposx == 0)) break;
1282
        if (db->cursor->payload[db->xoffset + db->cursorposx] != ' ') break;
1282
        if (db->cursor->payload[db->xoffset + db->cursorposx] != ' ') break;
1283
        cursor_left(db);
1283
        cursor_left(db);
1284
      }
1284
      }
1285
      /* now skip to next space or start of file */
1285
      /* now skip to next space or start of file */
1286
      for (;;) {
1286
      for (;;) {
1287
        cursor_left(db);
1287
        cursor_left(db);
1288
        if (db->cursor->payload[db->xoffset + db->cursorposx] == ' ') {
1288
        if (db->cursor->payload[db->xoffset + db->cursorposx] == ' ') {
1289
          cursor_right(db);
1289
          cursor_right(db);
1290
          break;
1290
          break;
1291
        }
1291
        }
1292
        if ((db->cursorposx == 0) && (db->xoffset == 0)) break;
1292
        if ((db->cursorposx == 0) && (db->xoffset == 0)) break;
1293
      }
1293
      }
1294
 
1294
 
1295
    } else if ((k == 0x003) || (k == 0x018)) { /* CTRL+C or CTRL+X */
1295
    } else if ((k == 0x003) || (k == 0x018)) { /* CTRL+C or CTRL+X */
1296
      /* free clipboard if anything in it */
1296
      /* free clipboard if anything in it */
1297
      if (clipboard != NULL) line_free(clipboard);
1297
      if (clipboard != NULL) line_free(clipboard);
1298
 
1298
 
1299
      /* copy cursor line to clipboard */
1299
      /* copy cursor line to clipboard */
1300
      clipboard = line_calloc(db->cursor->len);
1300
      clipboard = line_calloc(db->cursor->len);
1301
      if (clipboard == NULL) {
1301
      if (clipboard == NULL) {
1302
        ui_msg(10, 0, 0, SCHEME_ERR); /* ERROR */
1302
        ui_msg(10, 0, 0, SCHEME_ERR); /* ERROR */
1303
        mdr_bios_tickswait(18); /* 1s */
1303
        mdr_bios_tickswait(18); /* 1s */
1304
      } else {
1304
      } else {
1305
        mdr_cout_char_rep(db->cursorposy, 0, ' ', ((SCHEME_TEXT >> 4) | (SCHEME_TEXT << 4)) & 0xff, screenlastcol);
1305
        mdr_cout_char_rep(db->cursorposy, 0, ' ', ((SCHEME_TEXT >> 4) | (SCHEME_TEXT << 4)) & 0xff, screenlastcol);
1306
        uidirty.from = db->cursorposy;
1306
        uidirty.from = db->cursorposy;
1307
        uidirty.to = db->cursorposy;
1307
        uidirty.to = db->cursorposy;
1308
        if (db->cursor->len != 0) {
1308
        if (db->cursor->len != 0) {
1309
          _fmemmove(clipboard->payload, db->cursor->payload, db->cursor->len);
1309
          fmemmove(clipboard->payload, db->cursor->payload, db->cursor->len);
1310
          clipboard->len = db->cursor->len;
1310
          clipboard->len = db->cursor->len;
1311
        }
1311
        }
1312
        mdr_bios_tickswait(2); /* ca 100ms */
1312
        mdr_bios_tickswait(2); /* ca 100ms */
1313
 
1313
 
1314
        /* if this is about cutting the line (CTRL+X) then delete cur line */
1314
        /* if this is about cutting the line (CTRL+X) then delete cur line */
1315
        if ((k == 0x018) && ((db->cursor->next != NULL) || (db->cursor->prev != NULL))) {
1315
        if ((k == 0x018) && ((db->cursor->next != NULL) || (db->cursor->prev != NULL))) {
1316
          if (db->cursor->next) db->cursor->next->prev = db->cursor->prev;
1316
          if (db->cursor->next) db->cursor->next->prev = db->cursor->prev;
1317
          if (db->cursor->prev) db->cursor->prev->next = db->cursor->next;
1317
          if (db->cursor->prev) db->cursor->prev->next = db->cursor->next;
1318
          clipboard->prev = db->cursor;
1318
          clipboard->prev = db->cursor;
1319
          if (db->cursor->next) {
1319
          if (db->cursor->next) {
1320
            db->cursor = db->cursor->next;
1320
            db->cursor = db->cursor->next;
1321
          } else {
1321
          } else {
1322
            cursor_up(db);
1322
            cursor_up(db);
1323
          }
1323
          }
1324
          line_free(clipboard->prev);
1324
          line_free(clipboard->prev);
1325
          db->totlines -= 1;
1325
          db->totlines -= 1;
1326
          db->modflag = 1;
1326
          db->modflag = 1;
1327
          uidirty.from = 0;
1327
          uidirty.from = 0;
1328
          uidirty.to = 0xff;
1328
          uidirty.to = 0xff;
1329
          recompute_curline(db);
1329
          recompute_curline(db);
1330
        }
1330
        }
1331
      }
1331
      }
1332
 
1332
 
1333
    } else if ((k == 0x016) && (clipboard != NULL)) { /* CTRL+V */
1333
    } else if ((k == 0x016) && (clipboard != NULL)) { /* CTRL+V */
1334
      if (line_add(db, clipboard->payload, clipboard->len) != 0) {
1334
      if (line_add(db, clipboard->payload, clipboard->len) != 0) {
1335
        ui_msg(10, 0, 0, SCHEME_ERR); /* ERROR */
1335
        ui_msg(10, 0, 0, SCHEME_ERR); /* ERROR */
1336
        mdr_bios_tickswait(18); /* 1s */
1336
        mdr_bios_tickswait(18); /* 1s */
1337
      } else {
1337
      } else {
1338
        /* rewire the linked list so the new line is on top of the previous one */
1338
        /* rewire the linked list so the new line is on top of the previous one */
1339
        clipboard->prev = db->cursor->prev;
1339
        clipboard->prev = db->cursor->prev;
1340
        /* remove prev node from list */
1340
        /* remove prev node from list */
1341
        db->cursor->prev = db->cursor->prev->prev;
1341
        db->cursor->prev = db->cursor->prev->prev;
1342
        if (db->cursor->prev != NULL) db->cursor->prev->next = db->cursor;
1342
        if (db->cursor->prev != NULL) db->cursor->prev->next = db->cursor;
1343
        /* insert the node after cursor now */
1343
        /* insert the node after cursor now */
1344
        clipboard->prev->next = db->cursor->next;
1344
        clipboard->prev->next = db->cursor->next;
1345
        if (db->cursor->next != NULL) db->cursor->next->prev = clipboard->prev;
1345
        if (db->cursor->next != NULL) db->cursor->next->prev = clipboard->prev;
1346
        clipboard->prev->prev = db->cursor;
1346
        clipboard->prev->prev = db->cursor;
1347
        db->cursor->next = clipboard->prev;
1347
        db->cursor->next = clipboard->prev;
1348
        cursor_down(db);
1348
        cursor_down(db);
1349
        db->modflag = 1;
1349
        db->modflag = 1;
1350
      }
1350
      }
1351
      uidirty.from = 0;
1351
      uidirty.from = 0;
1352
      uidirty.to = 0xff;
1352
      uidirty.to = 0xff;
1353
      recompute_curline(db);
1353
      recompute_curline(db);
1354
 
1354
 
1355
#ifdef DBG_UNHKEYS
1355
#ifdef DBG_UNHKEYS
1356
    } else { /* UNHANDLED KEY - TODO IGNORE THIS IN PRODUCTION RELEASE */
1356
    } else { /* UNHANDLED KEY - TODO IGNORE THIS IN PRODUCTION RELEASE */
1357
      char buff[4];
1357
      char buff[4];
1358
      const char *HEX = "0123456789ABCDEF";
1358
      const char *HEX = "0123456789ABCDEF";
1359
      buff[0] = HEX[(k >> 8) & 15];
1359
      buff[0] = HEX[(k >> 8) & 15];
1360
      buff[1] = HEX[(k >> 4) & 15];
1360
      buff[1] = HEX[(k >> 4) & 15];
1361
      buff[2] = HEX[k & 15];
1361
      buff[2] = HEX[k & 15];
1362
      mdr_cout_str(screenh - 1, 0, "UNHANDLED KEY: 0x", SCHEME_STBAR1, 17);
1362
      mdr_cout_str(screenh - 1, 0, "UNHANDLED KEY: 0x", SCHEME_STBAR1, 17);
1363
      mdr_cout_str(screenh - 1, 17, buff, SCHEME_STBAR1, 3);
1363
      mdr_cout_str(screenh - 1, 17, buff, SCHEME_STBAR1, 3);
1364
      mdr_dos_getkey2();
1364
      mdr_dos_getkey2();
1365
      break;
1365
      break;
1366
#endif
1366
#endif
1367
    }
1367
    }
1368
  }
1368
  }
1369
 
1369
 
1370
  mdr_cout_close();
1370
  mdr_cout_close();
1371
 
1371
 
1372
  /* restore the DOS BREAK flag if it was originally set */
1372
  /* restore the DOS BREAK flag if it was originally set */
1373
  if (original_breakflag != 0) mdr_dos_ctrlc_enable();
1373
  if (original_breakflag != 0) mdr_dos_ctrlc_enable();
1374
 
1374
 
1375
  /* no need to free memory, DOS will do it for me */
1375
  /* no need to free memory, DOS will do it for me */
1376
 
1376
 
1377
  return;
1377
  return;
1378
}
1378
}
1379
 
1379