Subversion Repositories SvarDOS

Rev

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

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