Subversion Repositories SvarDOS

Rev

Rev 1320 | Rev 1322 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1320 Rev 1321
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 <dos.h>
26
#include <dos.h>
27
#include <fcntl.h>
27
#include <fcntl.h>
28
#include <stdlib.h>
28
#include <stdlib.h>
29
#include <string.h>
29
#include <string.h>
30
#include <malloc.h>   /* _fcalloc() */
30
#include <malloc.h>   /* _fcalloc() */
31
 
31
 
32
#include "mdr\bios.h"
32
#include "mdr\bios.h"
33
#include "mdr\cout.h"
33
#include "mdr\cout.h"
34
#include "mdr\dos.h"
34
#include "mdr\dos.h"
35
#include "mdr\keyb.h"
35
#include "mdr\keyb.h"
36
 
36
 
37
#include "svarlang\svarlang.h"
37
#include "svarlang\svarlang.h"
38
 
38
 
39
#define COL_TXT        0
39
#define COL_TXT        0
40
#define COL_STATUSBAR1 1
40
#define COL_STATUSBAR1 1
41
#define COL_STATUSBAR2 2
41
#define COL_STATUSBAR2 2
42
#define COL_SCROLLBAR  3
42
#define COL_SCROLLBAR  3
43
/* preload the mono scheme (to be overloaded at runtime if color adapter present) */
43
/* preload the mono scheme (to be overloaded at runtime if color adapter present) */
44
static unsigned char scheme[] = {0x07, 0x70, 0x70, 0x70};
44
static unsigned char scheme[] = {0x07, 0x70, 0x70, 0x70};
45
 
45
 
46
#define SCROLL_CURSOR 0xB1
46
#define SCROLL_CURSOR 0xB1
47
 
47
 
48
 
48
 
49
struct line {
49
struct line {
50
  struct line far *prev;
50
  struct line far *prev;
51
  struct line far *next;
51
  struct line far *next;
52
  unsigned short len;
52
  unsigned short len;
53
  char payload[1];
53
  char payload[1];
54
};
54
};
55
 
55
 
56
struct file {
56
struct file {
57
  int fd;
57
  int fd;
58
  struct line far *cursor;
58
  struct line far *cursor;
59
  unsigned short xoffset;
59
  unsigned short xoffset;
60
  unsigned char cursorposx;
60
  unsigned char cursorposx;
61
  unsigned char cursorposy;
61
  unsigned char cursorposy;
62
  char lfonly; /* set if line endings are LF (CR/LF otherwise) */
62
  char lfonly; /* set if line endings are LF (CR/LF otherwise) */
63
  char fname[1]; /* dynamically sized */
63
  char fname[1]; /* dynamically sized */
64
};
64
};
65
 
65
 
66
 
66
 
67
/* returns non-zero on error */
67
/* returns non-zero on error */
68
static int line_add(struct file *db, const char far *line) {
68
static int line_add(struct file *db, const char far *line) {
69
  unsigned short slen;
69
  unsigned short slen;
70
  struct line far *l;
70
  struct line far *l;
71
 
71
 
72
  /* slen = strlen(line) (but for far pointer) */
72
  /* slen = strlen(line) (but for far pointer) */
73
  for (slen = 0; line[slen] != 0; slen++);
73
  for (slen = 0; line[slen] != 0; slen++);
74
 
74
 
75
  /* trim out CR/LF line endings */
75
  /* trim out CR/LF line endings */
76
  if ((slen >= 2) && (line[slen - 2] == '\r')) {
76
  if ((slen >= 2) && (line[slen - 2] == '\r')) {
77
    slen -= 2;
77
    slen -= 2;
78
  } else if ((slen >= 1) && (line[slen - 1] == '\n')) {
78
  } else if ((slen >= 1) && (line[slen - 1] == '\n')) {
79
    slen--;
79
    slen--;
80
  }
80
  }
81
 
81
 
82
  l = _fcalloc(1, sizeof(struct line) + slen + 1);
82
  l = _fcalloc(1, sizeof(struct line) + slen + 1);
83
  if (l == NULL) return(-1);
83
  if (l == NULL) return(-1);
84
 
84
 
85
  l->prev = db->cursor;
85
  l->prev = db->cursor;
86
  if (db->cursor) {
86
  if (db->cursor) {
87
    l->next = db->cursor->next;
87
    l->next = db->cursor->next;
88
    db->cursor->next = l;
88
    db->cursor->next = l;
89
    l->next->prev = l;
89
    l->next->prev = l;
90
  }
90
  }
91
  db->cursor = l;
91
  db->cursor = l;
92
  _fmemcpy(l->payload, line, slen);
92
  _fmemcpy(l->payload, line, slen);
93
  l->len = slen;
93
  l->len = slen;
94
 
94
 
95
  return(0);
95
  return(0);
96
}
96
}
97
 
97
 
98
 
98
 
99
static void db_rewind(struct file *db) {
99
static void db_rewind(struct file *db) {
100
  if (db->cursor == NULL) return;
100
  if (db->cursor == NULL) return;
101
  while (db->cursor->prev) db->cursor = db->cursor->prev;
101
  while (db->cursor->prev) db->cursor = db->cursor->prev;
102
}
102
}
103
 
103
 
104
 
104
 
105
static void load_colorscheme(void) {
105
static void load_colorscheme(void) {
106
  scheme[COL_TXT] = 0x17;
106
  scheme[COL_TXT] = 0x17;
107
  scheme[COL_STATUSBAR1] = 0x70;
107
  scheme[COL_STATUSBAR1] = 0x70;
108
  scheme[COL_STATUSBAR2] = 0x78;
108
  scheme[COL_STATUSBAR2] = 0x78;
109
  scheme[COL_SCROLLBAR] = 0x70;
109
  scheme[COL_SCROLLBAR] = 0x70;
110
}
110
}
111
 
111
 
112
 
112
 
113
static void ui_basic(unsigned char screenw, unsigned char screenh, const struct file *db) {
113
static void ui_basic(unsigned char screenw, unsigned char screenh, const struct file *db) {
114
  unsigned char i;
114
  unsigned char i;
115
  const char *s = svarlang_strid(0); /* HELP */
115
  const char *s = svarlang_strid(0); /* HELP */
116
  unsigned char helpcol = screenw - (strlen(s) + 4);
116
  unsigned char helpcol = screenw - (strlen(s) + 4);
117
 
117
 
118
  /* fill status bar with background */
118
  /* fill status bar with background */
119
  mdr_cout_char_rep(screenh - 1, 0, ' ', scheme[COL_STATUSBAR1], screenw);
119
  mdr_cout_char_rep(screenh - 1, 0, ' ', scheme[COL_STATUSBAR1], screenw);
120
 
120
 
121
  /* filename */
121
  /* filename */
-
 
122
  if (db->fname[0] == 0) {
-
 
123
    mdr_cout_str(screenh - 1, 0, svarlang_str(0, 1), scheme[COL_STATUSBAR1], screenw);
-
 
124
  } else {
122
  mdr_cout_str(screenh - 1, 0, db->fname, scheme[COL_STATUSBAR1], screenw);
125
    mdr_cout_str(screenh - 1, 0, db->fname, scheme[COL_STATUSBAR1], screenw);
-
 
126
  }
123
 
127
 
124
  /* eol type */
128
  /* eol type */
125
  if (db->lfonly) {
129
  if (db->lfonly) {
126
    mdr_cout_str(screenh - 1, helpcol - 3, "LF", scheme[COL_STATUSBAR1], 5);
130
    mdr_cout_str(screenh - 1, helpcol - 3, "LF", scheme[COL_STATUSBAR1], 5);
127
  } else {
131
  } else {
128
    mdr_cout_str(screenh - 1, helpcol - 5, "CRLF", scheme[COL_STATUSBAR1], 5);
132
    mdr_cout_str(screenh - 1, helpcol - 5, "CRLF", scheme[COL_STATUSBAR1], 5);
129
  }
133
  }
130
 
134
 
131
  mdr_cout_str(screenh - 1, helpcol, " F1=", scheme[COL_STATUSBAR2], 40);
135
  mdr_cout_str(screenh - 1, helpcol, " F1=", scheme[COL_STATUSBAR2], 40);
132
  mdr_cout_str(screenh - 1, helpcol + 4, s, scheme[COL_STATUSBAR2], 40);
136
  mdr_cout_str(screenh - 1, helpcol + 4, s, scheme[COL_STATUSBAR2], 40);
133
 
137
 
134
  /* scroll bar */
138
  /* scroll bar */
135
  for (i = 0; i < (screenh - 1); i++) {
139
  for (i = 0; i < (screenh - 1); i++) {
136
    mdr_cout_char(i, screenw - 1, SCROLL_CURSOR, scheme[COL_SCROLLBAR]);
140
    mdr_cout_char(i, screenw - 1, SCROLL_CURSOR, scheme[COL_SCROLLBAR]);
137
  }
141
  }
138
}
142
}
139
 
143
 
140
 
144
 
141
static void ui_msg(const char *msg, unsigned char screenw, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
145
static void ui_msg(const char *msg, unsigned char screenw, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
142
  unsigned short x, y, msglen, i;
146
  unsigned short x, y, msglen, i;
143
  msglen = strlen(msg);
147
  msglen = strlen(msg);
144
  y = (screenh - 4) >> 1;
148
  y = (screenh - 4) >> 1;
145
  x = (screenw - msglen - 4) >> 1;
149
  x = (screenw - msglen - 4) >> 1;
146
  for (i = y+2; i >= y; i--) mdr_cout_char_rep(i, x, ' ', scheme[COL_STATUSBAR1], msglen + 2);
150
  for (i = y+2; i >= y; i--) mdr_cout_char_rep(i, x, ' ', scheme[COL_STATUSBAR1], msglen + 2);
147
  mdr_cout_str(y+1, x+1, msg, scheme[COL_STATUSBAR1], msglen);
151
  mdr_cout_str(y+1, x+1, msg, scheme[COL_STATUSBAR1], msglen);
148
 
152
 
149
  if (*uidirtyfrom > y) *uidirtyfrom = y;
153
  if (*uidirtyfrom > y) *uidirtyfrom = y;
150
  if (*uidirtyto < y+2) *uidirtyto = y+2;
154
  if (*uidirtyto < y+2) *uidirtyto = y+2;
151
}
155
}
152
 
156
 
153
 
157
 
154
static void ui_help(unsigned char screenw) {
158
static void ui_help(unsigned char screenw) {
155
#define MAXLINLEN 35
159
#define MAXLINLEN 35
156
  unsigned short i, offset;
160
  unsigned short i, offset;
157
  offset = (screenw - MAXLINLEN + 1) >> 1;
161
  offset = (screenw - MAXLINLEN + 1) >> 1;
158
  mdr_cout_cursor_hide();
162
  mdr_cout_cursor_hide();
159
  for (i = 2; i <= 12; i++) {
163
  for (i = 2; i <= 12; i++) {
160
    mdr_cout_char_rep(i, offset - 2, ' ', scheme[COL_STATUSBAR1], MAXLINLEN);
164
    mdr_cout_char_rep(i, offset - 2, ' ', scheme[COL_STATUSBAR1], MAXLINLEN);
161
  }
165
  }
162
 
166
 
163
  mdr_cout_str(3, offset, svarlang_str(0, 0), scheme[COL_STATUSBAR1], MAXLINLEN);
167
  mdr_cout_str(3, offset, svarlang_str(0, 0), scheme[COL_STATUSBAR1], MAXLINLEN);
164
  for (i = 0; i <= 2; i++) {
168
  for (i = 0; i <= 2; i++) {
165
    mdr_cout_str(5 + i, offset, svarlang_str(8, i), scheme[COL_STATUSBAR1], MAXLINLEN);
169
    mdr_cout_str(5 + i, offset, svarlang_str(8, i), scheme[COL_STATUSBAR1], MAXLINLEN);
166
  }
170
  }
167
  mdr_cout_str(9, offset, svarlang_str(8, 10), scheme[COL_STATUSBAR1], MAXLINLEN);
171
  mdr_cout_str(9, offset, svarlang_str(8, 10), scheme[COL_STATUSBAR1], MAXLINLEN);
168
  mdr_cout_str(11, offset, svarlang_str(8, 11), scheme[COL_STATUSBAR1], MAXLINLEN);
172
  mdr_cout_str(11, offset, svarlang_str(8, 11), scheme[COL_STATUSBAR1], MAXLINLEN);
169
 
173
 
170
  keyb_getkey();
174
  keyb_getkey();
171
  mdr_cout_cursor_show();
175
  mdr_cout_cursor_show();
172
#undef MAXLINLEN
176
#undef MAXLINLEN
173
}
177
}
174
 
178
 
175
 
179
 
176
static void ui_refresh(const struct file *db, unsigned char screenw, unsigned char screenh, unsigned char uidirtyfrom, unsigned char uidirtyto) {
180
static void ui_refresh(const struct file *db, unsigned char screenw, unsigned char screenh, unsigned char uidirtyfrom, unsigned char uidirtyto) {
177
  unsigned char x;
181
  unsigned char x;
178
  const struct line far *l;
182
  const struct line far *l;
179
  unsigned char y = db->cursorposy;
183
  unsigned char y = db->cursorposy;
180
 
184
 
181
#ifdef DBG_REFRESH
185
#ifdef DBG_REFRESH
182
  static char m = 'a';
186
  static char m = 'a';
183
  m++;
187
  m++;
184
  if (m > 'z') m = 'a';
188
  if (m > 'z') m = 'a';
185
#endif
189
#endif
186
 
190
 
187
  /* rewind cursor line to first line that needs redrawing */
191
  /* rewind cursor line to first line that needs redrawing */
188
  for (l = db->cursor; y > uidirtyfrom; y--) l = l->prev;
192
  for (l = db->cursor; y > uidirtyfrom; y--) l = l->prev;
189
 
193
 
190
  /* iterate over lines and redraw whatever needs to be redrawn */
194
  /* iterate over lines and redraw whatever needs to be redrawn */
191
  for (; l != NULL; l = l->next, y++) {
195
  for (; l != NULL; l = l->next, y++) {
192
 
196
 
193
    /* skip lines that do not need to be refreshed */
197
    /* skip lines that do not need to be refreshed */
194
    if (y < uidirtyfrom) continue;
198
    if (y < uidirtyfrom) continue;
195
    if (y > uidirtyto) break;
199
    if (y > uidirtyto) break;
196
 
200
 
197
    x = 0;
201
    x = 0;
198
    if (db->xoffset < l->len) {
202
    if (db->xoffset < l->len) {
199
      unsigned char i, limit;
203
      unsigned char i, limit;
200
      if (l->len - db->xoffset < screenw) {
204
      if (l->len - db->xoffset < screenw) {
201
        limit = l->len;
205
        limit = l->len;
202
      } else {
206
      } else {
203
        limit = db->xoffset + screenw - 1;
207
        limit = db->xoffset + screenw - 1;
204
      }
208
      }
205
      for (i = db->xoffset; i < limit; i++) mdr_cout_char(y, x++, l->payload[i], scheme[COL_TXT]);
209
      for (i = db->xoffset; i < limit; i++) mdr_cout_char(y, x++, l->payload[i], scheme[COL_TXT]);
206
    }
210
    }
207
 
211
 
208
    /* write empty spaces until end of line */
212
    /* write empty spaces until end of line */
209
    if (x < screenw - 1) mdr_cout_char_rep(y, x, ' ', scheme[COL_TXT], screenw - 1 - x);
213
    if (x < screenw - 1) mdr_cout_char_rep(y, x, ' ', scheme[COL_TXT], screenw - 1 - x);
210
 
214
 
211
#ifdef DBG_REFRESH
215
#ifdef DBG_REFRESH
212
    mdr_cout_char(y, 0, m, scheme[COL_STATUSBAR1]);
216
    mdr_cout_char(y, 0, m, scheme[COL_STATUSBAR1]);
213
#endif
217
#endif
214
 
218
 
215
    if (y == screenh - 2) break;
219
    if (y == screenh - 2) break;
216
  }
220
  }
217
 
221
 
218
  /* fill all lines below if empty (and they need to be redrawn) */
222
  /* fill all lines below if empty (and they need to be redrawn) */
219
  if (l == NULL) {
223
  if (l == NULL) {
220
    while ((y < screenh - 1) && (y < uidirtyto)) {
224
    while ((y < screenh - 1) && (y < uidirtyto)) {
221
      mdr_cout_char_rep(y++, 0, ' ', scheme[COL_TXT], screenw - 1);
225
      mdr_cout_char_rep(y++, 0, ' ', scheme[COL_TXT], screenw - 1);
222
    }
226
    }
223
  }
227
  }
224
}
228
}
225
 
229
 
226
 
230
 
227
static void check_cursor_not_after_eol(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
231
static void check_cursor_not_after_eol(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
228
  if (db->xoffset + db->cursorposx <= db->cursor->len) return;
232
  if (db->xoffset + db->cursorposx <= db->cursor->len) return;
229
 
233
 
230
  if (db->cursor->len < db->xoffset) {
234
  if (db->cursor->len < db->xoffset) {
231
    db->cursorposx = 0;
235
    db->cursorposx = 0;
232
    db->xoffset = db->cursor->len;
236
    db->xoffset = db->cursor->len;
233
    *uidirtyfrom = 0;
237
    *uidirtyfrom = 0;
234
    *uidirtyto = 0xff;
238
    *uidirtyto = 0xff;
235
  } else {
239
  } else {
236
    db->cursorposx = db->cursor->len - db->xoffset;
240
    db->cursorposx = db->cursor->len - db->xoffset;
237
  }
241
  }
238
}
242
}
239
 
243
 
240
 
244
 
241
static void cursor_up(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
245
static void cursor_up(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
242
  if (db->cursor->prev != NULL) {
246
  if (db->cursor->prev != NULL) {
243
    db->cursor = db->cursor->prev;
247
    db->cursor = db->cursor->prev;
244
    if (db->cursorposy == 0) {
248
    if (db->cursorposy == 0) {
245
      *uidirtyfrom = 0;
249
      *uidirtyfrom = 0;
246
      *uidirtyto = 0xff;
250
      *uidirtyto = 0xff;
247
    } else {
251
    } else {
248
      db->cursorposy -= 1;
252
      db->cursorposy -= 1;
249
    }
253
    }
250
  }
254
  }
251
}
255
}
252
 
256
 
253
 
257
 
254
static void cursor_eol(struct file *db, unsigned char screenw, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
258
static void cursor_eol(struct file *db, unsigned char screenw, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
255
  /* adjust xoffset to make sure eol is visible on screen */
259
  /* adjust xoffset to make sure eol is visible on screen */
256
  if (db->xoffset > db->cursor->len) {
260
  if (db->xoffset > db->cursor->len) {
257
    db->xoffset = db->cursor->len - 1;
261
    db->xoffset = db->cursor->len - 1;
258
    *uidirtyfrom = 0;
262
    *uidirtyfrom = 0;
259
    *uidirtyto = 0xff;
263
    *uidirtyto = 0xff;
260
  }
264
  }
261
 
265
 
262
  if (db->xoffset + screenw - 1 <= db->cursor->len) {
266
  if (db->xoffset + screenw - 1 <= db->cursor->len) {
263
    db->xoffset = db->cursor->len - screenw + 2;
267
    db->xoffset = db->cursor->len - screenw + 2;
264
    *uidirtyfrom = 0;
268
    *uidirtyfrom = 0;
265
    *uidirtyto = 0xff;
269
    *uidirtyto = 0xff;
266
  }
270
  }
267
  db->cursorposx = db->cursor->len - db->xoffset;
271
  db->cursorposx = db->cursor->len - db->xoffset;
268
}
272
}
269
 
273
 
270
 
274
 
271
static void cursor_down(struct file *db, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
275
static void cursor_down(struct file *db, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
272
  if (db->cursor->next != NULL) {
276
  if (db->cursor->next != NULL) {
273
    db->cursor = db->cursor->next;
277
    db->cursor = db->cursor->next;
274
    if (db->cursorposy < screenh - 2) {
278
    if (db->cursorposy < screenh - 2) {
275
      db->cursorposy += 1;
279
      db->cursorposy += 1;
276
    } else {
280
    } else {
277
      *uidirtyfrom = 0;
281
      *uidirtyfrom = 0;
278
      *uidirtyto = 0xff;
282
      *uidirtyto = 0xff;
279
    }
283
    }
280
  }
284
  }
281
}
285
}
282
 
286
 
283
 
287
 
284
static void cursor_left(struct file *db, unsigned char screenw, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
288
static void cursor_left(struct file *db, unsigned char screenw, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
285
  if (db->cursorposx > 0) {
289
  if (db->cursorposx > 0) {
286
    db->cursorposx -= 1;
290
    db->cursorposx -= 1;
287
  } else if (db->xoffset > 0) {
291
  } else if (db->xoffset > 0) {
288
    db->xoffset -= 1;
292
    db->xoffset -= 1;
289
    *uidirtyfrom = 0;
293
    *uidirtyfrom = 0;
290
    *uidirtyto = 0xff;
294
    *uidirtyto = 0xff;
291
  } else if (db->cursor->prev != NULL) { /* jump to end of line above */
295
  } else if (db->cursor->prev != NULL) { /* jump to end of line above */
292
    cursor_up(db, uidirtyfrom, uidirtyto);
296
    cursor_up(db, uidirtyfrom, uidirtyto);
293
    cursor_eol(db, screenw, uidirtyfrom, uidirtyto);
297
    cursor_eol(db, screenw, uidirtyfrom, uidirtyto);
294
  }
298
  }
295
}
299
}
296
 
300
 
297
 
301
 
298
static void cursor_home(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
302
static void cursor_home(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
299
  db->cursorposx = 0;
303
  db->cursorposx = 0;
300
  if (db->xoffset != 0) {
304
  if (db->xoffset != 0) {
301
    db->xoffset = 0;
305
    db->xoffset = 0;
302
    *uidirtyfrom = 0;
306
    *uidirtyfrom = 0;
303
    *uidirtyto = 0xff;
307
    *uidirtyto = 0xff;
304
  }
308
  }
305
}
309
}
306
 
310
 
307
 
311
 
308
static void cursor_right(struct file *db, unsigned char screenw, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
312
static void cursor_right(struct file *db, unsigned char screenw, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
309
  if (db->cursor->len > db->xoffset + db->cursorposx) {
313
  if (db->cursor->len > db->xoffset + db->cursorposx) {
310
    if (db->cursorposx < screenw - 2) {
314
    if (db->cursorposx < screenw - 2) {
311
      db->cursorposx += 1;
315
      db->cursorposx += 1;
312
    } else {
316
    } else {
313
      db->xoffset += 1;
317
      db->xoffset += 1;
314
      *uidirtyfrom = 0;
318
      *uidirtyfrom = 0;
315
      *uidirtyto = 0xff;
319
      *uidirtyto = 0xff;
316
    }
320
    }
317
  } else {
321
  } else {
318
    cursor_down(db, screenh, uidirtyfrom, uidirtyto);
322
    cursor_down(db, screenh, uidirtyfrom, uidirtyto);
319
    cursor_home(db, uidirtyfrom, uidirtyto);
323
    cursor_home(db, uidirtyfrom, uidirtyto);
320
  }
324
  }
321
}
325
}
322
 
326
 
323
 
327
 
324
static void del(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
328
static void del(struct file *db, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
325
  if (db->cursorposx + db->xoffset < db->cursor->len) {
329
  if (db->cursorposx + db->xoffset < db->cursor->len) {
326
    _fmemmove(db->cursor->payload + db->cursorposx + db->xoffset, db->cursor->payload + db->cursorposx + db->xoffset + 1, db->cursor->len - db->cursorposx - db->xoffset);
330
    _fmemmove(db->cursor->payload + db->cursorposx + db->xoffset, db->cursor->payload + db->cursorposx + db->xoffset + 1, db->cursor->len - db->cursorposx - db->xoffset);
327
    db->cursor->len -= 1; /* do this AFTER memmove so the copy includes the nul terminator */
331
    db->cursor->len -= 1; /* do this AFTER memmove so the copy includes the nul terminator */
328
    *uidirtyfrom = db->cursorposy;
332
    *uidirtyfrom = db->cursorposy;
329
    *uidirtyto = db->cursorposy;
333
    *uidirtyto = db->cursorposy;
330
  } else if (db->cursor->next != NULL) { /* cursor is at end of line: merge current line with next one (if there is a next one) */
334
  } else if (db->cursor->next != NULL) { /* cursor is at end of line: merge current line with next one (if there is a next one) */
331
    struct line far *nextline = db->cursor->next;
335
    struct line far *nextline = db->cursor->next;
332
    if (db->cursor->next->len > 0) {
336
    if (db->cursor->next->len > 0) {
333
      void far *newptr = _frealloc(db->cursor, sizeof(struct line) + db->cursor->len + db->cursor->next->len + 1);
337
      void far *newptr = _frealloc(db->cursor, sizeof(struct line) + db->cursor->len + db->cursor->next->len + 1);
334
      if (newptr != NULL) {
338
      if (newptr != NULL) {
335
        db->cursor = newptr;
339
        db->cursor = newptr;
336
        _fmemcpy(db->cursor->payload + db->cursor->len, db->cursor->next->payload, db->cursor->next->len + 1);
340
        _fmemcpy(db->cursor->payload + db->cursor->len, db->cursor->next->payload, db->cursor->next->len + 1);
337
        db->cursor->len += db->cursor->next->len;
341
        db->cursor->len += db->cursor->next->len;
338
      }
342
      }
339
    }
343
    }
340
    db->cursor->next = db->cursor->next->next;
344
    db->cursor->next = db->cursor->next->next;
341
    db->cursor->next->prev = db->cursor;
345
    db->cursor->next->prev = db->cursor;
342
    if (db->cursor->prev != NULL) db->cursor->prev->next = db->cursor; /* in case realloc changed my pointer */
346
    if (db->cursor->prev != NULL) db->cursor->prev->next = db->cursor; /* in case realloc changed my pointer */
343
    _ffree(nextline);
347
    _ffree(nextline);
344
    *uidirtyfrom = db->cursorposy;
348
    *uidirtyfrom = db->cursorposy;
345
    *uidirtyto = 0xff;
349
    *uidirtyto = 0xff;
346
  }
350
  }
347
}
351
}
348
 
352
 
349
 
353
 
350
static void bkspc(struct file *db, unsigned char screenw, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
354
static void bkspc(struct file *db, unsigned char screenw, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
351
 
355
 
352
  /* backspace is basically "left + del", not applicable only if cursor is on 1st byte of the file */
356
  /* backspace is basically "left + del", not applicable only if cursor is on 1st byte of the file */
353
  if ((db->cursorposx == 0) && (db->xoffset == 0) && (db->cursor->prev == NULL)) return;
357
  if ((db->cursorposx == 0) && (db->xoffset == 0) && (db->cursor->prev == NULL)) return;
354
 
358
 
355
  cursor_left(db, screenw, uidirtyfrom, uidirtyto);
359
  cursor_left(db, screenw, uidirtyfrom, uidirtyto);
356
  del(db, uidirtyfrom, uidirtyto);
360
  del(db, uidirtyfrom, uidirtyto);
357
}
361
}
358
 
362
 
359
 
363
 
360
/* a custom argv-parsing routine that looks directly inside the PSP, avoids the need
364
/* a custom argv-parsing routine that looks directly inside the PSP, avoids the need
361
 * of argc and argv, saves some 330 bytes of binary size */
365
 * of argc and argv, saves some 330 bytes of binary size */
362
static char *parseargv(void) {
366
static char *parseargv(void) {
363
  char *tail = (void *)0x81; /* THIS WORKS ONLY IN SMALL MEMORY MODEL */
367
  char *tail = (void *)0x81; /* THIS WORKS ONLY IN SMALL MEMORY MODEL */
364
  unsigned char count = 0;
368
  unsigned char count = 0;
365
  char *argv[4];
369
  char *argv[4];
366
 
370
 
367
  while (count < 4) {
371
  while (count < 4) {
368
    /* jump to nearest arg */
372
    /* jump to nearest arg */
369
    while (*tail == ' ') {
373
    while (*tail == ' ') {
370
      *tail = 0;
374
      *tail = 0;
371
      tail++;
375
      tail++;
372
    }
376
    }
373
 
377
 
374
    if (*tail == '\r') {
378
    if (*tail == '\r') {
375
      *tail = 0;
379
      *tail = 0;
376
      break;
380
      break;
377
    }
381
    }
378
 
382
 
379
    argv[count++] = tail;
383
    argv[count++] = tail;
380
 
384
 
381
    /* jump to next delimiter */
385
    /* jump to next delimiter */
382
    while ((*tail != ' ') && (*tail != '\r')) tail++;
386
    while ((*tail != ' ') && (*tail != '\r')) tail++;
383
  }
387
  }
384
 
388
 
385
  /* check args now */
389
  /* check args now */
386
  if (count != 1) return(NULL);
390
  if (count == 0) return("");
387
 
391
 
388
  return(argv[0]);
392
  return(argv[0]);
389
}
393
}
390
 
394
 
391
 
395
 
392
static struct file *loadfile(const char *fname) {
396
static struct file *loadfile(const char *fname) {
393
  char buff[1024];
397
  char buff[1024];
394
  unsigned int prevlen = 0, len, llen;
398
  unsigned int prevlen = 0, len, llen;
395
  int fd;
399
  int fd;
396
  struct file *db;
400
  struct file *db;
397
 
401
 
-
 
402
  len = strlen(fname) + 1;
-
 
403
  db = calloc(1, sizeof(struct file) + len);
-
 
404
  if (db == NULL) return(NULL);
-
 
405
  memcpy(db->fname, fname, len);
-
 
406
 
-
 
407
  if (*fname == 0) goto SKIPLOADING;
-
 
408
 
398
  if (_dos_open(fname, O_RDONLY, &fd) != 0) {
409
  if (_dos_open(fname, O_RDONLY, &fd) != 0) {
399
    mdr_coutraw_puts("Failed to open file:");
410
    mdr_coutraw_puts("Failed to open file:");
400
    mdr_coutraw_puts(fname);
411
    mdr_coutraw_puts(fname);
-
 
412
    free(db);
401
    return(NULL);
413
    return(NULL);
402
  }
414
  }
403
 
415
 
404
  len = strlen(fname) + 1;
-
 
405
  db = calloc(1, sizeof(struct file) + len);
-
 
406
  if (db == NULL) {
-
 
407
    _dos_close(fd);
-
 
408
    return(NULL);
-
 
409
  }
-
 
410
  memcpy(db->fname, fname, len);
-
 
411
 
-
 
412
  db->lfonly = 1;
416
  db->lfonly = 1;
413
 
417
 
414
  do {
418
  do {
415
    if (_dos_read(fd, buff + prevlen, sizeof(buff) - prevlen, &len) == 0) {
419
    if (_dos_read(fd, buff + prevlen, sizeof(buff) - prevlen, &len) == 0) {
416
      len += prevlen;
420
      len += prevlen;
417
    } else {
421
    } else {
418
      len = prevlen;
422
      len = prevlen;
419
    }
423
    }
420
 
424
 
421
    /* look for nearest \n and replace with 0*/
425
    /* look for nearest \n and replace with 0*/
422
    for (llen = 0; buff[llen] != '\n'; llen++) {
426
    for (llen = 0; buff[llen] != '\n'; llen++) {
423
      if (llen == sizeof(buff)) { /* TODO line too long: handle it in some classy way */
427
      if (llen == sizeof(buff)) { /* TODO line too long: handle it in some classy way */
424
        break;
428
        break;
425
      }
429
      }
426
    }
430
    }
427
    buff[llen] = 0;
431
    buff[llen] = 0;
428
    if ((llen > 0) && (buff[llen - 1] == '\r')) {
432
    if ((llen > 0) && (buff[llen - 1] == '\r')) {
429
      buff[llen - 1] = 0; /* trim \r if line ending is cr/lf */
433
      buff[llen - 1] = 0; /* trim \r if line ending is cr/lf */
430
      db->lfonly = 0;
434
      db->lfonly = 0;
431
    }
435
    }
432
    if (line_add(db, buff) != 0) {
436
    if (line_add(db, buff) != 0) {
433
      mdr_coutraw_puts("out of memory");
437
      mdr_coutraw_puts("out of memory");
434
      free(db);
438
      free(db);
435
      db = NULL;
439
      db = NULL;
436
      break;
440
      break;
437
    }
441
    }
438
 
442
 
439
    len -= llen + 1;
443
    len -= llen + 1;
440
    memmove(buff, buff + llen + 1, len);
444
    memmove(buff, buff + llen + 1, len);
441
    prevlen = len;
445
    prevlen = len;
442
  } while (len > 0);
446
  } while (len > 0);
443
 
447
 
444
  _dos_close(fd);
448
  _dos_close(fd);
445
 
449
 
-
 
450
  SKIPLOADING:
-
 
451
 
446
  /* add an empty line at end if not present already, also rewind cursor to top of file */
452
  /* add an empty line at end if not present already, also rewind cursor to top of file */
447
  if (db != NULL) {
453
  if (db != NULL) {
448
    if (db->cursor->len != 0) line_add(db, "");
454
    if ((db->cursor == NULL) || (db->cursor->len != 0)) line_add(db, "");
449
    db_rewind(db);
455
    db_rewind(db);
450
  }
456
  }
451
 
457
 
452
  return(db);
458
  return(db);
453
}
459
}
454
 
460
 
455
 
461
 
456
static int savefile(const struct file *db) {
462
static int savefile(const struct file *db) {
457
  int fd;
463
  int fd;
458
  const struct line far *l;
464
  const struct line far *l;
459
  unsigned bytes;
465
  unsigned bytes;
460
  unsigned char eollen;
466
  unsigned char eollen;
461
  unsigned char eolbuf[2];
467
  unsigned char eolbuf[2];
462
 
468
 
463
  if (_dos_open(db->fname, O_WRONLY, &fd) != 0) {
469
  if (_dos_open(db->fname, O_WRONLY, &fd) != 0) {
464
    return(-1);
470
    return(-1);
465
  }
471
  }
466
 
472
 
467
  l = db->cursor;
473
  l = db->cursor;
468
  while (l->prev) l = l->prev;
474
  while (l->prev) l = l->prev;
469
 
475
 
470
  /* preset line terminators */
476
  /* preset line terminators */
471
  if (db->lfonly) {
477
  if (db->lfonly) {
472
    eolbuf[0] = '\n';
478
    eolbuf[0] = '\n';
473
    eollen = 1;
479
    eollen = 1;
474
  } else {
480
  } else {
475
    eolbuf[0] = '\r';
481
    eolbuf[0] = '\r';
476
    eolbuf[1] = '\n';
482
    eolbuf[1] = '\n';
477
    eollen = 2;
483
    eollen = 2;
478
  }
484
  }
479
 
485
 
480
  while (l) {
486
  while (l) {
481
    _dos_write(fd, l->payload, l->len, &bytes);
487
    _dos_write(fd, l->payload, l->len, &bytes);
482
    _dos_write(fd, eolbuf, eollen, &bytes);
488
    _dos_write(fd, eolbuf, eollen, &bytes);
483
    l = l->next;
489
    l = l->next;
484
  }
490
  }
485
 
491
 
486
  _dos_close(fd);
492
  _dos_close(fd);
487
  return(0);
493
  return(0);
488
}
494
}
489
 
495
 
490
 
496
 
491
static void insert_in_line(struct file *db, const char *databuf, unsigned short len, unsigned char screenw, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
497
static void insert_in_line(struct file *db, const char *databuf, unsigned short len, unsigned char screenw, unsigned char screenh, unsigned char *uidirtyfrom, unsigned char *uidirtyto) {
492
  struct line far *n;
498
  struct line far *n;
493
  n = _frealloc(db->cursor, sizeof(struct line) + db->cursor->len + len);
499
  n = _frealloc(db->cursor, sizeof(struct line) + db->cursor->len + len);
494
  if (n != NULL) {
500
  if (n != NULL) {
495
    unsigned short off = db->xoffset + db->cursorposx;
501
    unsigned short off = db->xoffset + db->cursorposx;
496
    if (n->prev) n->prev->next = n;
502
    if (n->prev) n->prev->next = n;
497
    if (n->next) n->next->prev = n;
503
    if (n->next) n->next->prev = n;
498
    db->cursor = n;
504
    db->cursor = n;
499
    _fmemmove(db->cursor->payload + off + len, db->cursor->payload + off, db->cursor->len - off + 1);
505
    _fmemmove(db->cursor->payload + off + len, db->cursor->payload + off, db->cursor->len - off + 1);
500
    db->cursor->len += len;
506
    db->cursor->len += len;
501
    *uidirtyfrom = db->cursorposy;
507
    *uidirtyfrom = db->cursorposy;
502
    *uidirtyto = db->cursorposy;
508
    *uidirtyto = db->cursorposy;
503
    while (len--) {
509
    while (len--) {
504
      db->cursor->payload[off++] = *databuf;
510
      db->cursor->payload[off++] = *databuf;
505
      databuf++;
511
      databuf++;
506
      cursor_right(db, screenw, screenh, uidirtyfrom, uidirtyto);
512
      cursor_right(db, screenw, screenh, uidirtyfrom, uidirtyto);
507
    }
513
    }
508
  }
514
  }
509
}
515
}
510
 
516
 
511
 
517
 
512
int main(void) {
518
int main(void) {
513
  const char *fname;
519
  const char *fname;
514
  struct file *db;
520
  struct file *db;
515
  unsigned char screenw = 0, screenh = 0;
521
  unsigned char screenw = 0, screenh = 0;
516
  unsigned char uidirtyfrom = 0, uidirtyto = 0xff; /* make sure to redraw entire UI at first run */
522
  unsigned char uidirtyfrom = 0, uidirtyto = 0xff; /* make sure to redraw entire UI at first run */
517
 
523
 
518
  {
524
  {
519
    char nlspath[128], lang[8];
525
    char nlspath[128], lang[8];
520
    svarlang_autoload_pathlist("sved", mdr_dos_getenv(nlspath, "NLSPATH", sizeof(nlspath)), mdr_dos_getenv(lang, "LANG", sizeof(lang)));
526
    svarlang_autoload_pathlist("sved", mdr_dos_getenv(nlspath, "NLSPATH", sizeof(nlspath)), mdr_dos_getenv(lang, "LANG", sizeof(lang)));
521
  }
527
  }
522
 
528
 
523
  fname = parseargv();
529
  fname = parseargv();
524
 
530
 
525
  if (fname == NULL) {
531
  if (fname == NULL) {
526
    mdr_coutraw_puts(svarlang_str(1,0)); /* usage: sved file.txt */
532
    mdr_coutraw_puts(svarlang_str(1,0)); /* usage: sved file.txt */
527
    return(0);
533
    return(0);
528
  }
534
  }
529
 
535
 
530
  /* load file */
536
  /* load file */
531
  db = loadfile(fname);
537
  db = loadfile(fname);
532
  if (db == NULL) return(1);
538
  if (db == NULL) return(1);
533
 
539
 
534
  if (mdr_cout_init(&screenw, &screenh)) load_colorscheme();
540
  if (mdr_cout_init(&screenw, &screenh)) load_colorscheme();
535
  ui_basic(screenw, screenh, db);
541
  ui_basic(screenw, screenh, db);
536
 
542
 
537
  for (;;) {
543
  for (;;) {
538
    int k;
544
    int k;
539
 
545
 
540
    check_cursor_not_after_eol(db, &uidirtyfrom, &uidirtyto);
546
    check_cursor_not_after_eol(db, &uidirtyfrom, &uidirtyto);
541
    mdr_cout_locate(db->cursorposy, db->cursorposx);
547
    mdr_cout_locate(db->cursorposy, db->cursorposx);
542
 
548
 
543
    if (uidirtyfrom != 0xff) {
549
    if (uidirtyfrom != 0xff) {
544
      ui_refresh(db, screenw, screenh, uidirtyfrom, uidirtyto);
550
      ui_refresh(db, screenw, screenh, uidirtyfrom, uidirtyto);
545
      uidirtyfrom = 0xff;
551
      uidirtyfrom = 0xff;
546
    }
552
    }
547
 
553
 
548
    k = keyb_getkey();
554
    k = keyb_getkey();
549
 
555
 
550
    if (k == 0x150) { /* down */
556
    if (k == 0x150) { /* down */
551
      cursor_down(db, screenh, &uidirtyfrom, &uidirtyto);
557
      cursor_down(db, screenh, &uidirtyfrom, &uidirtyto);
552
 
558
 
553
    } else if (k == 0x148) { /* up */
559
    } else if (k == 0x148) { /* up */
554
      cursor_up(db, &uidirtyfrom, &uidirtyto);
560
      cursor_up(db, &uidirtyfrom, &uidirtyto);
555
 
561
 
556
    } else if (k == 0x14D) { /* right */
562
    } else if (k == 0x14D) { /* right */
557
      cursor_right(db, screenw, screenh, &uidirtyfrom, &uidirtyto);
563
      cursor_right(db, screenw, screenh, &uidirtyfrom, &uidirtyto);
558
 
564
 
559
    } else if (k == 0x14B) { /* left */
565
    } else if (k == 0x14B) { /* left */
560
      cursor_left(db, screenw, &uidirtyfrom, &uidirtyto);
566
      cursor_left(db, screenw, &uidirtyfrom, &uidirtyto);
561
 
567
 
562
    } else if (k == 0x149) { /* pgup */
568
    } else if (k == 0x149) { /* pgup */
563
      // TODO
569
      // TODO
564
 
570
 
565
    } else if (k == 0x151) { /* pgdown */
571
    } else if (k == 0x151) { /* pgdown */
566
      // TODO
572
      // TODO
567
 
573
 
568
    } else if (k == 0x147) { /* home */
574
    } else if (k == 0x147) { /* home */
569
       cursor_home(db, &uidirtyfrom, &uidirtyto);
575
       cursor_home(db, &uidirtyfrom, &uidirtyto);
570
 
576
 
571
    } else if (k == 0x14F) { /* end */
577
    } else if (k == 0x14F) { /* end */
572
       cursor_eol(db, screenw, &uidirtyfrom, &uidirtyto);
578
       cursor_eol(db, screenw, &uidirtyfrom, &uidirtyto);
573
 
579
 
574
    } else if (k == 0x1B) { /* ESC */
580
    } else if (k == 0x1B) { /* ESC */
575
      break;
581
      break;
576
 
582
 
577
    } else if (k == 0x0D) { /* ENTER */
583
    } else if (k == 0x0D) { /* ENTER */
578
      /* add a new line */
584
      /* add a new line */
579
      if (line_add(db, db->cursor->payload + db->xoffset + db->cursorposx) == 0) {
585
      if (line_add(db, db->cursor->payload + db->xoffset + db->cursorposx) == 0) {
580
        /* trim the line above */
586
        /* trim the line above */
581
        db->cursor->prev->len = db->xoffset + db->cursorposx;
587
        db->cursor->prev->len = db->xoffset + db->cursorposx;
582
        db->cursor->prev->payload[db->cursor->prev->len] = 0;
588
        db->cursor->prev->payload[db->cursor->prev->len] = 0;
583
        /* move cursor to the (new) line below */
589
        /* move cursor to the (new) line below */
584
        db->cursorposx = 0;
590
        db->cursorposx = 0;
585
        if (db->cursorposy < screenh - 2) {
591
        if (db->cursorposy < screenh - 2) {
586
          uidirtyfrom = db->cursorposy;
592
          uidirtyfrom = db->cursorposy;
587
          db->cursorposy++;
593
          db->cursorposy++;
588
        } else {
594
        } else {
589
          uidirtyfrom = 0;
595
          uidirtyfrom = 0;
590
        }
596
        }
591
        uidirtyto = 0xff;
597
        uidirtyto = 0xff;
592
      } else {
598
      } else {
593
        /* ERROR: OUT OF MEMORY */
599
        /* ERROR: OUT OF MEMORY */
594
      }
600
      }
595
 
601
 
596
    } else if (k == 0x153) {  /* DEL */
602
    } else if (k == 0x153) {  /* DEL */
597
      del(db, &uidirtyfrom, &uidirtyto);
603
      del(db, &uidirtyfrom, &uidirtyto);
598
 
604
 
599
    } else if (k == 0x008) { /* BKSPC */
605
    } else if (k == 0x008) { /* BKSPC */
600
      bkspc(db, screenw, &uidirtyfrom, &uidirtyto);
606
      bkspc(db, screenw, &uidirtyfrom, &uidirtyto);
601
 
607
 
602
    } else if ((k >= 0x20) && (k <= 0xff)) { /* "normal" character */
608
    } else if ((k >= 0x20) && (k <= 0xff)) { /* "normal" character */
603
      char c = k;
609
      char c = k;
604
      insert_in_line(db, &c, 1, screenw, screenh, &uidirtyfrom, &uidirtyto);
610
      insert_in_line(db, &c, 1, screenw, screenh, &uidirtyfrom, &uidirtyto);
605
 
611
 
606
    } else if (k == 0x009) { /* TAB */
612
    } else if (k == 0x009) { /* TAB */
607
      const char *tab = "        ";
613
      const char *tab = "        ";
608
      insert_in_line(db, tab, 8, screenw, screenh, &uidirtyfrom, &uidirtyto);
614
      insert_in_line(db, tab, 8, screenw, screenh, &uidirtyfrom, &uidirtyto);
609
 
615
 
610
    } else if (k == 0x13b) { /* F1 */
616
    } else if (k == 0x13b) { /* F1 */
611
      ui_help(screenw);
617
      ui_help(screenw);
612
      uidirtyfrom = 0;
618
      uidirtyfrom = 0;
613
      uidirtyto = 0xff;
619
      uidirtyto = 0xff;
614
 
620
 
615
    } else if (k == 0x13f) { /* F5 */
621
    } else if (k == 0x13f) { /* F5 */
616
      const char *m[] = {"SAVED", "SAVING FILE FAILED"};
622
      const char *m[] = {"SAVED", "SAVING FILE FAILED"};
617
      int i;
623
      int i;
618
      i = !!savefile(db);
624
      i = !!savefile(db);
619
      ui_msg(m[i], screenw, screenh, &uidirtyfrom, &uidirtyto);
625
      ui_msg(m[i], screenw, screenh, &uidirtyfrom, &uidirtyto);
620
      mdr_bios_tickswait(11); /* 11 ticks is about 600 ms */
626
      mdr_bios_tickswait(11); /* 11 ticks is about 600 ms */
621
 
627
 
622
    } else if (k == 0x144) { /* F10 */
628
    } else if (k == 0x144) { /* F10 */
623
      db->lfonly ^= 1;
629
      db->lfonly ^= 1;
624
      ui_basic(screenw, screenh, db);
630
      ui_basic(screenw, screenh, db);
625
 
631
 
626
    } else { /* UNHANDLED KEY - TODO IGNORE THIS IN PRODUCTION RELEASE */
632
    } else { /* UNHANDLED KEY - TODO IGNORE THIS IN PRODUCTION RELEASE */
627
      char buff[4];
633
      char buff[4];
628
      const char *HEX = "0123456789ABCDEF";
634
      const char *HEX = "0123456789ABCDEF";
629
      buff[0] = HEX[(k >> 8) & 15];
635
      buff[0] = HEX[(k >> 8) & 15];
630
      buff[1] = HEX[(k >> 4) & 15];
636
      buff[1] = HEX[(k >> 4) & 15];
631
      buff[2] = HEX[k & 15];
637
      buff[2] = HEX[k & 15];
632
      mdr_cout_str(screenh - 1, 0, "UNHANDLED KEY: 0x", scheme[COL_STATUSBAR1], 17);
638
      mdr_cout_str(screenh - 1, 0, "UNHANDLED KEY: 0x", scheme[COL_STATUSBAR1], 17);
633
      mdr_cout_str(screenh - 1, 17, buff, scheme[COL_STATUSBAR1], 3);
639
      mdr_cout_str(screenh - 1, 17, buff, scheme[COL_STATUSBAR1], 3);
634
      keyb_getkey();
640
      keyb_getkey();
635
      break;
641
      break;
636
    }
642
    }
637
  }
643
  }
638
 
644
 
639
  mdr_cout_close();
645
  mdr_cout_close();
640
 
646
 
641
  /* no need to free memory, DOS will do it for me */
647
  /* no need to free memory, DOS will do it for me */
642
 
648
 
643
  return(0);
649
  return(0);
644
}
650
}
645
 
651