Subversion Repositories SvarDOS

Rev

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

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