Subversion Repositories SvarDOS

Rev

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

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