Subversion Repositories SvarDOS

Rev

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

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