1 /*
2
3 Minimum Profit - A Text Editor
4
5 ttcdt <dev@triptico.com> et al.
6
7 This software is released into the public domain.
8 NO WARRANTY. See file LICENSE for details.
9
10 */
11
12 #include "config.h"
13
14 #include <stdio.h>
15 #include <wchar.h>
16 #include <wctype.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #include "mpdm.h"
21 #include "mpsl.h"
22
23 #include "mp.h"
24
25 /** data **/
26
27 /* exit requested? */
28 int mp_exit_requested = 0;
29
30 /** private data for drawing syntax-highlighted text **/
31
32 struct drw_1_info {
33 mpdm_t txt; /* the document */
34 mpdm_t syntax; /* syntax highlight information */
35 mpdm_t colors; /* color definitions (for attributes) */
36 mpdm_t word_color_func; /* word color function (just for detection) */
37 mpdm_t last_search; /* last search regex */
38 int normal_attr; /* normal attr */
39 int cursor_attr; /* cursor attr */
40 int n_lines; /* number of processed lines */
41 int p_lines; /* number of prereaded lines */
42 int t_lines; /* total lines in document */
43 int vx; /* first visible column */
44 int vy; /* first visible line */
45 int tx; /* horizontal window size */
46 int ty; /* vertical window size */
47 int tab_size; /* tabulator size */
48 int mod; /* modify count */
49 int preread_lines; /* lines to pre-read (for synhi blocks) */
50 int mark_eol; /* mark end of lines */
51 int redraw; /* redraw trigger */
52 int xoffset; /* # of columns reserved for line numbers */
53 int double_page; /* # of columns where double page activates */
54 wchar_t wc_tab; /* char for marking tabs */
55 wchar_t wc_formfeed; /* char for marking form feeds */
56 wchar_t wc_unknown; /* char for marking unknown characters */
57 wchar_t wc_wordwrap; /* char for marking word wraps */
58 wchar_t wc_m_dash; /* char for the m-dash */
59 };
60
61 struct drw_1_info drw_1;
62 struct drw_1_info drw_1_o;
63
64 static struct {
65 int x; /* cursor x */
66 int y; /* cursor y */
67 int *offsets; /* offsets of lines */
68 char *attrs; /* attributes */
69 int visible; /* offset to the first visible character */
70 int cursor; /* offset to cursor */
71 wchar_t *ptr; /* pointer to joined data */
72 int size; /* size of joined data */
73 int matchparen_offset; /* offset to matched paren */
74 int matchparen_o_attr; /* original attribute there */
75 int cursor_o_attr; /* original attribute under cursor */
76 mpdm_t v; /* the data */
77 mpdm_t old; /* the previously generated array */
78 int mark_offset; /* offset to the marked block */
79 int mark_size; /* size of mark_o_attr */
80 char *mark_o_attr; /* saved attributes for the mark */
81
82 wchar_t *cmap;
83 int *amap;
84 int *vx2x;
85 int *vy2y;
86 int mx;
87 int my;
88 } drw_2;
89
90 /** code **/
91
92 #define MP_REAL_TAB_SIZE(x) (drw_1.tab_size - ((x) % drw_1.tab_size))
93
drw_wcwidth(int x,wchar_t c)94 static int drw_wcwidth(int x, wchar_t c)
95 /* returns the wcwidth of c, or the tab spaces for
96 the x column if it's a tab */
97 {
98 int r;
99
100 switch (c) {
101 case L'\n':
102 r = 1;
103 break;
104
105 case L'\t':
106 r = MP_REAL_TAB_SIZE(x);
107 break;
108
109 default:
110 r = 1;
111 break;
112 }
113
114 return r < 0 ? 1 : r;
115 }
116
117
drw_vx2x(mpdm_t str,int vx)118 int drw_vx2x(mpdm_t str, int vx)
119 /* returns the character in str that is on column vx */
120 {
121 const wchar_t *ptr = str->data;
122 int n, x;
123
124 for (n = x = 0; n < vx && ptr[x] != L'\0'; x++)
125 n += drw_wcwidth(n, ptr[x]);
126
127 return x;
128 }
129
130
drw_x2vx(mpdm_t str,int x)131 int drw_x2vx(mpdm_t str, int x)
132 /* returns the column where the character at offset x seems to be */
133 {
134 const wchar_t *ptr;
135 int n, vx = 0;
136
137 if (str) {
138 ptr = str->data;
139 for (n = vx = 0; n < x && ptr[n] != L'\0'; n++)
140 vx += drw_wcwidth(vx, ptr[n]);
141 }
142
143 return vx;
144 }
145
146
drw_line_offset(int l)147 static int drw_line_offset(int l)
148 /* returns the offset into v for line number l */
149 {
150 return drw_2.offsets[l - drw_1.vy + drw_1.p_lines];
151 }
152
153
drw_adjust_y(int y,int * vy,int ty)154 static int drw_adjust_y(int y, int *vy, int ty)
155 /* adjusts the visual y position */
156 {
157 int t = *vy;
158
159 if (*vy < 0)
160 *vy = 0;
161
162 /* is y above the first visible line? */
163 if (y < *vy)
164 *vy = y;
165
166 /* is y below the last visible line? */
167 if (y > *vy + (ty - 2))
168 *vy = y - (ty - 2);
169
170 return t != *vy;
171 }
172
173
drw_adjust_x(int x,int y,int * vx,int tx,wchar_t * ptr)174 static int drw_adjust_x(int x, int y, int *vx, int tx, wchar_t * ptr)
175 /* adjust the visual x position */
176 {
177 int n, m;
178 int t = *vx;
179
180 /* calculate the column for the cursor position */
181 for (n = m = 0; n < x; n++, ptr++)
182 m += drw_wcwidth(m, *ptr);
183
184 /* if new cursor column is nearer the leftmost column, set */
185 if (m < *vx)
186 *vx = m;
187
188 /* if new cursor column is further the rightmost column, set */
189 if (m > *vx + (tx - 1))
190 *vx = m - (tx - 1);
191
192 return t != *vx;
193 }
194
195
drw_get_attr(wchar_t * color_name)196 static int drw_get_attr(wchar_t * color_name)
197 /* returns the attribute number for a color */
198 {
199 mpdm_t v;
200 int attr = 0;
201
202 if ((v = mpdm_get_wcs(drw_1.colors, color_name)) != NULL)
203 attr = mpdm_ival(mpdm_get_wcs(v, L"attr"));
204
205 return attr;
206 }
207
208
drw_prepare(mpdm_t doc)209 static int drw_prepare(mpdm_t doc)
210 /* prepares the document for screen drawing */
211 {
212 mpdm_t window = mpdm_ref(mpdm_get_wcs(MP, L"window"));
213 mpdm_t config = mpdm_ref(mpdm_get_wcs(MP, L"config"));
214 mpdm_t txt = mpdm_ref(mpdm_get_wcs(doc, L"txt"));
215 mpdm_t lines = mpdm_ref(mpdm_get_wcs(txt, L"lines"));
216 int x = mpdm_ival(mpdm_get_wcs(txt, L"x"));
217 int y = mpdm_ival(mpdm_get_wcs(txt, L"y"));
218 int n;
219 mpdm_t v;
220 wchar_t *ptr;
221 int ret = 1;
222
223 mpdm_store(&drw_1.txt, txt);
224 mpdm_store(&drw_1.syntax, mpdm_get_wcs(doc, L"syntax"));
225 mpdm_store(&drw_1.colors, mpdm_get_wcs(MP, L"colors"));
226 mpdm_store(&drw_1.word_color_func, mpdm_get_wcs(MP, L"word_color_func"));
227 mpdm_store(&drw_1.last_search, mpdm_get_wcs(MP, L"last_search"));
228
229 drw_1.vx = mpdm_ival(mpdm_get_wcs(txt, L"vx"));
230 drw_1.vy = mpdm_ival(mpdm_get_wcs(txt, L"vy"));
231 drw_1.tx = mpdm_ival(mpdm_get_wcs(window, L"tx"));
232 drw_1.ty = mpdm_ival(mpdm_get_wcs(window, L"ty"));
233 drw_1.tab_size = mpdm_ival(mpdm_get_wcs(config, L"tab_size"));
234 drw_1.mod = mpdm_ival(mpdm_get_wcs(txt, L"mod"));
235 drw_1.mark_eol = mpdm_ival(mpdm_get_wcs(config, L"mark_eol"));
236 drw_1.t_lines = mpdm_size(lines);
237
238 /* get preread_lines from the syntax definition */
239 drw_1.preread_lines = mpdm_ival(mpdm_get_wcs(drw_1.syntax, L"preread_lines"));
240
241 /* if it's 0, get it from the configuration */
242 if (drw_1.preread_lines == 0)
243 drw_1.preread_lines = mpdm_ival(mpdm_get_wcs(config, L"preread_lines"));
244
245 n = mpdm_ival(mpdm_get_wcs(config, L"double_page"));
246
247 if (n && drw_1.tx > n) {
248 /* if the usable screen is wider than the
249 double page setting, activate it */
250 drw_1.tx /= 2;
251 drw_1.ty *= 2;
252 drw_1.double_page = 1;
253 }
254 else
255 drw_1.double_page = 0;
256
257 /* adjust the visual y coordinate */
258 if (drw_adjust_y(y, &drw_1.vy, drw_1.ty))
259 mpdm_set_wcs(txt, MPDM_I(drw_1.vy), L"vy");
260
261 /* adjust the visual x coordinate */
262 if (drw_adjust_x(x, y, &drw_1.vx, drw_1.tx, mpdm_string(mpdm_get_i(lines, y))))
263 mpdm_set_wcs(txt, MPDM_I(drw_1.vx), L"vx");
264
265 /* get the maximum prereadable lines */
266 drw_1.p_lines = drw_1.vy > drw_1.preread_lines ? drw_1.preread_lines : drw_1.vy;
267
268 /* maximum lines */
269 drw_1.n_lines = drw_1.ty + drw_1.p_lines;
270
271 /* get the most used attributes */
272 drw_1.normal_attr = drw_get_attr(L"normal");
273 drw_1.cursor_attr = drw_get_attr(L"cursor");
274
275 drw_2.x = x;
276 drw_2.y = y;
277
278 /* redraw trigger */
279 drw_1.redraw = mpdm_ival(mpdm_get_wcs(MP, L"redraw_counter"));
280
281 /* calculate number of lines reserved for line numbers */
282 n = mpdm_ival(mpdm_get_wcs(config, L"show_line_numbers"));
283
284 if (n) {
285 char tmp[32];
286 sprintf(tmp, " %d ", (int) mpdm_size(lines));
287 drw_1.xoffset = strlen(tmp);
288 }
289 else
290 drw_1.xoffset = 0;
291
292 mpdm_set_wcs(MP, MPDM_I(drw_1.xoffset), L"xoffset");
293
294 /* placeholder Unicode characters */
295 n = mpdm_ival(mpdm_get_wcs(config, L"use_unicode"));
296 v = mpdm_get_i(mpdm_get_wcs(MP, L"unicode_tbl"), n);
297
298 if ((ptr = mpdm_string(mpdm_get_wcs(v, L"tab"))) != NULL)
299 drw_1.wc_tab = *ptr;
300 if ((ptr = mpdm_string(mpdm_get_wcs(v, L"formfeed"))) != NULL)
301 drw_1.wc_formfeed = *ptr;
302 if ((ptr = mpdm_string(mpdm_get_wcs(v, L"wordwrap"))) != NULL)
303 drw_1.wc_wordwrap = *ptr;
304 if ((ptr = mpdm_string(mpdm_get_wcs(v, L"m_dash"))) != NULL)
305 drw_1.wc_m_dash = *ptr;
306 if ((ptr = mpdm_string(mpdm_get_wcs(v, L"unknown"))) != NULL)
307 drw_1.wc_unknown = *ptr;
308
309 /* compare drw_1 with drw_1_o; if they are the same,
310 no more expensive calculations on drw_2 are needed */
311 if (memcmp(&drw_1, &drw_1_o, sizeof(drw_1)) != 0) {
312
313 /* different; store now */
314 memcpy(&drw_1_o, &drw_1, sizeof(drw_1_o));
315
316 /* alloc space for line offsets */
317 drw_2.offsets = realloc(drw_2.offsets, drw_1.n_lines * sizeof(int));
318
319 drw_2.ptr = NULL;
320 drw_2.size = 0;
321
322 /* add first line */
323 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
324 mpdm_get_i(lines, drw_1.vy - drw_1.p_lines));
325
326 /* first line start at 0 */
327 drw_2.offsets[0] = 0;
328
329 /* add the following lines and store their offsets */
330 for (n = 1; n < drw_1.n_lines; n++) {
331 /* add the separator */
332 drw_2.ptr = mpdm_pokews(drw_2.ptr, &drw_2.size, L"\n");
333
334 /* this line starts here */
335 drw_2.offsets[n] = drw_2.size;
336
337 /* now add it */
338 drw_2.ptr = mpdm_pokev(drw_2.ptr, &drw_2.size,
339 mpdm_get_i(lines, n + drw_1.vy - drw_1.p_lines));
340 }
341
342 drw_2.ptr = mpdm_poke(drw_2.ptr, &drw_2.size, L"", 1, sizeof(wchar_t));
343 drw_2.size--;
344
345 /* now create a value */
346 mpdm_store(&drw_2.v, MPDM_ENS(drw_2.ptr, drw_2.size));
347
348 /* alloc and init space for the attributes */
349 drw_2.attrs = realloc(drw_2.attrs, drw_2.size + 1);
350 memset(drw_2.attrs, drw_1.normal_attr, drw_2.size + 1);
351
352 drw_2.visible = drw_line_offset(drw_1.vy);
353
354 /* (re)create the maps */
355 n = (drw_1.tx + 1) * drw_1.ty;
356 drw_2.cmap = realloc(drw_2.cmap, n * sizeof(wchar_t));
357 drw_2.amap = realloc(drw_2.amap, n * sizeof(int));
358 drw_2.vx2x = realloc(drw_2.vx2x, n * sizeof(int));
359 drw_2.vy2y = realloc(drw_2.vy2y, n * sizeof(int));
360
361 drw_2.mx = drw_2.my = -1;
362 }
363 else
364 /* drw_1 didn't change */
365 ret = 0;
366
367 mpdm_unref(lines);
368 mpdm_unref(txt);
369 mpdm_unref(config);
370 mpdm_unref(window);
371
372 return ret;
373 }
374
375
drw_fill_attr(int attr,int offset,int size)376 static int drw_fill_attr(int attr, int offset, int size)
377 /* fill an attribute */
378 {
379 if (attr != -1 && offset + size < drw_2.size + 1)
380 memset(drw_2.attrs + offset, attr, size);
381
382 return offset + size;
383 }
384
385
drw_fill_attr_regex(int attr)386 static int drw_fill_attr_regex(int attr)
387 /* fills with an attribute the last regex match */
388 {
389 return drw_fill_attr(attr, mpdm_regex_offset, mpdm_regex_size);
390 }
391
392
drw_words(void)393 static void drw_words(void)
394 /* fills the attributes for separate words */
395 {
396 mpdm_t wcolor, func;
397 int o = drw_2.visible;
398
399 wcolor = mpdm_get_wcs(MP, L"word_color");
400 func = drw_1.word_color_func;
401
402 if (mpdm_count(wcolor) || func) {
403 while (drw_2.ptr[o]) {
404 int ws;
405
406 /* skip non-alpha characters */
407 while (drw_2.ptr[o] && !iswalpha(drw_2.ptr[o]))
408 o++;
409
410 ws = o;
411
412 /* count alpha characters */
413 while(iswalpha(drw_2.ptr[o]))
414 o++;
415
416 if (ws != o) {
417 int attr = -1;
418 mpdm_t w, v;
419
420 /* create a word */
421 w = mpdm_ref(MPDM_NS(&drw_2.ptr[ws], o - ws));
422
423 if ((v = mpdm_get(wcolor, w)) != NULL)
424 attr = mpdm_ival(v);
425 else
426 if (func != NULL)
427 attr = mpdm_ival(mpdm_exec_1(func, w, NULL));
428
429 drw_fill_attr(attr, ws, o - ws);
430
431 mpdm_unref(w);
432 }
433 }
434 }
435 }
436
437
drw_multiline_regex(mpdm_t a,int attr)438 static void drw_multiline_regex(mpdm_t a, int attr)
439 /* sets the attribute to all matching (possibly multiline) regexes */
440 {
441 int n;
442
443 mpdm_ref(a);
444
445 for (n = 0; n < mpdm_size(a); n++) {
446 mpdm_t r = mpdm_get_i(a, n);
447 int o = 0;
448
449 /* if the regex is an array, it's a pair of
450 'match from this' / 'match until this' */
451 if (mpdm_type(r) == MPDM_TYPE_ARRAY) {
452 mpdm_t rs = mpdm_get_i(r, 0);
453 mpdm_t re = mpdm_get_i(r, 1);
454
455 while (!mpdm_is_null(mpdm_regex(drw_2.v, rs, o))) {
456 int s;
457
458 /* fill the matched part */
459 o = drw_fill_attr_regex(attr);
460
461 /* try to match the end */
462 if (!mpdm_is_null(mpdm_regex(drw_2.v, re, o))) {
463 /* found; fill the attribute
464 to the end of the match */
465 s = mpdm_regex_size + (mpdm_regex_offset - o);
466 }
467 else {
468 /* not found; fill to the end
469 of the document */
470 s = drw_2.size - o;
471 }
472
473 /* fill to there */
474 o = drw_fill_attr(attr, o, s);
475 }
476 }
477 else {
478 /* must be a scalar */
479
480 if (*mpdm_string(r) == L'%') {
481 /* it's a sscanf() expression */
482 mpdm_t v;
483
484 while ((v = mpdm_ref(mpdm_sscanf(drw_2.v, r, o)))
485 && mpdm_size(v) == 2) {
486 int i = mpdm_ival(mpdm_get_i(v, 0));
487 int s = mpdm_ival(mpdm_get_i(v, 1)) - i;
488
489 o = drw_fill_attr(attr, i, s);
490
491 mpdm_unref(v);
492 }
493 }
494 else {
495 /* it's a regex */
496 /* while the regex matches, fill attributes */
497 while (!mpdm_is_null(mpdm_regex(drw_2.v, r, o)) && mpdm_regex_size)
498 o = drw_fill_attr_regex(attr);
499 }
500 }
501 }
502
503 mpdm_unref(a);
504 }
505
506
drw_blocks(void)507 static void drw_blocks(void)
508 /* fill attributes for multiline blocks */
509 {
510 mpdm_t defs;
511
512 if (drw_1.syntax && (defs = mpdm_get_wcs(drw_1.syntax, L"defs"))) {
513 int n;
514
515 for (n = 0; n < mpdm_size(defs); n += 2) {
516 mpdm_t attr;
517 mpdm_t list;
518
519 /* get the attribute */
520 attr = mpdm_get_i(defs, n);
521 attr = mpdm_get(drw_1.colors, attr);
522 attr = mpdm_get_wcs(attr, L"attr");
523
524 /* get the list for this word color */
525 list = mpdm_get_i(defs, n + 1);
526
527 drw_multiline_regex(list, mpdm_ival(attr));
528 }
529 }
530 }
531
532
drw_selection(void)533 static void drw_selection(void)
534 /* draws the selected block, if any */
535 {
536 mpdm_t mark;
537 int bx, by, ex, ey, vertical;
538 int so, eo;
539 int mby, mey;
540 int line_offset, next_line_offset;
541 int y;
542 int len;
543 int attr;
544
545 /* no mark? return */
546 if ((mark = mpdm_get_wcs(drw_1.txt, L"mark")) == NULL)
547 return;
548
549 bx = mpdm_ival(mpdm_get_wcs(mark, L"bx"));
550 by = mpdm_ival(mpdm_get_wcs(mark, L"by"));
551 ex = mpdm_ival(mpdm_get_wcs(mark, L"ex"));
552 ey = mpdm_ival(mpdm_get_wcs(mark, L"ey"));
553 vertical = mpdm_ival(mpdm_get_wcs(mark, L"vertical"));
554
555 /* if block is not visible, return */
556 if (ey < drw_1.vy || by >= drw_1.vy + drw_1.ty)
557 return;
558
559 so = by < drw_1.vy ? drw_2.visible : drw_line_offset(by) + bx;
560 eo = ey >= drw_1.vy + drw_1.ty ? drw_2.size : drw_line_offset(ey) + ex;
561
562 /* alloc space and save the attributes being destroyed */
563 drw_2.mark_offset = so;
564 drw_2.mark_size = eo - so + 1;
565 drw_2.mark_o_attr = malloc(eo - so + 1);
566 memcpy(drw_2.mark_o_attr, &drw_2.attrs[so], eo - so + 1);
567
568 if (vertical == 0) {
569 /* normal selection */
570 drw_fill_attr(drw_get_attr(L"selection"), so, eo - so);
571 }
572 else {
573 /* vertical selection */
574 mby = by < drw_1.vy ? drw_1.vy : by;
575 mey = ey >= drw_1.vy + drw_1.ty ? drw_1.vy + drw_1.ty : ey;
576 line_offset = drw_line_offset(mby);
577 attr = drw_get_attr(L"selection");
578 for (y = mby; y <= mey; y++) {
579 next_line_offset = drw_line_offset(y + 1);
580 len = next_line_offset - line_offset - 1;
581 so = bx > len ? -1 : bx;
582 eo = ex > len ? len : ex;
583
584 if (so >= 0 && eo >= so)
585 drw_fill_attr(attr, line_offset + so, eo - so + 1);
586
587 line_offset = next_line_offset;
588 }
589 }
590 }
591
592
drw_search_hit(void)593 static void drw_search_hit(void)
594 /* colorize the search hit, if any */
595 {
596 if (drw_1.last_search != NULL) {
597 mpdm_t l = MPDM_A(0);
598
599 mpdm_set_i(l, drw_1.last_search, 0);
600 drw_multiline_regex(l, drw_get_attr(L"search"));
601 }
602 }
603
604
drw_cursor(void)605 static void drw_cursor(void)
606 /* fill the attribute for the cursor */
607 {
608 /* calculate the cursor offset */
609 drw_2.cursor = drw_line_offset(drw_2.y) + drw_2.x;
610
611 drw_2.cursor_o_attr = drw_2.attrs[drw_2.cursor];
612 drw_fill_attr(drw_1.cursor_attr, drw_2.cursor, 1);
613 }
614
615
drw_matching_paren(void)616 static void drw_matching_paren(void)
617 /* highlights the matching paren */
618 {
619 int o = drw_2.cursor;
620 int i = 0;
621 wchar_t c;
622
623 /* by default, no offset has been found */
624 drw_2.matchparen_offset = -1;
625
626 /* find the opposite and the increment (direction) */
627 switch (drw_2.ptr[o]) {
628 case L'(':
629 c = L')';
630 i = 1;
631 break;
632 case L'{':
633 c = L'}';
634 i = 1;
635 break;
636 case L'[':
637 c = L']';
638 i = 1;
639 break;
640 case L')':
641 c = L'(';
642 i = -1;
643 break;
644 case L'}':
645 c = L'{';
646 i = -1;
647 break;
648 case L']':
649 c = L'[';
650 i = -1;
651 break;
652 }
653
654 /* if a direction is set, do the searching */
655 if (i) {
656 wchar_t s = drw_2.ptr[o];
657 int m = 0;
658 int l = i == -1 ? drw_2.visible - 1 : drw_2.size;
659
660 while (o != l) {
661 if (drw_2.ptr[o] == s) {
662 /* found the same */
663 m++;
664 }
665 else if (drw_2.ptr[o] == c) {
666 /* found the opposite */
667 if (--m == 0) {
668 /* found! fill and exit */
669 drw_2.matchparen_offset = o;
670 drw_2.matchparen_o_attr = drw_2.attrs[o];
671 drw_fill_attr(drw_get_attr(L"matching"), o, 1);
672 break;
673 }
674 }
675
676 o += i;
677 }
678 }
679 }
680
681
drw_push_pair(mpdm_t l,int i,int a,wchar_t * tmp)682 static mpdm_t drw_push_pair(mpdm_t l, int i, int a, wchar_t * tmp)
683 /* pushes a pair of attribute / string into l */
684 {
685 /* create the array, if doesn't exist yet */
686 if (l == NULL)
687 l = MPDM_A(0);
688
689 /* finish the string */
690 tmp[i] = L'\0';
691
692 /* special magic: if the attribute is the
693 one of the cursor and the string is more than
694 one character, create two strings; the
695 cursor is over a tab */
696 if (a == drw_1.cursor_attr && i > 1) {
697 mpdm_push(l, MPDM_I(a));
698 mpdm_push(l, MPDM_NS(tmp, 1));
699
700 /* the rest of the string has the original attr */
701 a = drw_2.cursor_o_attr;
702
703 /* one char less */
704 tmp[i - 1] = L'\0';
705 }
706
707 /* store the attribute and the string */
708 mpdm_push(l, MPDM_I(a));
709 mpdm_push(l, MPDM_S(tmp));
710
711 return l;
712 }
713
714
drw_char(wchar_t c,wchar_t pc,int n)715 static wchar_t drw_char(wchar_t c, wchar_t pc, int n)
716 /* does possible conversions to the char about to be printed */
717 {
718 /* real tab */
719 if (n == 0 && c == L'\t')
720 c = drw_1.wc_tab;
721
722 /* soft hyphen */
723 if (c == L'\xad')
724 c = drw_1.wc_wordwrap; /* cedilla */
725
726 /* m-dash */
727 if (c == L'\x2014')
728 c = drw_1.wc_m_dash;
729
730 if (drw_1.mark_eol) {
731 if (c == L'\t')
732 c = L'\xb7'; /* middledot */
733 else
734 if (c == L'\n' || c == L'\0') {
735 if (pc != L'\xad')
736 c = L'\xb6'; /* pilcrow */
737 else
738 c = L' ';
739 }
740 }
741 else {
742 if (c == L'\t' || c == L'\n' || c == L'\0')
743 c = L' ';
744 }
745
746 /* replace form feed with visual representation and
747 the rest of control codes with the Unicode replace char */
748 if (c == L'\f')
749 c = drw_1.wc_formfeed;
750 else
751 if (c < L' ')
752 c = drw_1.wc_unknown;
753
754 return c;
755 }
756
757
drw_map_1(int mx,int my,wchar_t c,int a,int x,int y)758 static void drw_map_1(int mx, int my, wchar_t c, int a, int x, int y)
759 {
760 int o = mx + my * (drw_1.tx + 1);
761
762 drw_2.cmap[o] = c;
763 drw_2.amap[o] = a;
764 drw_2.vx2x[o] = x;
765 drw_2.vy2y[o] = y;
766
767 if (a == drw_1.cursor_attr) {
768 drw_2.mx = mx;
769 drw_2.my = my;
770 }
771 }
772
773
vpos2pos(int mx,int my,int * x,int * y)774 static void vpos2pos(int mx, int my, int *x, int *y)
775 {
776 if (my < 0) {
777 /* above top margin: pick previous line */
778 *x = mx;
779 *y = drw_1.vy - 2;
780 }
781 else
782 if (my > drw_1.ty - 1) {
783 /* below bottom margin: pick next line */
784 *x = mx;
785 *y = drw_1.vy + drw_1.ty;
786 }
787 else {
788 /* in range: pick from the map */
789 int o = mx + my * (drw_1.tx + 1);
790
791 *x = drw_2.vx2x[o];
792 *y = drw_2.vy2y[o];
793 }
794 }
795
796
drw_remap_truncate(void)797 static void drw_remap_truncate(void)
798 {
799 int i = drw_2.offsets[drw_1.p_lines];
800 int mx, my;
801 int x, y;
802
803 x = 0;
804 y = drw_1.vy;
805
806 for (my = 0; my < drw_1.ty; my++) {
807 wchar_t c, pc = 0;
808 int ax = 0;
809 mx = 0;
810
811 do {
812 c = drw_2.ptr[i];
813 int t = drw_wcwidth(mx, c);
814 int n;
815
816 if (c == '\0')
817 break;
818
819 for (n = 0; n < t && mx < drw_1.tx; n++) {
820 if (ax >= drw_1.vx)
821 drw_map_1(mx++, my, drw_char(c, pc, n), drw_2.attrs[i], x, y);
822 ax++;
823 }
824
825 i++;
826
827 if (c == '\n')
828 break;
829
830 x++;
831 pc = c;
832
833 } while (mx < drw_1.tx);
834
835 while (mx < drw_1.tx)
836 drw_map_1(mx++, my, '.', -1, x, y);
837
838 while (c != '\n' && c != '\0')
839 c = drw_2.ptr[i++];
840
841 if (c == '\n') {
842 x = 0;
843 y++;
844 }
845 }
846 }
847
848
drw_double_page(void)849 static void drw_double_page(void)
850 /* recompose a double page char-mapped buffer */
851 {
852 if (drw_1.double_page) {
853 int n, m;
854 wchar_t *dp_cmap = drw_2.cmap;
855 int *dp_amap = drw_2.amap;
856 int *dp_vx2x = drw_2.vx2x;
857 int *dp_vy2y = drw_2.vy2y;
858 int o = 0;
859
860 n = (drw_1.tx + 1) * drw_1.ty;
861 drw_2.cmap = calloc(n, sizeof(wchar_t));
862 drw_2.amap = calloc(n, sizeof(int));
863 drw_2.vx2x = calloc(n, sizeof(int));
864 drw_2.vy2y = calloc(n, sizeof(int));
865
866 for (n = 0; n < drw_1.ty / 2; n++) {
867 int i;
868
869 /* copy first column */
870 i = n * (drw_1.tx + 1);
871
872 for (m = 0; m < drw_1.tx && dp_amap[i] != -1; m++) {
873 drw_2.amap[o] = dp_amap[i];
874 drw_2.cmap[o] = dp_cmap[i];
875 drw_2.vx2x[o] = dp_vx2x[i];
876 drw_2.vy2y[o] = dp_vy2y[i];
877
878 i++;
879 o++;
880 }
881
882 /* fill up to next column with spaces */
883 for (; m < drw_1.tx; m++) {
884 drw_2.amap[o] = drw_1.normal_attr;
885 drw_2.cmap[o] = L' ';
886 drw_2.vx2x[o] = dp_vx2x[i];
887 drw_2.vy2y[o] = dp_vy2y[i];
888
889 o++;
890 }
891
892 /* put the column separator */
893 drw_2.amap[o] = drw_1.normal_attr;
894 drw_2.cmap[o] = L'\x2502';
895 o++;
896
897 /* copy the second column */
898 i = (n - 1 + drw_1.ty / 2) * (drw_1.tx + 1);
899
900 for (m = 0; m < drw_1.tx; m++) {
901 drw_2.amap[o] = dp_amap[i];
902 drw_2.cmap[o] = dp_cmap[i];
903 drw_2.vx2x[o] = dp_vx2x[i];
904 drw_2.vy2y[o] = dp_vy2y[i];
905
906 i++;
907 o++;
908 }
909 }
910
911 /* restore size */
912 drw_1.tx *= 2;
913 drw_1.ty /= 2;
914
915 free(dp_cmap);
916 free(dp_amap);
917 }
918 }
919
920
drw_remap_to_array(void)921 static mpdm_t drw_remap_to_array(void)
922 /* converts the char-mapped buffer to arrays of attr, string per line */
923 {
924 mpdm_t r = MPDM_A(0);
925 wchar_t *line = malloc((drw_1.tx + 1) * sizeof(wchar_t));
926 int my;
927 mpdm_t fmt = NULL;
928
929 if (drw_1.xoffset) {
930 fmt = mpdm_ref(mpdm_strcat(MPDM_S(L" %"),
931 mpdm_strcat_wcs(MPDM_I(drw_1.xoffset - 2), L"d ")));
932 }
933
934 for (my = 0; my < drw_1.ty; my++) {
935 mpdm_t l = MPDM_A(0);
936 int o = my * (drw_1.tx + 1);
937 int mx = 0;
938
939 if (drw_1.xoffset && drw_1.vy + my < drw_1.t_lines) {
940 mpdm_push(l, MPDM_I(drw_1.normal_attr));
941 mpdm_push(l, mpdm_fmt(fmt, MPDM_I(drw_1.vy + 1 + my)));
942 }
943
944 while (mx < drw_1.tx && drw_2.amap[o] != -1) {
945 int i = 0;
946 int a = drw_2.amap[o];
947
948 while (a == drw_2.amap[o] && mx++ < drw_1.tx)
949 line[i++] = drw_2.cmap[o++];
950
951 line[i] = L'\0';
952
953 l = drw_push_pair(l, i, a, line);
954 }
955
956 mpdm_push(r, l);
957 }
958
959 free(line);
960
961 mpdm_unref(fmt);
962
963 return r;
964 }
965
966
drw_optimize_array(mpdm_t a,int optimize)967 static mpdm_t drw_optimize_array(mpdm_t a, int optimize)
968 /* optimizes the array, NULLifying all lines that are the same as the last time */
969 {
970 mpdm_t o = drw_2.old;
971 mpdm_t r = a;
972
973 mpdm_ref(a);
974
975 if (optimize && o != NULL) {
976 int n = 0;
977
978 /* creates a copy */
979 r = mpdm_clone(a);
980
981 mpdm_ref(r);
982
983 /* compare each array */
984 while (n < mpdm_size(o) && n < mpdm_size(r)) {
985 /* if both lines are equal, optimize out */
986 if (mpdm_cmp(mpdm_get_i(o, n), mpdm_get_i(r, n)) == 0)
987 mpdm_set_i(r, NULL, n);
988
989 n++;
990 }
991
992 mpdm_unrefnd(r);
993 }
994
995 mpdm_store(&drw_2.old, a);
996
997 mpdm_unref(a);
998
999 return r;
1000 }
1001
1002
drw_restore_attrs(void)1003 static void drw_restore_attrs(void)
1004 /* restored the patched attrs */
1005 {
1006 /* matching paren, if any */
1007 if (drw_2.matchparen_offset != -1)
1008 drw_fill_attr(drw_2.matchparen_o_attr, drw_2.matchparen_offset, 1);
1009
1010 /* cursor */
1011 drw_fill_attr(drw_2.cursor_o_attr, drw_2.cursor, 1);
1012
1013 /* marked block, if any */
1014 if (drw_2.mark_o_attr != NULL) {
1015 memcpy(&drw_2.attrs[drw_2.mark_offset], drw_2.mark_o_attr,
1016 drw_2.mark_size);
1017
1018 free(drw_2.mark_o_attr);
1019 drw_2.mark_o_attr = NULL;
1020 }
1021 }
1022
1023
drw_draw(mpdm_t doc,int optimize)1024 static mpdm_t drw_draw(mpdm_t doc, int optimize)
1025 /* main document drawing function: takes a document and returns an array of
1026 arrays of attribute / string pairs */
1027 {
1028 mpdm_t r = NULL, w;
1029
1030 if (drw_prepare(doc)) {
1031 /* colorize separate words */
1032 drw_words();
1033
1034 /* colorize multiline blocks */
1035 drw_blocks();
1036 }
1037
1038 /* now set the marked block (if any) */
1039 drw_selection();
1040
1041 /* colorize the search hit */
1042 drw_search_hit();
1043
1044 /* the cursor */
1045 drw_cursor();
1046
1047 /* highlight the matching paren */
1048 drw_matching_paren();
1049
1050 /* convert to an array of string / atribute pairs */
1051 drw_remap_truncate();
1052
1053 drw_double_page();
1054
1055 r = drw_remap_to_array();
1056
1057 /* optimize */
1058 r = drw_optimize_array(r, optimize);
1059
1060 /* restore the patched attrs */
1061 drw_restore_attrs();
1062
1063 w = mpdm_get_wcs(MP, L"window");
1064 mpdm_set_wcs(w, MPDM_I(drw_2.mx), L"mx");
1065 mpdm_set_wcs(w, MPDM_I(drw_2.my), L"my");
1066
1067 return r;
1068 }
1069
1070
1071 /** interface **/
1072
mp_draw(mpdm_t doc,int optimize)1073 mpdm_t mp_draw(mpdm_t doc, int optimize)
1074 /* main generic drawing function for drivers */
1075 {
1076 mpdm_t f, r = NULL;
1077 static mpdm_t d = NULL;
1078
1079 if (doc != d) {
1080 optimize = 0;
1081 mpdm_store(&d, doc);
1082 }
1083
1084 if ((f = mpdm_get_wcs(doc, L"render")) != NULL) {
1085 /* create a context to contain the object itself
1086 (i.e. call as a method) */
1087 mpdm_t ctxt = MPDM_A(0);
1088
1089 mpdm_push(ctxt, doc);
1090 r = mpdm_exec_2(f, doc, MPDM_I(optimize), ctxt);
1091 }
1092
1093 return r;
1094 }
1095
1096
1097 #define THR_SPEED_STEP 10
1098 #define THR_MAX_SPEED 7
1099
mp_keypress_throttle(int keydown)1100 int mp_keypress_throttle(int keydown)
1101 /* processes key acceleration and throttle */
1102 {
1103 #ifdef USE_THROTTLE
1104 static int keydowns = 0;
1105 static int seq = 0;
1106 int redraw = 0;
1107
1108 if (keydown) {
1109 int speed;
1110
1111 /* as keydowns accumulate, speed increases, which is the number
1112 of cycles the redraw will be skipped (up to a maximum) */
1113 if ((speed = 1 + (++keydowns / THR_SPEED_STEP)) > THR_MAX_SPEED)
1114 speed = THR_MAX_SPEED;
1115
1116 if (++seq % speed == 0)
1117 redraw = 1;
1118 }
1119 else {
1120 if (keydowns > 1)
1121 redraw = 1;
1122
1123 keydowns = 0;
1124 }
1125
1126 return redraw;
1127
1128 #else /* USE_THROTTLE */
1129 return 1;
1130 #endif /* USE_THROTTLE */
1131 }
1132
1133
mp_active(void)1134 mpdm_t mp_active(void)
1135 /* interface to mp.active() */
1136 {
1137 return mpdm_exec(mpdm_get_wcs(MP, L"active"), NULL, NULL);
1138 }
1139
1140
mp_process_action(mpdm_t action)1141 void mp_process_action(mpdm_t action)
1142 /* interface to mp.process_action() */
1143 {
1144 mpdm_void(mpdm_exec_1(mpdm_get_wcs(MP, L"process_action"), action, NULL));
1145 }
1146
1147
mp_process_event(mpdm_t keycode)1148 void mp_process_event(mpdm_t keycode)
1149 /* interface to mp.process_event() */
1150 {
1151 mpdm_void(mpdm_exec_1(mpdm_get_wcs(MP, L"process_event"), keycode, NULL));
1152 }
1153
1154
mp_set_y(mpdm_t doc,int y)1155 void mp_set_y(mpdm_t doc, int y)
1156 /* interface to mp.set_y() */
1157 {
1158 mpdm_void(mpdm_exec_2(mpdm_get_wcs(doc, L"set_y"), doc, MPDM_I(y), NULL));
1159 }
1160
1161
mp_build_status_line(void)1162 mpdm_t mp_build_status_line(void)
1163 /* interface to mp.build_status_line() */
1164 {
1165 return mpdm_exec(mpdm_get_wcs(MP, L"build_status_line"), NULL, NULL);
1166 }
1167
1168
mp_get_history(mpdm_t key)1169 mpdm_t mp_get_history(mpdm_t key)
1170 /* interface to mp.get_history() */
1171 {
1172 return mpdm_exec_1(mpdm_get_wcs(MP, L"get_history"), key, NULL);
1173 }
1174
1175
mp_get_doc_names(void)1176 mpdm_t mp_get_doc_names(void)
1177 /* interface to mp.get_doc_names() */
1178 {
1179 return mpdm_exec(mpdm_get_wcs(MP, L"get_doc_names"), NULL, NULL);
1180 }
1181
1182
mp_menu_label(mpdm_t action)1183 mpdm_t mp_menu_label(mpdm_t action)
1184 /* interface to mp.menu_label() */
1185 {
1186 return mpdm_exec_1(mpdm_get_wcs(MP, L"menu_label"), action, NULL);
1187 }
1188
1189
mp_c_exit(mpdm_t args,mpdm_t ctxt)1190 mpdm_t mp_c_exit(mpdm_t args, mpdm_t ctxt)
1191 /* exit the editor (set mp_exit_requested) */
1192 {
1193 mp_exit_requested = 1;
1194
1195 return NULL;
1196 }
1197
1198
mp_c_exit_requested(mpdm_t args,mpdm_t ctxt)1199 static mpdm_t mp_c_exit_requested(mpdm_t args, mpdm_t ctxt)
1200 /* returns the value of the mp_exit_requested variable */
1201 {
1202 return MPDM_I(mp_exit_requested);
1203 }
1204
1205
mp_c_render(mpdm_t args,mpdm_t ctxt)1206 mpdm_t mp_c_render(mpdm_t args, mpdm_t ctxt)
1207 {
1208 return drw_draw(mpdm_get_i(args, 0), mpdm_ival(mpdm_get_i(args, 1)));
1209 }
1210
1211
mp_c_vx2x(mpdm_t args,mpdm_t ctxt)1212 mpdm_t mp_c_vx2x(mpdm_t args, mpdm_t ctxt)
1213 /* interface to drw_vx2x() */
1214 {
1215 return MPDM_I(drw_vx2x(mpdm_get_i(args, 0), mpdm_ival(mpdm_get_i(args, 1))));
1216 }
1217
1218
mp_c_x2vx(mpdm_t args,mpdm_t ctxt)1219 mpdm_t mp_c_x2vx(mpdm_t args, mpdm_t ctxt)
1220 /* interface to drw_x2vx() */
1221 {
1222 return MPDM_I(drw_x2vx(mpdm_get_i(args, 0), mpdm_ival(mpdm_get_i(args, 1))));
1223 }
1224
1225
mp_c_vpos2pos(mpdm_t args,mpdm_t ctxt)1226 mpdm_t mp_c_vpos2pos(mpdm_t args, mpdm_t ctxt)
1227 {
1228 mpdm_t r = MPDM_A(2);
1229 int x = mpdm_ival(mpdm_get_i(args, 0));
1230 int y = mpdm_ival(mpdm_get_i(args, 1));
1231
1232 vpos2pos(x, y, &x, &y);
1233
1234 mpdm_set_i(r, MPDM_I(x), 0);
1235 mpdm_set_i(r, MPDM_I(y), 1);
1236
1237 return r;
1238 }
1239
1240
mp_c_search_hex(mpdm_t args,mpdm_t ctxt)1241 mpdm_t mp_c_search_hex(mpdm_t args, mpdm_t ctxt)
1242 /* search the hex string str in the file */
1243 {
1244 mpdm_t fd = mpdm_get_i(args, 0);
1245 mpdm_t str = mpdm_get_i(args, 1);
1246 FILE *f = mpdm_get_filehandle(fd);
1247 wchar_t *s = mpdm_string(str);
1248 int n = 0;
1249 unsigned char *ptr;
1250 off_t o;
1251 int found = 0;
1252
1253 /* parse str into a binary buffer */
1254 ptr = malloc(wcslen(s) + 1);
1255 while (s[0] && s[1]) {
1256 char tmp[3];
1257 int c;
1258
1259 tmp[0] = (char)s[0];
1260 tmp[1] = (char)s[1];
1261 sscanf(tmp, "%02x", &c);
1262
1263 ptr[n++] = (unsigned char) c;
1264 s += 2;
1265 }
1266 ptr[n] = 0;
1267
1268 /* start searching */
1269 o = ftell(f);
1270 while (!found && !feof(f)) {
1271 int c;
1272
1273 fseek(f, o, 0);
1274 n = 0;
1275
1276 while (!found && (c = fgetc(f)) != EOF) {
1277 if (c == ptr[n]) {
1278 n++;
1279
1280 if (ptr[n] == '\0')
1281 found = 1;
1282 }
1283 else {
1284 o++;
1285 break;
1286 }
1287 }
1288 }
1289
1290 if (found)
1291 fseek(f, o, 0);
1292
1293 free(ptr);
1294
1295 return MPDM_I(found);
1296 }
1297
1298
mp_c_get_offset(mpdm_t args,mpdm_t ctxt)1299 mpdm_t mp_c_get_offset(mpdm_t args, mpdm_t ctxt)
1300 /* gets the character offset at lines[y][0] */
1301 {
1302 mpdm_t lines = mpdm_get_i(args, 0);
1303 int y = mpdm_ival(mpdm_get_i(args, 1));
1304 int n, o = 0;
1305
1306 for (n = 0; n < y; n++) {
1307 mpdm_t v = mpdm_get_i(lines, n);
1308 wchar_t *ptr = mpdm_string(v);
1309 int z = wcslen(ptr);
1310
1311 /* count 1 less if it ends in soft-hyphen, 1 more if not */
1312 z += (z && ptr[z - 1] == 0xad) ? -1 : 1;
1313
1314 o += z;
1315 }
1316
1317 return MPDM_I(o);
1318 }
1319
1320
mp_c_set_offset(mpdm_t args,mpdm_t ctxt)1321 mpdm_t mp_c_set_offset(mpdm_t args, mpdm_t ctxt)
1322 /* gets the x, y position of offset */
1323 {
1324 mpdm_t lines = mpdm_get_i(args, 0);
1325 int o = mpdm_ival(mpdm_get_i(args, 1));
1326 int n, y = 0;
1327 mpdm_t r;
1328
1329 for (n = 0; n < mpdm_size(lines); n++) {
1330 mpdm_t v = mpdm_get_i(lines, n);
1331 wchar_t *ptr = mpdm_string(v);
1332 int z = wcslen(ptr);
1333
1334 /* count 1 less if it ends in soft-hyphen, 1 more if not */
1335 z += (z && ptr[z - 1] == 0xad) ? -1 : 1;
1336
1337 if (o <= z)
1338 break;
1339
1340 o -= z;
1341 y++;
1342 }
1343
1344 r = MPDM_A(2);
1345 mpdm_set_i(r, MPDM_I(o), 0);
1346 mpdm_set_i(r, MPDM_I(y), 1);
1347
1348 return r;
1349 }
1350
1351
mp_c_vw_unwrap(mpdm_t args,mpdm_t ctxt)1352 mpdm_t mp_c_vw_unwrap(mpdm_t args, mpdm_t ctxt)
1353 /* unwraps lines wrapped by soft-hyphens */
1354 {
1355 mpdm_t lines = mpdm_get_i(args, 0);
1356 mpdm_t v = mpdm_get_i(args, 1);
1357 int y, o1;
1358
1359 /* y not set? wrap the full array */
1360 if (v == NULL) {
1361 y = 0;
1362 o1 = 0;
1363 }
1364 else {
1365 y = mpdm_ival(v);
1366 o1 = 1;
1367 }
1368
1369 while (y < mpdm_size(lines)) {
1370 wchar_t *ptr;
1371 int z;
1372
1373 v = mpdm_get_i(lines, y);
1374
1375 /* while this line ends in a soft-hyphen... */
1376 while ((ptr = mpdm_string(v)) && (z = wcslen(ptr)) > 1 && ptr[z - 1] == L'\xad') {
1377 /* join this line (without the soft-hyphen) with next line */
1378 v = mpdm_strcat(MPDM_NS(ptr, z - 1), mpdm_get_i(lines, y + 1));
1379
1380 /* store in the array */
1381 mpdm_set_i(lines, v, y);
1382
1383 /* delete next line */
1384 mpdm_del_i(lines, y + 1);
1385 }
1386
1387 /* only one? done */
1388 if (o1)
1389 break;
1390
1391 y++;
1392 }
1393
1394 return lines;
1395 }
1396
1397
mp_c_vw_wrap(mpdm_t args,mpdm_t ctxt)1398 mpdm_t mp_c_vw_wrap(mpdm_t args, mpdm_t ctxt)
1399 /* rewrap lines to max */
1400 {
1401 mpdm_t lines = mpdm_get_i(args, 0);
1402 int max = mpdm_ival(mpdm_get_i(args, 1));
1403 mpdm_t v = mpdm_get_i(args, 2);
1404 int y, o1;
1405
1406 /* convert args from lines, max, y to lines, y */
1407 mpdm_del_i(args, 1);
1408
1409 /* unwrap first */
1410 mp_c_vw_unwrap(args, ctxt);
1411
1412 /* y not set? wrap the full array */
1413 if (v == NULL) {
1414 y = 0;
1415 o1 = 0;
1416 }
1417 else {
1418 y = mpdm_ival(v);
1419 o1 = 1;
1420 }
1421
1422 while (y < mpdm_size(lines)) {
1423 wchar_t *ptr;
1424
1425 v = mpdm_get_i(lines, y);
1426
1427 /* while this line is longer than max... */
1428 while ((ptr = mpdm_string(v)) && wcslen(ptr) > max) {
1429 mpdm_t w;
1430 int m = max;
1431 wchar_t *ptr2;
1432
1433 /* wrap by word */
1434 while (m > 0 && ptr[m] == L' ')
1435 m--;
1436 while (m > 0 && ptr[m] != L' ')
1437 m--;
1438
1439 if (m == 0)
1440 m = max;
1441
1442 /* build the first part */
1443 ptr2 = calloc((m + 3), sizeof(wchar_t));
1444 wcsncpy(ptr2, ptr, m + 1);
1445 ptr2[m + 1] = L'\xad';
1446 w = MPDM_ENS(ptr2, m + 2);
1447
1448 /* build the second part */
1449 v = MPDM_S(&ptr[m + 1]);
1450
1451 /* set the first part */
1452 mpdm_set_i(lines, w, y);
1453
1454 /* insert the second part */
1455 y++;
1456 mpdm_ins(lines, v, y);
1457 }
1458
1459 /* only one? done */
1460 if (o1)
1461 break;
1462
1463 y++;
1464 }
1465
1466 return lines;
1467 }
1468
1469
find_in_embedded_arch(mpdm_t args,mpdm_t ctxt)1470 static mpdm_t find_in_embedded_arch(mpdm_t args, mpdm_t ctxt)
1471 /* searches for embedded MPSL code */
1472 {
1473 return mpdm_read_arch_mem_s(mpdm_get_i(args, 0), ARCH_START, ARCH_END);
1474 }
1475
1476
ni_drv_startup(mpdm_t v)1477 mpdm_t ni_drv_startup(mpdm_t v)
1478 {
1479 return NULL;
1480 }
1481
1482
ni_drv_detect(int * argc,char *** argv)1483 int ni_drv_detect(int *argc, char ***argv)
1484 {
1485 int n, ret = 0;
1486
1487 for (n = 0; n < *argc; n++) {
1488 if (strcmp(argv[0][n], "-ni") == 0 || strcmp(argv[0][n], "-F") == 0)
1489 ret = 1;
1490 }
1491
1492 if (ret) {
1493 mpdm_t drv;
1494
1495 drv = mpdm_set_wcs(mpdm_root(), MPDM_O(), L"mp_drv");
1496 mpdm_set_wcs(drv, MPDM_S(L"ni"), L"id");
1497 mpdm_set_wcs(drv, MPDM_X(ni_drv_startup), L"startup");
1498 }
1499
1500 return ret;
1501 }
1502
1503
mp_startup(int argc,char * argv[])1504 void mp_startup(int argc, char *argv[])
1505 {
1506 mpdm_t INC;
1507 char *ptr;
1508 mpdm_t mp_c;
1509
1510 mpdm_startup();
1511 mpdm_set_wcs(mpdm_root(), MPDM_MBS(CONFOPT_APPNAME), L"APPID");
1512
1513 mpsl_startup();
1514
1515 /* reset the structures */
1516 memset(&drw_1, '\0', sizeof(drw_1));
1517 memset(&drw_1_o, '\0', sizeof(drw_1_o));
1518
1519 /* set an initial value for drw_1.tab_size:
1520 drw_wcwidth() may be called before drw_1 being filled
1521 by drw_prepare() (when opening files from the command
1522 line and mp.config.visual_wrap == 1) */
1523 drw_1.tab_size = 1;
1524
1525 /* new mp_c namespace (C interface) */
1526 mp_c = mpdm_set_wcs(mpdm_root(), MPDM_O(), L"mp_c");
1527
1528 /* version */
1529 mpdm_set_wcs(mp_c, MPDM_S(L"" VERSION), L"VERSION");
1530 mpdm_set_wcs(mp_c, MPDM_X(mp_c_x2vx), L"x2vx");
1531 mpdm_set_wcs(mp_c, MPDM_X(mp_c_vx2x), L"vx2x");
1532 mpdm_set_wcs(mp_c, MPDM_X(mp_c_vpos2pos), L"vpos2pos");
1533 mpdm_set_wcs(mp_c, MPDM_X(mp_c_exit), L"exit");
1534 mpdm_set_wcs(mp_c, MPDM_X(mp_c_exit_requested), L"exit_requested");
1535 mpdm_set_wcs(mp_c, MPDM_X(mp_c_render), L"render");
1536 mpdm_set_wcs(mp_c, MPDM_X(mp_c_search_hex), L"search_hex");
1537 mpdm_set_wcs(mp_c, MPDM_X(mp_c_get_offset), L"get_offset");
1538 mpdm_set_wcs(mp_c, MPDM_X(mp_c_set_offset), L"set_offset");
1539 mpdm_set_wcs(mp_c, MPDM_X(mp_c_vw_unwrap), L"vw_unwrap");
1540 mpdm_set_wcs(mp_c, MPDM_X(mp_c_vw_wrap), L"vw_wrap");
1541
1542 /* creates the INC (executable path) array */
1543 INC = mpdm_set_wcs(mpdm_root(), MPDM_A(0), L"INC");
1544
1545 /* if the MP_LIBRARY_PATH environment variable is set,
1546 put it before anything else */
1547 if ((ptr = getenv("MP_LIBRARY_PATH")) != NULL)
1548 mpdm_push(INC, MPDM_MBS(ptr));
1549
1550 /* add code library as embedded archive */
1551 mpdm_push(INC, MPDM_X(find_in_embedded_arch));
1552
1553 /* add code library as externally installed zip */
1554 mpdm_push(INC, mpdm_strcat_wcs(
1555 mpdm_get_wcs(mpdm_root(), L"APPDIR"), L"/mp.zip"));
1556
1557 /* add code library as externally installed tar */
1558 mpdm_push(INC, mpdm_strcat_wcs(
1559 mpdm_get_wcs(mpdm_root(), L"APPDIR"), L"/mp.tar"));
1560
1561 if (!ni_drv_detect(&argc, &argv) && !TRY_DRIVERS()) {
1562 printf("No usable driver found; exiting.\n");
1563 exit(1);
1564 }
1565
1566 mpsl_argv(argc, argv);
1567 }
1568
1569
mp_mpsl(void)1570 void mp_mpsl(void)
1571 {
1572 mpdm_t e;
1573
1574 mpdm_void(mpsl_eval(MPDM_S(L"load('mp_core.mpsl');"), NULL, NULL));
1575
1576 if ((e = mpdm_get_wcs(mpdm_root(), L"ERROR")) != NULL) {
1577 mpdm_write_wcs(stdout, mpdm_string(e));
1578 printf("\n");
1579 }
1580 }
1581
1582
mp_shutdown(void)1583 void mp_shutdown(void)
1584 {
1585 /* unref pending values */
1586 mpdm_unref(drw_1.txt);
1587 mpdm_unref(drw_2.v);
1588 mpdm_unref(drw_2.old);
1589
1590 #ifdef DEBUG_CLEANUP
1591 mpdm_unref(mpdm_root());
1592 #endif
1593
1594 mpsl_shutdown();
1595 }
1596
1597
main(int argc,char * argv[])1598 int main(int argc, char *argv[])
1599 {
1600 mp_startup(argc, argv);
1601
1602 mp_mpsl();
1603
1604 mp_shutdown();
1605
1606 return 0;
1607 }
1608