Subversion Repositories SvarDOS

Rev

Rev 1353 | Rev 1355 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1283 mateusz.vi 1
/* Sved, the SvarDOS editor
2
 *
3
 * Copyright (C) 2023 Mateusz Viste
4
 *
5
 * Sved is released under the terms of the MIT license.
6
 *
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
9
 * deal in the Software without restriction, including without limitation the
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
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
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,
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
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
23
 * IN THE SOFTWARE.
24
 */
1275 mateusz.vi 25
 
1338 mateusz.vi 26
#include <dos.h>      /* _dos_open(), _dos_read(), _dos_close(), ... */
27
#include <fcntl.h>    /* O_RDONLY, O_WRONLY */
1275 mateusz.vi 28
#include <string.h>
29
 
1312 mateusz.vi 30
#include "mdr\bios.h"
1275 mateusz.vi 31
#include "mdr\cout.h"
1307 mateusz.vi 32
#include "mdr\dos.h"
1275 mateusz.vi 33
#include "mdr\keyb.h"
34
 
1282 mateusz.vi 35
#include "svarlang\svarlang.h"
36
 
1326 mateusz.vi 37
 
38
/*****************************************************************************
39
 * global variables and definitions                                          *
40
 *****************************************************************************/
41
 
1275 mateusz.vi 42
/* preload the mono scheme (to be overloaded at runtime if color adapter present) */
1333 mateusz.vi 43
static unsigned char SCHEME_TEXT   = 0x07,
1354 mateusz.vi 44
                     SCHEME_MENU   = 0x70,
45
                     SCHEME_MENU_CUR= 0x0f,
46
                     SCHEME_MENU_SEL= 0x00,
1333 mateusz.vi 47
                     SCHEME_STBAR1 = 0x70,
48
                     SCHEME_STBAR2 = 0x70,
49
                     SCHEME_STBAR3 = 0xf0,
50
                     SCHEME_SCROLL = 0x70,
51
                     SCHEME_MSG    = 0x70,
52
                     SCHEME_ERR    = 0xf0;
1327 mateusz.vi 53
 
1326 mateusz.vi 54
static unsigned char screenw, screenh;
1275 mateusz.vi 55
 
1327 mateusz.vi 56
static struct {
57
    unsigned char from;
58
    unsigned char to;
1342 mateusz.vi 59
    unsigned char statusbar;
60
} uidirty = {0, 0xff, 1}; /* make sure to redraw entire UI at first run */
1327 mateusz.vi 61
 
1275 mateusz.vi 62
#define SCROLL_CURSOR 0xB1
63
 
64
struct line {
1288 mateusz.vi 65
  struct line far *prev;
66
  struct line far *next;
1275 mateusz.vi 67
  unsigned short len;
68
  char payload[1];
69
};
70
 
1315 mateusz.vi 71
struct file {
1288 mateusz.vi 72
  struct line far *cursor;
1275 mateusz.vi 73
  unsigned short xoffset;
1348 mateusz.vi 74
  unsigned short cursorposx;
75
  unsigned short cursorposy;
1328 mateusz.vi 76
  unsigned short totlines;
77
  unsigned short curline;
1330 mateusz.vi 78
  char lfonly;   /* set if line endings are LF (CR/LF otherwise) */
79
  char modflag;  /* non-zero if file has been modified since last save */
1332 mateusz.vi 80
  char fname[128];
1275 mateusz.vi 81
};
82
 
83
 
1326 mateusz.vi 84
/*****************************************************************************
85
 * functions                                                                 *
86
 *****************************************************************************/
87
 
1339 mateusz.vi 88
static struct line far *line_calloc(unsigned short siz) {
1342 mateusz.vi 89
  struct line far *res;
1339 mateusz.vi 90
  unsigned int seg;
1341 mateusz.vi 91
  if (_dos_allocmem((sizeof(struct line) + siz + 15) / 16, &seg) != 0) return(NULL);
1342 mateusz.vi 92
  res = MK_FP(seg, 0);
93
  _fmemset(res, 0, sizeof(struct line) + siz);
1339 mateusz.vi 94
  return(MK_FP(seg, 0));
95
}
96
 
97
 
98
static void line_free(struct line far *ptr) {
99
  _dos_freemem(FP_SEG(ptr));
100
}
101
 
102
 
1348 mateusz.vi 103
static int curline_resize(struct file far *db, unsigned short newsiz) {
1339 mateusz.vi 104
  unsigned int maxavail;
105
  struct line far *newptr;
106
 
1341 mateusz.vi 107
  /* try resizing the block (much faster) */
108
  if (_dos_setblock((sizeof(struct line) + newsiz + 15) / 16, FP_SEG(db->cursor), &maxavail) == 0) return(0);
1339 mateusz.vi 109
 
110
  /* create a new block and copy data over */
111
  newptr = line_calloc(newsiz);
1340 mateusz.vi 112
  if (newptr == NULL) return(-1);
113
  _fmemmove(newptr, db->cursor, sizeof(struct line) + db->cursor->len);
114
 
115
  /* rewire the linked list */
116
  db->cursor = newptr;
117
  if (newptr->next) newptr->next->prev = newptr;
118
  if (newptr->prev) newptr->prev->next = newptr;
119
 
120
  return(0);
1339 mateusz.vi 121
}
122
 
123
 
1328 mateusz.vi 124
/* adds a new line at cursor position into file linked list and advance cursor
1324 mateusz.vi 125
 * returns non-zero on error */
1328 mateusz.vi 126
static int line_add(struct file *db, const char far *line, unsigned short slen) {
1288 mateusz.vi 127
  struct line far *l;
1275 mateusz.vi 128
 
1339 mateusz.vi 129
  l = line_calloc(slen);
1287 mateusz.vi 130
  if (l == NULL) return(-1);
131
 
1275 mateusz.vi 132
  l->prev = db->cursor;
133
  if (db->cursor) {
134
    l->next = db->cursor->next;
135
    db->cursor->next = l;
136
    l->next->prev = l;
137
  }
138
  db->cursor = l;
1342 mateusz.vi 139
  if (slen > 0) {
140
    _fmemmove(l->payload, line, slen);
141
    l->len = slen;
142
  }
1287 mateusz.vi 143
 
1328 mateusz.vi 144
  db->totlines += 1;
145
  db->curline += 1;
146
 
1287 mateusz.vi 147
  return(0);
1275 mateusz.vi 148
}
149
 
150
 
1348 mateusz.vi 151
static void ui_getstring(const char *query, char *s, unsigned short maxlen) {
152
  unsigned short len = 0;
153
  unsigned char y, x;
1332 mateusz.vi 154
  int k;
155
 
156
  if (maxlen == 0) return;
157
  maxlen--; /* make room for the nul terminator */
158
 
159
  y = screenh - 1;
160
 
161
  /* print query string */
1333 mateusz.vi 162
  x = mdr_cout_str(y, 0, query, SCHEME_STBAR3, 40);
163
  mdr_cout_char_rep(y, x++, ' ', SCHEME_STBAR3, screenw - x);
1332 mateusz.vi 164
 
165
  for (;;) {
166
    mdr_cout_locate(y, x + len);
167
    k = keyb_getkey();
168
 
1345 mateusz.vi 169
    switch (k) {
170
      case 0x1b: /* ESC */
171
        s[0] = 0;
172
        return;
173
      case '\r':
174
        s[len] = 0;
175
        return;
176
      case 0x08: /* BKSPC */
177
        if (len > 0) {
178
          len--;
179
          mdr_cout_char(y, x + len, ' ', SCHEME_STBAR3);
180
        }
181
        break;
182
      default:
183
        if ((k <= 0xff) && (k >= ' ') && (len < maxlen)) {
184
          mdr_cout_char(y, x + len, k, SCHEME_STBAR3);
185
          s[len++] = k;
186
        }
1332 mateusz.vi 187
    }
1345 mateusz.vi 188
  }
1332 mateusz.vi 189
 
190
}
191
 
192
 
1324 mateusz.vi 193
/* append a nul-terminated string to line at cursor position */
194
static int line_append(struct file *f, const char far *buf, unsigned short len) {
195
  if (sizeof(struct line) + f->cursor->len + len < len) return(-1); /* overflow check */
1340 mateusz.vi 196
  if (curline_resize(f, f->cursor->len + len) != 0) return(-1);
1337 mateusz.vi 197
  _fmemmove(f->cursor->payload + f->cursor->len, buf, len);
1324 mateusz.vi 198
  f->cursor->len += len;
199
 
200
  return(0);
201
}
202
 
203
 
1315 mateusz.vi 204
static void db_rewind(struct file *db) {
1275 mateusz.vi 205
  if (db->cursor == NULL) return;
206
  while (db->cursor->prev) db->cursor = db->cursor->prev;
1328 mateusz.vi 207
  db->curline = 0;
1275 mateusz.vi 208
}
209
 
210
 
1326 mateusz.vi 211
static void ui_basic(const struct file *db) {
1302 mateusz.vi 212
  const char *s = svarlang_strid(0); /* HELP */
1348 mateusz.vi 213
  unsigned short helpcol = screenw - strlen(s);
1275 mateusz.vi 214
 
1330 mateusz.vi 215
  /* fill status bar with background (without modflag as it is refreshed by ui_refresh) */
1333 mateusz.vi 216
  mdr_cout_char_rep(screenh - 1, 1, ' ', SCHEME_STBAR1, screenw - 1);
1313 mateusz.vi 217
 
218
  /* filename */
1330 mateusz.vi 219
  {
220
    const char *fn = db->fname;
221
    if (*fn == 0) fn = svarlang_str(0, 1);
1333 mateusz.vi 222
    mdr_cout_str(screenh - 1, 1, fn, SCHEME_STBAR1, screenw);
1321 mateusz.vi 223
  }
1313 mateusz.vi 224
 
225
  /* eol type */
1330 mateusz.vi 226
  {
227
    const char *eoltype = "CRLF";
1353 mateusz.vi 228
    if (db->lfonly) eoltype += 2;
1335 mateusz.vi 229
    mdr_cout_str(screenh - 1, helpcol - 6, eoltype, SCHEME_STBAR1, 5);
1275 mateusz.vi 230
  }
1313 mateusz.vi 231
 
1335 mateusz.vi 232
  mdr_cout_str(screenh - 1, helpcol, s, SCHEME_STBAR2, 40);
1275 mateusz.vi 233
}
234
 
235
 
1331 mateusz.vi 236
static void ui_msg(const char *msg1, const char *msg2, unsigned char attr) {
1312 mateusz.vi 237
  unsigned short x, y, msglen, i;
1331 mateusz.vi 238
  unsigned char msg2flag = 0;
239
 
240
  msglen = strlen(msg1);
241
  if (msg2) {
242
    msg2flag = 1;
243
    i = strlen(msg2);
244
    if (i > msglen) msglen = i;
245
  }
246
 
247
  y = (screenh - 6) >> 1;
1312 mateusz.vi 248
  x = (screenw - msglen - 4) >> 1;
1331 mateusz.vi 249
  for (i = y+2+msg2flag; i >= y; i--) mdr_cout_char_rep(i, x, ' ', attr, msglen + 2);
250
  x++;
1345 mateusz.vi 251
 
1331 mateusz.vi 252
  mdr_cout_str(y+1, x, msg1, attr, msglen);
253
  if (msg2) mdr_cout_str(y+2, x, msg2, attr, msglen);
1312 mateusz.vi 254
 
1327 mateusz.vi 255
  if (uidirty.from > y) uidirty.from = y;
1331 mateusz.vi 256
  if (uidirty.to < y+4) uidirty.to = y+4;
1312 mateusz.vi 257
}
258
 
259
 
1342 mateusz.vi 260
static unsigned char ui_confirm_if_unsaved(struct file *db) {
261
  if (db->modflag == 0) return(0);
262
 
263
  /* if file has been modified then ask for confirmation */
264
  ui_msg(svarlang_str(0,4), svarlang_str(0,5), SCHEME_MSG);
265
  if (keyb_getkey() == '\r') return(0);
266
 
267
  return(1);
268
}
269
 
270
 
1327 mateusz.vi 271
static void ui_refresh(const struct file *db) {
1318 mateusz.vi 272
  unsigned char x;
1310 mateusz.vi 273
  const struct line far *l;
1316 mateusz.vi 274
  unsigned char y = db->cursorposy;
1275 mateusz.vi 275
 
1288 mateusz.vi 276
#ifdef DBG_REFRESH
1282 mateusz.vi 277
  static char m = 'a';
278
  m++;
279
  if (m > 'z') m = 'a';
1288 mateusz.vi 280
#endif
1282 mateusz.vi 281
 
1310 mateusz.vi 282
  /* rewind cursor line to first line that needs redrawing */
1327 mateusz.vi 283
  for (l = db->cursor; y > uidirty.from; y--) l = l->prev;
1282 mateusz.vi 284
 
1310 mateusz.vi 285
  /* iterate over lines and redraw whatever needs to be redrawn */
286
  for (; l != NULL; l = l->next, y++) {
287
 
288
    /* skip lines that do not need to be refreshed */
1327 mateusz.vi 289
    if (y < uidirty.from) continue;
290
    if (y > uidirty.to) break;
1282 mateusz.vi 291
 
1318 mateusz.vi 292
    x = 0;
1275 mateusz.vi 293
    if (db->xoffset < l->len) {
1318 mateusz.vi 294
      unsigned char i, limit;
295
      if (l->len - db->xoffset < screenw) {
296
        limit = l->len;
297
      } else {
298
        limit = db->xoffset + screenw - 1;
299
      }
1333 mateusz.vi 300
      for (i = db->xoffset; i < limit; i++) mdr_cout_char(y, x++, l->payload[i], SCHEME_TEXT);
1275 mateusz.vi 301
    }
1282 mateusz.vi 302
 
1318 mateusz.vi 303
    /* write empty spaces until end of line */
1333 mateusz.vi 304
    if (x < screenw - 1) mdr_cout_char_rep(y, x, ' ', SCHEME_TEXT, screenw - 1 - x);
1318 mateusz.vi 305
 
1288 mateusz.vi 306
#ifdef DBG_REFRESH
1333 mateusz.vi 307
    mdr_cout_char(y, 0, m, SCHEME_STBAR1);
1288 mateusz.vi 308
#endif
1282 mateusz.vi 309
 
1275 mateusz.vi 310
    if (y == screenh - 2) break;
311
  }
1310 mateusz.vi 312
 
1319 mateusz.vi 313
  /* fill all lines below if empty (and they need to be redrawn) */
314
  if (l == NULL) {
1327 mateusz.vi 315
    while ((y < screenh - 1) && (y < uidirty.to)) {
1333 mateusz.vi 316
      mdr_cout_char_rep(y++, 0, ' ', SCHEME_TEXT, screenw - 1);
1319 mateusz.vi 317
    }
1318 mateusz.vi 318
  }
1328 mateusz.vi 319
 
1330 mateusz.vi 320
  /* "file changed" flag */
1351 mateusz.vi 321
  mdr_cout_char(screenh - 1, 0, db->modflag, SCHEME_STBAR1);
1330 mateusz.vi 322
 
1328 mateusz.vi 323
  /* scroll bar */
324
  for (y = 0; y < (screenh - 1); y++) {
1333 mateusz.vi 325
    mdr_cout_char(y, screenw - 1, SCROLL_CURSOR, SCHEME_SCROLL);
1328 mateusz.vi 326
  }
327
 
328
  /* scroll cursor */
329
  if (db->totlines >= screenh) {
330
    unsigned short topline = db->curline - db->cursorposy;
331
    unsigned short col;
332
    unsigned short totlines = db->totlines - screenh + 1;
333
    if (db->totlines - screenh > screenh) {
334
      col = topline / (totlines / (screenh - 1));
335
    } else {
336
      col = topline * (screenh - 1) / totlines;
337
    }
338
    if (col >= screenh - 1) col = screenh - 2;
1333 mateusz.vi 339
    mdr_cout_char(col, screenw - 1, ' ', SCHEME_SCROLL);
1328 mateusz.vi 340
  }
1275 mateusz.vi 341
}
342
 
343
 
1327 mateusz.vi 344
static void check_cursor_not_after_eol(struct file *db) {
1316 mateusz.vi 345
  if (db->xoffset + db->cursorposx <= db->cursor->len) return;
1275 mateusz.vi 346
 
347
  if (db->cursor->len < db->xoffset) {
1316 mateusz.vi 348
    db->cursorposx = 0;
1275 mateusz.vi 349
    db->xoffset = db->cursor->len;
1327 mateusz.vi 350
    uidirty.from = 0;
351
    uidirty.to = 0xff;
1275 mateusz.vi 352
  } else {
1316 mateusz.vi 353
    db->cursorposx = db->cursor->len - db->xoffset;
1275 mateusz.vi 354
  }
355
}
356
 
357
 
1327 mateusz.vi 358
static void cursor_up(struct file *db) {
1275 mateusz.vi 359
  if (db->cursor->prev != NULL) {
1328 mateusz.vi 360
    db->curline -= 1;
1275 mateusz.vi 361
    db->cursor = db->cursor->prev;
1316 mateusz.vi 362
    if (db->cursorposy == 0) {
1327 mateusz.vi 363
      uidirty.from = 0;
364
      uidirty.to = 0xff;
1275 mateusz.vi 365
    } else {
1316 mateusz.vi 366
      db->cursorposy -= 1;
1275 mateusz.vi 367
    }
368
  }
369
}
370
 
371
 
1327 mateusz.vi 372
static void cursor_eol(struct file *db) {
1275 mateusz.vi 373
  /* adjust xoffset to make sure eol is visible on screen */
1282 mateusz.vi 374
  if (db->xoffset > db->cursor->len) {
375
    db->xoffset = db->cursor->len - 1;
1327 mateusz.vi 376
    uidirty.from = 0;
377
    uidirty.to = 0xff;
1282 mateusz.vi 378
  }
379
 
380
  if (db->xoffset + screenw - 1 <= db->cursor->len) {
381
    db->xoffset = db->cursor->len - screenw + 2;
1327 mateusz.vi 382
    uidirty.from = 0;
383
    uidirty.to = 0xff;
1282 mateusz.vi 384
  }
1316 mateusz.vi 385
  db->cursorposx = db->cursor->len - db->xoffset;
1275 mateusz.vi 386
}
387
 
388
 
1327 mateusz.vi 389
static void cursor_down(struct file *db) {
1276 mateusz.vi 390
  if (db->cursor->next != NULL) {
1328 mateusz.vi 391
    db->curline += 1;
1276 mateusz.vi 392
    db->cursor = db->cursor->next;
1316 mateusz.vi 393
    if (db->cursorposy < screenh - 2) {
394
      db->cursorposy += 1;
1276 mateusz.vi 395
    } else {
1327 mateusz.vi 396
      uidirty.from = 0;
397
      uidirty.to = 0xff;
1276 mateusz.vi 398
    }
399
  }
400
}
401
 
402
 
1327 mateusz.vi 403
static void cursor_left(struct file *db) {
1316 mateusz.vi 404
  if (db->cursorposx > 0) {
405
    db->cursorposx -= 1;
1302 mateusz.vi 406
  } else if (db->xoffset > 0) {
407
    db->xoffset -= 1;
1327 mateusz.vi 408
    uidirty.from = 0;
409
    uidirty.to = 0xff;
1302 mateusz.vi 410
  } else if (db->cursor->prev != NULL) { /* jump to end of line above */
1327 mateusz.vi 411
    cursor_up(db);
412
    cursor_eol(db);
1302 mateusz.vi 413
  }
414
}
415
 
416
 
1327 mateusz.vi 417
static void cursor_home(struct file *db) {
1316 mateusz.vi 418
  db->cursorposx = 0;
1282 mateusz.vi 419
  if (db->xoffset != 0) {
420
    db->xoffset = 0;
1327 mateusz.vi 421
    uidirty.from = 0;
422
    uidirty.to = 0xff;
1282 mateusz.vi 423
  }
1276 mateusz.vi 424
}
425
 
426
 
1327 mateusz.vi 427
static void cursor_right(struct file *db) {
1316 mateusz.vi 428
  if (db->cursor->len > db->xoffset + db->cursorposx) {
429
    if (db->cursorposx < screenw - 2) {
430
      db->cursorposx += 1;
1308 mateusz.vi 431
    } else {
432
      db->xoffset += 1;
1327 mateusz.vi 433
      uidirty.from = 0;
434
      uidirty.to = 0xff;
1308 mateusz.vi 435
    }
436
  } else {
1327 mateusz.vi 437
    cursor_down(db);
438
    cursor_home(db);
1308 mateusz.vi 439
  }
440
}
441
 
442
 
1327 mateusz.vi 443
static void del(struct file *db) {
1316 mateusz.vi 444
  if (db->cursorposx + db->xoffset < db->cursor->len) {
445
    _fmemmove(db->cursor->payload + db->cursorposx + db->xoffset, db->cursor->payload + db->cursorposx + db->xoffset + 1, db->cursor->len - db->cursorposx - db->xoffset);
1292 mateusz.vi 446
    db->cursor->len -= 1; /* do this AFTER memmove so the copy includes the nul terminator */
1327 mateusz.vi 447
    uidirty.from = db->cursorposy;
448
    uidirty.to = db->cursorposy;
1351 mateusz.vi 449
    db->modflag = '*';
1292 mateusz.vi 450
  } else if (db->cursor->next != NULL) { /* cursor is at end of line: merge current line with next one (if there is a next one) */
451
    struct line far *nextline = db->cursor->next;
452
    if (db->cursor->next->len > 0) {
1340 mateusz.vi 453
      if (curline_resize(db, db->cursor->len + db->cursor->next->len + 1) == 0) {
1337 mateusz.vi 454
        _fmemmove(db->cursor->payload + db->cursor->len, db->cursor->next->payload, db->cursor->next->len + 1);
1292 mateusz.vi 455
        db->cursor->len += db->cursor->next->len;
456
      }
457
    }
1340 mateusz.vi 458
 
1292 mateusz.vi 459
    db->cursor->next = db->cursor->next->next;
460
    db->cursor->next->prev = db->cursor;
1340 mateusz.vi 461
 
1339 mateusz.vi 462
    line_free(nextline);
1327 mateusz.vi 463
    uidirty.from = db->cursorposy;
464
    uidirty.to = 0xff;
1328 mateusz.vi 465
    db->totlines -= 1;
1351 mateusz.vi 466
    db->modflag = '*';
1292 mateusz.vi 467
  }
468
}
469
 
470
 
1327 mateusz.vi 471
static void bkspc(struct file *db) {
1302 mateusz.vi 472
 
473
  /* backspace is basically "left + del", not applicable only if cursor is on 1st byte of the file */
1316 mateusz.vi 474
  if ((db->cursorposx == 0) && (db->xoffset == 0) && (db->cursor->prev == NULL)) return;
1302 mateusz.vi 475
 
1327 mateusz.vi 476
  cursor_left(db);
477
  del(db);
1302 mateusz.vi 478
}
479
 
480
 
1286 mateusz.vi 481
/* a custom argv-parsing routine that looks directly inside the PSP, avoids the need
482
 * of argc and argv, saves some 330 bytes of binary size */
1352 mateusz.vi 483
static const char *parseargv(void) {
1286 mateusz.vi 484
  char *tail = (void *)0x81; /* THIS WORKS ONLY IN SMALL MEMORY MODEL */
1348 mateusz.vi 485
  unsigned short count = 0;
1352 mateusz.vi 486
  char *argv[2];
1286 mateusz.vi 487
 
1352 mateusz.vi 488
  while (count < 2) {
1286 mateusz.vi 489
    /* jump to nearest arg */
490
    while (*tail == ' ') {
491
      *tail = 0;
492
      tail++;
493
    }
494
 
495
    if (*tail == '\r') {
496
      *tail = 0;
497
      break;
498
    }
499
 
500
    argv[count++] = tail;
501
 
502
    /* jump to next delimiter */
503
    while ((*tail != ' ') && (*tail != '\r')) tail++;
504
  }
505
 
506
  /* check args now */
1321 mateusz.vi 507
  if (count == 0) return("");
1352 mateusz.vi 508
  if (count == 1) return(argv[0]);
1286 mateusz.vi 509
 
1352 mateusz.vi 510
  return(NULL);
1286 mateusz.vi 511
}
512
 
513
 
1346 mateusz.vi 514
/* returns 0 on success, 1 on file not found, 2 on other error */
515
static unsigned char loadfile(struct file *db, const char *fname) {
1324 mateusz.vi 516
  char buff[512]; /* read one entire sector at a time (faster) */
517
  char *buffptr;
518
  unsigned int len, llen;
1287 mateusz.vi 519
  int fd;
1324 mateusz.vi 520
  unsigned char eolfound;
1287 mateusz.vi 521
 
1339 mateusz.vi 522
  bzero(db, sizeof(db));
523
  memcpy(db->fname, fname, strlen(fname));
1321 mateusz.vi 524
 
525
  if (*fname == 0) goto SKIPLOADING;
526
 
1287 mateusz.vi 527
  if (_dos_open(fname, O_RDONLY, &fd) != 0) {
1346 mateusz.vi 528
    return(1);
1287 mateusz.vi 529
  }
530
 
1313 mateusz.vi 531
  db->lfonly = 1;
532
 
1324 mateusz.vi 533
  /* start by adding an empty line */
1328 mateusz.vi 534
  if (line_add(db, NULL, 0) != 0) {
1324 mateusz.vi 535
    /* TODO ERROR HANDLING */
536
  }
1287 mateusz.vi 537
 
1324 mateusz.vi 538
  for (eolfound = 0;;) {
539
    unsigned short consumedbytes;
540
 
541
    if ((_dos_read(fd, buff, sizeof(buff), &len) != 0) || (len == 0)) break;
542
    buffptr = buff;
543
 
544
    FINDLINE:
545
 
546
    /* look for nearest \n */
547
    for (consumedbytes = 0;; consumedbytes++) {
548
      if (consumedbytes == len) {
549
        llen = consumedbytes;
550
        break;
1323 mateusz.vi 551
      }
1324 mateusz.vi 552
      if (buffptr[consumedbytes] == '\r') {
553
        llen = consumedbytes;
554
        consumedbytes++;
555
        db->lfonly = 0;
1320 mateusz.vi 556
        break;
557
      }
1324 mateusz.vi 558
      if (buffptr[consumedbytes] == '\n') {
559
        eolfound = 1;
560
        llen = consumedbytes;
561
        consumedbytes++;
562
        break;
563
      }
1287 mateusz.vi 564
    }
1324 mateusz.vi 565
 
566
    /* consumedbytes is the amount of bytes processed from buffptr,
567
     * llen is the length of line's payload (without its line terminator) */
568
 
569
    /* append content, if line is non-empty */
570
    if ((llen > 0) && (line_append(db, buffptr, llen) != 0)) {
1339 mateusz.vi 571
      goto IOERR;
1287 mateusz.vi 572
    }
573
 
1324 mateusz.vi 574
    /* add a new line if necessary */
575
    if (eolfound) {
1328 mateusz.vi 576
      if (line_add(db, NULL, 0) != 0) {
1339 mateusz.vi 577
        goto IOERR;
1324 mateusz.vi 578
      }
579
      eolfound = 0;
580
    }
1287 mateusz.vi 581
 
1324 mateusz.vi 582
    /* anything left? process the buffer leftover again */
583
    if (consumedbytes < len) {
584
      len -= consumedbytes;
585
      buffptr += consumedbytes;
586
      goto FINDLINE;
587
    }
588
 
589
  }
590
 
1287 mateusz.vi 591
  _dos_close(fd);
592
 
1321 mateusz.vi 593
  SKIPLOADING:
594
 
1320 mateusz.vi 595
  /* add an empty line at end if not present already, also rewind cursor to top of file */
1339 mateusz.vi 596
  if ((db->cursor == NULL) || (db->cursor->len != 0)) line_add(db, NULL, 0);
597
  db_rewind(db);
1320 mateusz.vi 598
 
1346 mateusz.vi 599
  return(0);
1339 mateusz.vi 600
 
601
  IOERR:
602
  _dos_close(fd);
1346 mateusz.vi 603
  return(2);
1287 mateusz.vi 604
}
605
 
606
 
1332 mateusz.vi 607
static int savefile(const struct file *db, const char *newfname) {
1311 mateusz.vi 608
  int fd;
609
  const struct line far *l;
610
  unsigned bytes;
1313 mateusz.vi 611
  unsigned char eollen;
612
  unsigned char eolbuf[2];
1332 mateusz.vi 613
  int errflag = 0;
1313 mateusz.vi 614
 
1332 mateusz.vi 615
  /* either create a new file if newfname provided, or... */
616
  if (newfname) {
617
    if (_dos_creatnew(newfname, _A_NORMAL, &fd) != 0) return(-1);
618
  } else { /* ...open db->fname */
619
    if (_dos_open(db->fname, O_WRONLY, &fd) != 0) return(-1);
1311 mateusz.vi 620
  }
621
 
622
  l = db->cursor;
623
  while (l->prev) l = l->prev;
624
 
1313 mateusz.vi 625
  /* preset line terminators */
626
  if (db->lfonly) {
627
    eolbuf[0] = '\n';
628
    eollen = 1;
629
  } else {
630
    eolbuf[0] = '\r';
631
    eolbuf[1] = '\n';
632
    eollen = 2;
633
  }
634
 
1311 mateusz.vi 635
  while (l) {
1324 mateusz.vi 636
    /* do not write the last empty line, it is only useful for edition */
637
    if (l->len != 0) {
1332 mateusz.vi 638
      errflag |= _dos_write(fd, l->payload, l->len, &bytes);
1324 mateusz.vi 639
    } else if (l->next == NULL) {
640
      break;
641
    }
1332 mateusz.vi 642
    errflag |= _dos_write(fd, eolbuf, eollen, &bytes);
1311 mateusz.vi 643
    l = l->next;
644
  }
645
 
1332 mateusz.vi 646
  errflag |= _dos_close(fd);
1330 mateusz.vi 647
 
1332 mateusz.vi 648
  return(errflag);
1311 mateusz.vi 649
}
650
 
651
 
1327 mateusz.vi 652
static void insert_in_line(struct file *db, const char *databuf, unsigned short len) {
1340 mateusz.vi 653
  if (curline_resize(db, db->cursor->len + len) == 0) {
1317 mateusz.vi 654
    unsigned short off = db->xoffset + db->cursorposx;
1351 mateusz.vi 655
    db->modflag = '*';
1317 mateusz.vi 656
    _fmemmove(db->cursor->payload + off + len, db->cursor->payload + off, db->cursor->len - off + 1);
657
    db->cursor->len += len;
1327 mateusz.vi 658
    uidirty.from = db->cursorposy;
659
    uidirty.to = db->cursorposy;
1317 mateusz.vi 660
    while (len--) {
661
      db->cursor->payload[off++] = *databuf;
662
      databuf++;
1327 mateusz.vi 663
      cursor_right(db);
1317 mateusz.vi 664
    }
665
  }
666
}
667
 
668
 
1342 mateusz.vi 669
static void clear_file(struct file *db) {
670
 
671
  /* free the entire linked list of lines */
672
  db_rewind(db);
673
  while (db->cursor) {
674
    struct line far *victim;
675
    victim = db->cursor;
676
    db->cursor = db->cursor->next;
677
    line_free(victim);
678
  }
679
 
680
  /* zero out the struct */
681
  bzero(db, sizeof(struct file));
682
}
683
 
684
 
1343 mateusz.vi 685
/* recompute db->curline by counting nodes in linked list */
686
static void recompute_curline(struct file *db) {
687
  const struct line far *l = db->cursor;
688
 
689
  db->curline = 0;
690
  while (l->prev != NULL) {
691
    db->curline += 1;
692
    l = l->prev;
693
  }
694
}
695
 
696
 
1354 mateusz.vi 697
enum MENU_ACTION {
698
  MENU_NONE = 0,
699
  MENU_NEW = 1,
700
  MENU_OPEN = 2,
701
  MENU_SAVE = 3,
702
  MENU_SAVEAS = 4,
703
  MENU_CHGEOL = 5,
704
  MENU_QUIT = 6
705
};
706
 
707
static enum MENU_ACTION ui_menu(void) {
708
  unsigned short i, curchoice, attr, x, slen;
709
  uidirty.from = 0;
710
  uidirty.to = 0xff;
711
  uidirty.statusbar = 1;
712
 
713
  /* find out the longest string */
714
  slen = 0;
715
  for (i = MENU_NEW; i <= MENU_QUIT; i++) {
716
    x = strlen(svarlang_str(8, i));
717
    if (x > slen) slen = x;
718
  }
719
 
720
  curchoice = MENU_NEW;
721
  for (;;) {
722
    /* render menu */
723
    for (i = MENU_NONE; i <= MENU_QUIT + 1; i++) {
724
      mdr_cout_char_rep(i, 0, ' ', SCHEME_MENU, slen+4);
725
      if (i == curchoice) {
726
        attr = SCHEME_MENU_CUR;
727
        mdr_cout_char(i, 1, '>', SCHEME_MENU_SEL);
728
      } else {
729
        attr = SCHEME_MENU;
730
      }
731
      x = mdr_cout_str(i, 2, svarlang_str(8, i), attr, slen);
732
      if (i == curchoice) {
733
        mdr_cout_char_rep(i, x + 2, ' ', SCHEME_MENU_SEL, slen - x + 1);
734
        mdr_cout_locate(i, x + 2);
735
      }
736
    }
737
    /* wait for key */
738
    switch (keyb_getkey()) {
739
      case '\r': return(curchoice); /* ENTER */
740
      case 0x150: /* down */
741
        if (curchoice == MENU_QUIT) {
742
          curchoice = MENU_NEW;
743
        } else {
744
          curchoice++;
745
        }
746
        break;
747
      case 0x148: /* up */
748
        if (curchoice == MENU_NEW) {
749
          curchoice = MENU_QUIT;
750
        } else {
751
          curchoice--;
752
        }
753
        break;
754
      default: return(MENU_NONE);
755
    }
756
  }
757
}
758
 
759
 
1347 mateusz.vi 760
/* main returns nothing, ie. sved always exits with a zero exit code
761
 * (this saves 20 bytes of executable footprint) */
762
void main(void) {
1354 mateusz.vi 763
  static struct file dbarr[12];
1286 mateusz.vi 764
  const char *fname;
1346 mateusz.vi 765
  struct file *db = dbarr;
1275 mateusz.vi 766
 
1307 mateusz.vi 767
  {
768
    char nlspath[128], lang[8];
769
    svarlang_autoload_pathlist("sved", mdr_dos_getenv(nlspath, "NLSPATH", sizeof(nlspath)), mdr_dos_getenv(lang, "LANG", sizeof(lang)));
770
  }
1282 mateusz.vi 771
 
1286 mateusz.vi 772
  fname = parseargv();
773
 
1350 mateusz.vi 774
  if ((fname == NULL) || (*fname == '/')) {
1302 mateusz.vi 775
    mdr_coutraw_puts(svarlang_str(1,0)); /* usage: sved file.txt */
1347 mateusz.vi 776
    return;
1275 mateusz.vi 777
  }
778
 
1282 mateusz.vi 779
  /* load file */
1346 mateusz.vi 780
  {
781
    unsigned char err = loadfile(db, fname);
782
    if (err == 1) {
783
      mdr_coutraw_puts(svarlang_str(0,11)); /* file not found */
1347 mateusz.vi 784
      return;
1346 mateusz.vi 785
    } else if (err != 0) {
786
      mdr_coutraw_puts(svarlang_str(0,10)); /* ERROR */
1347 mateusz.vi 787
      return;
1346 mateusz.vi 788
    }
789
  }
1282 mateusz.vi 790
 
1333 mateusz.vi 791
  if (mdr_cout_init(&screenw, &screenh)) {
792
    /* load color scheme if mdr_cout_init returns a color flag */
793
    SCHEME_TEXT = 0x17;
1354 mateusz.vi 794
    SCHEME_MENU = 0x70;
795
    SCHEME_MENU_CUR = 0x2f;
796
    SCHEME_MENU_SEL = 0x22;
1333 mateusz.vi 797
    SCHEME_STBAR1 = 0x70;
798
    SCHEME_STBAR2 = 0x78;
799
    SCHEME_STBAR3 = 0xf0;
800
    SCHEME_SCROLL = 0x70;
801
    SCHEME_MSG = 0xf0;
802
    SCHEME_ERR = 0x4f;
803
  }
1275 mateusz.vi 804
 
805
  for (;;) {
806
    int k;
807
 
1327 mateusz.vi 808
    check_cursor_not_after_eol(db);
1320 mateusz.vi 809
    mdr_cout_locate(db->cursorposy, db->cursorposx);
1275 mateusz.vi 810
 
1327 mateusz.vi 811
    if (uidirty.from != 0xff) {
812
      ui_refresh(db);
813
      uidirty.from = 0xff;
1282 mateusz.vi 814
    }
1342 mateusz.vi 815
    if (uidirty.statusbar) {
816
      ui_basic(db);
817
      uidirty.statusbar = 0;
818
    }
1328 mateusz.vi 819
#ifdef DBG_LINENUM
820
      {
821
        char ddd[10];
822
        db->curline += 1;
823
        ddd[0] = '0' + db->curline / 100;
824
        ddd[1] = '0' + (db->curline % 100) / 10;
825
        ddd[2] = '0' + (db->curline % 10);
826
        db->curline -= 1;
827
        ddd[3] = '/';
828
        ddd[4] = '0' + db->totlines / 100;
829
        ddd[5] = '0' + (db->totlines % 100) / 10;
830
        ddd[6] = '0' + (db->totlines % 10);
831
        ddd[7] = 0;
1333 mateusz.vi 832
        mdr_cout_str(screenh - 1, 40, ddd, SCHEME_STBAR1, sizeof(ddd));
1328 mateusz.vi 833
      }
834
#endif
1275 mateusz.vi 835
 
836
    k = keyb_getkey();
1282 mateusz.vi 837
 
1275 mateusz.vi 838
    if (k == 0x150) { /* down */
1327 mateusz.vi 839
      cursor_down(db);
1275 mateusz.vi 840
 
841
    } else if (k == 0x148) { /* up */
1327 mateusz.vi 842
      cursor_up(db);
1275 mateusz.vi 843
 
844
    } else if (k == 0x14D) { /* right */
1327 mateusz.vi 845
      cursor_right(db);
1275 mateusz.vi 846
 
847
    } else if (k == 0x14B) { /* left */
1327 mateusz.vi 848
      cursor_left(db);
1275 mateusz.vi 849
 
1282 mateusz.vi 850
    } else if (k == 0x149) { /* pgup */
1334 mateusz.vi 851
      unsigned char dist = db->cursorposy + screenh - 1;
852
      while ((dist != 0) && (db->cursor->prev != NULL)) {
853
        db->cursor = db->cursor->prev;
854
        dist--;
855
      }
856
      if (dist != 0) {
857
        db->cursorposy = 0;
858
        db->cursorposx = 0;
859
      } else {
860
        dist = db->cursorposy;
861
        while ((dist--) && (db->cursor->next)) db->cursor = db->cursor->next;
862
      }
863
      uidirty.from = 0;
864
      uidirty.to = 0xff;
1343 mateusz.vi 865
      recompute_curline(db);
1282 mateusz.vi 866
 
867
    } else if (k == 0x151) { /* pgdown */
1334 mateusz.vi 868
      unsigned char dist = screenh + screenh - db->cursorposy - 3;
869
      while ((dist != 0) && (db->cursor->next != NULL)) {
870
        db->cursor = db->cursor->next;
871
        dist--;
872
      }
873
      if (dist != 0) {
874
        db->cursorposy = screenh - 2;
875
        if (db->totlines <= db->cursorposy) db->cursorposy = db->totlines - 1;
876
        db->cursorposx = 0;
877
      } else {
878
        dist = screenh - 2 - db->cursorposy;
879
        while ((dist--) && (db->cursor->prev)) db->cursor = db->cursor->prev;
880
      }
881
      uidirty.from = 0;
882
      uidirty.to = 0xff;
1343 mateusz.vi 883
      recompute_curline(db);
1282 mateusz.vi 884
 
885
    } else if (k == 0x147) { /* home */
1327 mateusz.vi 886
       cursor_home(db);
1282 mateusz.vi 887
 
888
    } else if (k == 0x14F) { /* end */
1327 mateusz.vi 889
       cursor_eol(db);
1282 mateusz.vi 890
 
1275 mateusz.vi 891
    } else if (k == 0x1B) { /* ESC */
1354 mateusz.vi 892
      int quitnow = 0;
893
      char fname[25];
894
      int saveflag = 0;
1275 mateusz.vi 895
 
1354 mateusz.vi 896
      switch (ui_menu()) {
897
 
898
        case MENU_NONE:
899
          break;
900
 
901
        case MENU_NEW:
902
          if (ui_confirm_if_unsaved(db) == 0) {
903
            clear_file(db);
904
            /* add a single empty line */
905
            line_add(db, NULL, 0);
906
          }
907
          uidirty.statusbar = 1;
908
          break;
909
 
910
        case MENU_OPEN:
911
          /* display a warning if unsaved changes are pending */
912
          if (db->modflag != 0) ui_msg(svarlang_str(0,4), svarlang_str(0,8), SCHEME_MSG);
913
 
914
          /* ask for filename */
915
          ui_getstring(svarlang_str(0,7), fname, sizeof(fname));
916
          if (fname[0] != 0) {
917
            unsigned char err;
918
            clear_file(db);
919
            err = loadfile(db, fname);
920
            if (err != 0) {
921
              if (err == 1) {
922
                ui_msg(svarlang_str(0,11), NULL, SCHEME_ERR); /* file not found */
923
              } else {
924
                ui_msg(svarlang_str(0,10), NULL, SCHEME_ERR);  /* ERROR */
925
              }
926
              mdr_bios_tickswait(44); /* 3s */
927
              clear_file(db);
928
            }
929
          }
930
          break;
931
 
932
        case MENU_SAVEAS:
933
          saveflag = 1;
934
          /* FALLTHRU */
935
        case MENU_SAVE:
936
          if ((saveflag != 0) || (db->fname[0] == 0)) { /* save as... */
937
            ui_getstring(svarlang_str(0,6), fname, sizeof(fname));
938
            if (*fname == 0) break;
939
            saveflag = savefile(db, fname);
940
            if (saveflag == 0) memcpy(db->fname, fname, sizeof(fname));
941
          } else {
942
            saveflag = savefile(db, NULL);
943
          }
944
 
945
          if (saveflag == 0) {
946
            db->modflag = 0;
947
            ui_msg(svarlang_str(0, 2), NULL, SCHEME_MSG);
948
            mdr_bios_tickswait(11); /* 11 ticks is about 600 ms */
949
          } else {
950
            ui_msg(svarlang_str(0, 3), NULL, SCHEME_ERR);
951
            mdr_bios_tickswait(36); /* 2s */
952
          }
953
          break;
954
 
955
        case MENU_CHGEOL:
956
          db->modflag = '*';
957
          db->lfonly ^= 1;
958
          break;
959
 
960
        case MENU_QUIT:
961
          if (ui_confirm_if_unsaved(db) == 0) quitnow = 1;
962
          break;
963
      }
964
 
965
      if (quitnow) break;
966
 
1289 mateusz.vi 967
    } else if (k == 0x0D) { /* ENTER */
1328 mateusz.vi 968
      unsigned short off = db->xoffset + db->cursorposx;
1289 mateusz.vi 969
      /* add a new line */
1328 mateusz.vi 970
      if (line_add(db, db->cursor->payload + off, db->cursor->len - off) == 0) {
1351 mateusz.vi 971
        db->modflag = '*';
1328 mateusz.vi 972
        db->cursor = db->cursor->prev; /* back to original line */
1289 mateusz.vi 973
        /* trim the line above */
1328 mateusz.vi 974
        db->cursor->len = off;
1289 mateusz.vi 975
        /* move cursor to the (new) line below */
1343 mateusz.vi 976
        db->curline -= 1;
1328 mateusz.vi 977
        uidirty.from = db->cursorposy;
1327 mateusz.vi 978
        uidirty.to = 0xff;
1328 mateusz.vi 979
        cursor_down(db);
980
        cursor_home(db);
1289 mateusz.vi 981
      } else {
982
        /* ERROR: OUT OF MEMORY */
983
      }
984
 
1292 mateusz.vi 985
    } else if (k == 0x153) {  /* DEL */
1327 mateusz.vi 986
      del(db);
1292 mateusz.vi 987
 
1302 mateusz.vi 988
    } else if (k == 0x008) { /* BKSPC */
1327 mateusz.vi 989
      bkspc(db);
1302 mateusz.vi 990
 
1308 mateusz.vi 991
    } else if ((k >= 0x20) && (k <= 0xff)) { /* "normal" character */
1317 mateusz.vi 992
      char c = k;
1327 mateusz.vi 993
      insert_in_line(db, &c, 1);
1308 mateusz.vi 994
 
1317 mateusz.vi 995
    } else if (k == 0x009) { /* TAB */
1348 mateusz.vi 996
      insert_in_line(db, "        ", 8);
1317 mateusz.vi 997
 
1354 mateusz.vi 998
    } else if ((k >= 0x13b) && (k <= 0x146)) { /* F1..F12 */
1327 mateusz.vi 999
      uidirty.from = 0;
1000
      uidirty.to = 0xff;
1309 mateusz.vi 1001
 
1325 mateusz.vi 1002
    } else if (k == 0x174) { /* CTRL+ArrRight - jump to next word */
1003
      /* if currently cursor is on a non-space, then fast-forward to nearest space or EOL */
1004
      for (;;) {
1005
        if (db->xoffset + db->cursorposx == db->cursor->len) break;
1006
        if (db->cursor->payload[db->xoffset + db->cursorposx] == ' ') break;
1327 mateusz.vi 1007
        cursor_right(db);
1325 mateusz.vi 1008
      }
1009
      /* now skip to next non-space or end of file */
1010
      for (;;) {
1327 mateusz.vi 1011
        cursor_right(db);
1325 mateusz.vi 1012
        if (db->cursor->payload[db->xoffset + db->cursorposx] != ' ') break;
1013
        if ((db->cursor->next == NULL) && (db->cursorposx + db->xoffset == db->cursor->len)) break;
1014
      }
1015
 
1016
    } else if (k == 0x173) { /* CTRL+ArrLeft - jump to prev word */
1327 mateusz.vi 1017
      cursor_left(db);
1325 mateusz.vi 1018
      /* if currently cursor is on a space, then fast-forward to nearest non-space or start of line */
1019
      for (;;) {
1020
        if ((db->xoffset == 0) && (db->cursorposx == 0)) break;
1021
        if (db->cursor->payload[db->xoffset + db->cursorposx] != ' ') break;
1327 mateusz.vi 1022
        cursor_left(db);
1325 mateusz.vi 1023
      }
1024
      /* now skip to next space or start of file */
1025
      for (;;) {
1327 mateusz.vi 1026
        cursor_left(db);
1325 mateusz.vi 1027
        if (db->cursor->payload[db->xoffset + db->cursorposx] == ' ') {
1327 mateusz.vi 1028
          cursor_right(db);
1325 mateusz.vi 1029
          break;
1030
        }
1031
        if ((db->cursorposx == 0) && (db->xoffset == 0)) break;
1032
      }
1033
 
1333 mateusz.vi 1034
#ifdef DBG_UNHKEYS
1282 mateusz.vi 1035
    } else { /* UNHANDLED KEY - TODO IGNORE THIS IN PRODUCTION RELEASE */
1036
      char buff[4];
1037
      const char *HEX = "0123456789ABCDEF";
1038
      buff[0] = HEX[(k >> 8) & 15];
1039
      buff[1] = HEX[(k >> 4) & 15];
1040
      buff[2] = HEX[k & 15];
1333 mateusz.vi 1041
      mdr_cout_str(screenh - 1, 0, "UNHANDLED KEY: 0x", SCHEME_STBAR1, 17);
1042
      mdr_cout_str(screenh - 1, 17, buff, SCHEME_STBAR1, 3);
1275 mateusz.vi 1043
      keyb_getkey();
1044
      break;
1333 mateusz.vi 1045
#endif
1275 mateusz.vi 1046
    }
1047
  }
1048
 
1049
  mdr_cout_close();
1050
 
1320 mateusz.vi 1051
  /* no need to free memory, DOS will do it for me */
1275 mateusz.vi 1052
 
1347 mateusz.vi 1053
  return;
1275 mateusz.vi 1054
}