Subversion Repositories SvarDOS

Rev

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

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