1 /*
2 * Basic user edit functions
3 * Copyright
4 * (C) 1992 Joseph H. Allen
5 *
6 * This file is part of JOE (Joe's Own Editor)
7 */
8 #include "types.h"
9
10 /***************/
11 /* Global options */
12 int pgamnt = -1; /* No. of PgUp/PgDn lines to keep */
13
14 /*
15 * Move cursor to beginning of line
16 */
u_goto_bol(W * w,int k)17 int u_goto_bol(W *w, int k)
18 {
19 BW *bw;
20 WIND_BW(bw, w);
21 if (bw->o.hex) {
22 pbkwd(bw->cursor,bw->cursor->byte%16);
23 } else {
24 p_goto_bol(bw->cursor);
25 }
26 return 0;
27 }
28
29 /*
30 * Move cursor to first non-whitespace character, unless it is
31 * already there, in which case move it to beginning of line
32 */
uhome(W * w,int k)33 int uhome(W *w, int k)
34 {
35 BW *bw;
36 P *p;
37 WIND_BW(bw, w);
38
39 if (bw->o.hex) {
40 return u_goto_bol(w, 0);
41 }
42
43 p = pdup(bw->cursor, "uhome");
44
45 if (bw->o.indentfirst) {
46 if ((bw->o.smarthome) && (piscol(p) > pisindent(p))) {
47 p_goto_bol(p);
48 while (joe_isblank(p->b->o.charmap,brc(p)))
49 pgetc(p);
50 } else
51 p_goto_bol(p);
52 } else {
53 if (bw->o.smarthome && piscol(p)==0 && pisindent(p)) {
54 while (joe_isblank(p->b->o.charmap,brc(p)))
55 pgetc(p);
56 } else
57 p_goto_bol(p);
58 }
59
60 pset(bw->cursor, p);
61 prm(p);
62 return 0;
63 }
64
65 /*
66 * Move cursor to end of line
67 */
u_goto_eol(W * w,int k)68 int u_goto_eol(W *w, int k)
69 {
70 BW *bw;
71 WIND_BW(bw, w);
72 if (bw->o.hex) {
73 if (bw->cursor->byte + 15 - bw->cursor->byte%16 > bw->b->eof->byte)
74 pset(bw->cursor,bw->b->eof);
75 else
76 pfwrd(bw->cursor, 15 - bw->cursor->byte%16);
77 } else
78 p_goto_eol(bw->cursor);
79 return 0;
80 }
81
82 /*
83 * Move cursor to beginning of file
84 */
u_goto_bof(W * w,int k)85 int u_goto_bof(W *w, int k)
86 {
87 BW *bw;
88 WIND_BW(bw, w);
89 p_goto_bof(bw->cursor);
90 return 0;
91 }
92
93 /*
94 * Move cursor to end of file
95 */
u_goto_eof(W * w,int k)96 int u_goto_eof(W *w, int k)
97 {
98 BW *bw;
99 WIND_BW(bw, w);
100 if (bw->b->vt && bw->b->pid) {
101 pset(bw->cursor, bw->b->vt->vtcur);
102 } else {
103 p_goto_eof(bw->cursor);
104 }
105 return 0;
106 }
107
108 /*
109 * Move cursor left
110 */
u_goto_left(W * w,int k)111 int u_goto_left(W *w, int k)
112 {
113 BW *bw;
114 WIND_BW(bw, w);
115 if (bw->o.hex) {
116 if (prgetb(bw->cursor) != NO_MORE_DATA) {
117 return 0;
118 } else {
119 return -1;
120 }
121 }
122 if (bw->o.picture) {
123 if (bw->cursor->xcol) {
124 --bw->cursor->xcol;
125 pcol(bw->cursor,bw->cursor->xcol);
126 return 0;
127 } else
128 return -1;
129 } else {
130 /* Have to do ECHKXCOL here because of picture mode */
131 if (bw->cursor->xcol != piscol(bw->cursor)) {
132 bw->cursor->xcol = piscol(bw->cursor);
133 return 0;
134 } else if (prgetc(bw->cursor) != NO_MORE_DATA) {
135 bw->cursor->xcol = piscol(bw->cursor);
136 return 0;
137 } else {
138 return -1;
139 }
140 }
141 }
142
143 /*
144 * Move cursor right
145 */
u_goto_right(W * w,int k)146 int u_goto_right(W *w, int k)
147 {
148 BW *bw;
149 WIND_BW(bw, w);
150 if (bw->o.hex) {
151 if (pgetb(bw->cursor) != NO_MORE_DATA) {
152 return 0;
153 } else {
154 return -1;
155 }
156 }
157 if (bw->o.picture) {
158 ++bw->cursor->xcol;
159 pcol(bw->cursor,bw->cursor->xcol);
160 return 0;
161 } else {
162 int rtn;
163 if (pgetc(bw->cursor) != NO_MORE_DATA) {
164 bw->cursor->xcol = piscol(bw->cursor);
165 rtn = 0;
166 } else {
167 rtn = -1;
168 }
169 /* Have to do EFIXXCOL here because of picture mode */
170 if (bw->cursor->xcol != piscol(bw->cursor))
171 bw->cursor->xcol = piscol(bw->cursor);
172 return rtn;
173 }
174 }
175
176 /*
177 * Move cursor to beginning of previous word or if there isn't
178 * previous word then go to beginning of the file
179 *
180 * WORD is a sequence non-white-space characters
181 */
p_goto_prev(P * ptr)182 static int p_goto_prev(P *ptr)
183 {
184 P *p = pdup(ptr, "p_goto_prev");
185 struct charmap *map=ptr->b->o.charmap;
186 int c = prgetc(p);
187
188 if (joe_isalnum_(map,c)) {
189 while (joe_isalnum_(map,(c=prgetc(p))))
190 /* Do nothing */;
191 if (c != NO_MORE_DATA)
192 pgetc(p);
193 } else if (joe_isspace(map,c) || joe_ispunct(map,c)) {
194 while ((c=prgetc(p)), (joe_isspace(map,c) || joe_ispunct(map,c)))
195 /* Do nothing */;
196 while(joe_isalnum_(map,(c=prgetc(p))))
197 /* Do nothing */;
198 if (c != NO_MORE_DATA)
199 pgetc(p);
200 }
201 pset(ptr, p);
202 prm(p);
203 return 0;
204 }
205
u_goto_prev(W * w,int k)206 int u_goto_prev(W *w, int k)
207 {
208 BW *bw;
209 WIND_BW(bw, w);
210 return p_goto_prev(bw->cursor);
211 }
212
213 /*
214 * Move cursor to end of next word or if there isn't
215 * next word then go to end of the file
216 *
217 * WORD is a sequence non-white-space characters
218 */
p_goto_next(P * ptr)219 static int p_goto_next(P *ptr)
220 {
221 P *p = pdup(ptr, "p_goto_next");
222 struct charmap *map=ptr->b->o.charmap;
223 int c = brch(p);
224 int rtn = -1;
225
226 if (joe_isalnum_(map,c)) {
227 rtn = 0;
228 while (joe_isalnum_(map,(c = brch(p))))
229 pgetc(p);
230 } else if (joe_isspace(map,c) || joe_ispunct(map,c)) {
231 while (joe_isspace(map, (c = brch(p))) || joe_ispunct(map,c))
232 pgetc(p);
233 while (joe_isalnum_(map,(c = brch(p)))) {
234 rtn = 0;
235 pgetc(p);
236 }
237 } else
238 pgetc(p);
239 pset(ptr, p);
240 prm(p);
241 return rtn;
242 }
243
u_goto_next(W * w,int k)244 int u_goto_next(W *w, int k)
245 {
246 BW *bw;
247 WIND_BW(bw, w);
248 return p_goto_next(bw->cursor);
249 }
250
pboi(P * p)251 static P *pboi(P *p)
252 {
253 p_goto_bol(p);
254 while (joe_isblank(p->b->o.charmap,brc(p)))
255 pgetc(p);
256 return p;
257 }
258
pisedge(P * p)259 static int pisedge(P *p)
260 {
261 P *q;
262 int c;
263
264 if (pisbol(p))
265 return -1;
266 if (piseol(p))
267 return 1;
268 q = pdup(p, "pisedge");
269 pboi(q);
270 if (q->byte == p->byte)
271 goto left;
272 if (joe_isblank(p->b->o.charmap,(c = brc(p)))) {
273 pset(q, p);
274 if (joe_isblank(p->b->o.charmap,prgetc(q)))
275 goto no;
276 if (c == '\t')
277 goto right;
278 pset(q, p);
279 pgetc(q);
280 if (pgetc(q) == ' ')
281 goto right;
282 goto no;
283 } else {
284 pset(q, p);
285 c = prgetc(q);
286 if (c == '\t')
287 goto left;
288 if (c != ' ')
289 goto no;
290 if (prgetc(q) == ' ')
291 goto left;
292 goto no;
293 }
294
295 right:prm(q);
296 return 1;
297 left:prm(q);
298 return -1;
299 no:prm(q);
300 return 0;
301 }
302
upedge(W * w,int k)303 int upedge(W *w, int k)
304 {
305 BW *bw;
306 WIND_BW(bw, w);
307 if (prgetc(bw->cursor) == NO_MORE_DATA)
308 return -1;
309 while (pisedge(bw->cursor) != -1)
310 prgetc(bw->cursor);
311 return 0;
312 }
313
unedge(W * w,int k)314 int unedge(W *w, int k)
315 {
316 BW *bw;
317 WIND_BW(bw, w);
318 if (pgetc(bw->cursor) == NO_MORE_DATA)
319 return -1;
320 while (pisedge(bw->cursor) != 1)
321 pgetc(bw->cursor);
322 return 0;
323 }
324
325 /* Move cursor to matching delimiter */
326 /*
327 * begin end
328 *
329 * module endmodule
330 *
331 * function endfunction
332 *
333 * <word </word
334 *
335 * if elif else fi
336 *
337 * do done
338 *
339 * case esac, endcase
340 *
341 * #if #ifdef #ifndef #elseif #else #endif
342 *
343 * `ifdef `ifndef `else `endif
344 *
345 */
346
347 /* A delimiter set list is a : separated list of delimiter sets.
348 A delimiter set is two or more groups of matching delimiters.
349 A group is a list of equivalent delimiters separated with |.
350
351 For example, here is a delimiter set list, with three sets:
352 "case|casex|casez=endcase:begin=end:if=elif=else=fi:
353
354 In the first delimiter set: "case," "casex" and "casez" all match with
355 "endcase." In the third set: "if" matches with "elif," which matches with
356 "else," which finally matches with "fi".
357
358 The search goes forward if the delimiter matches any words of any group
359 but the last of the set. If the delimiter matches a word in the last
360 group, the search goes backward to the first delimiter.
361
362 Delimiter sets lists are now UTF-8.
363 */
364
365 /* Return pointer to first matching set in delimiter set list. Returns NULL
366 if no matches were found. */
367
next_set(const char * set)368 static const char *next_set(const char *set)
369 {
370 while (*set && *set!=':')
371 ++set;
372 if (*set==':')
373 ++set;
374 return set;
375 }
376
next_group(const char * group)377 static const char *next_group(const char *group)
378 {
379 while (*group && *group!='=' && *group!=':')
380 ++group;
381 if (*group=='=')
382 ++group;
383 return group;
384 }
385
next_word(const char * word)386 static const char *next_word(const char *word)
387 {
388 while (*word && *word!='|' && *word!='=' && *word!=':')
389 ++word;
390 if (*word=='|')
391 ++word;
392 return word;
393 }
394
match_word(const char * word,const int * s)395 static int match_word(const char *word,const int *s)
396 {
397 while (*s && *word && utf8_decode_fwrd(&word, NULL) == *s++);
398
399 if (!*s && (!*word || *word=='|' || *word=='=' || *word==':'))
400 return 1;
401 else
402 return 0;
403 }
404
is_in_group(const char * group,const int * s)405 static int is_in_group(const char *group,const int *s)
406 {
407 while (*group && *group!='=' && *group!=':') {
408 if (match_word(group, s))
409 return 1;
410 else
411 group = next_word(group);
412 }
413 return 0;
414 }
415
is_in_any_group(const char * group,const int * s)416 static int is_in_any_group(const char *group,const int *s)
417 {
418 while (*group && *group!=':') {
419 if (match_word(group, s))
420 return 1;
421 else {
422 group = next_word(group);
423 if (*group == '=')
424 ++group;
425 }
426 }
427 return 0;
428 }
429
find_last_group(const char * group)430 static const char *find_last_group(const char *group)
431 {
432 const char *s;
433 for (s = group; *s && *s!=':'; s=next_group(s))
434 group = s;
435 return group;
436 }
437
438 #define MAX_WORD_SIZE 255
439
440 /* Search for matching delimiter: ignore things in comments or strings */
441
tomatch_char_or_word(BW * bw,int word_delimiter,int c,int f,const char * set,const char * group,int backward)442 static int tomatch_char_or_word(BW *bw,int word_delimiter,int c,int f,const char *set,const char *group,int backward)
443 {
444 P *p = pdup(bw->cursor, "tomatch_char_or_word");
445 P *q = pdup(p, "tomatch_char_or_word");
446 const char *last_of_set = "";
447 int buf[MAX_WORD_SIZE+1];
448 int len;
449 int query_highlighter = bw->o.highlighter_context && bw->o.syntax && bw->db;
450 int initial_context = 0;
451 int col = 0;
452 int cnt = 0; /* No. levels of delimiters we're in */
453 int d;
454 off_t sod = 0; /* Start of delimiter */
455
456 if (word_delimiter) {
457 if (backward) {
458 last_of_set = find_last_group(set);
459 p_goto_next(p);
460 p_goto_prev(p);
461 } else {
462 last_of_set = find_last_group(group);
463 p_goto_next(p);
464 }
465 pset(q, p);
466 }
467
468 if (query_highlighter) {
469 col = -1;
470 do {
471 d = prgetc(q);
472 ++col;
473 } while (d != NO_MORE_DATA && d != '\n');
474 if (d != NO_MORE_DATA)
475 pgetc(q);
476 parse(bw->o.syntax, q, lattr_get(bw->db, bw->o.syntax, q, q->line),bw->o.charmap);
477 initial_context = attr_buf[col] & CONTEXT_MASK;
478 }
479
480 if (backward) {
481 /* Backward search */
482 while ((d = prgetc(p)) != NO_MORE_DATA) {
483 int peek;
484 int peek1;
485
486 if (query_highlighter && d == '\n'){
487 pset(q, p);
488 col = -1;
489 do {
490 d = prgetc(q);
491 ++col;
492 } while (d != NO_MORE_DATA && d != '\n');
493 if (d != NO_MORE_DATA)
494 pgetc(q);
495 parse(bw->o.syntax, q, lattr_get(bw->db, bw->o.syntax, q, q->line), bw->o.charmap);
496 continue;
497 }
498
499 peek = prgetc(p);
500 peek1 = 0;
501 if(peek != NO_MORE_DATA) {
502 peek1 = prgetc(p);
503 if (peek1 != NO_MORE_DATA)
504 pgetc(p);
505 pgetc(p);
506 }
507 --col;
508
509 if (query_highlighter
510 && (attr_buf[col] & (CONTEXT_COMMENT | CONTEXT_STRING))
511 && (attr_buf[col] & CONTEXT_MASK) != initial_context) {
512 /* Ignore */
513 } else if (!query_highlighter
514 && (bw->o.cpp_comment || bw->o.pound_comment ||
515 bw->o.semi_comment || bw->o.tex_comment || bw->o.vhdl_comment) && d == '\n') {
516 int cc;
517 pset(q, p);
518 p_goto_bol(q);
519 while((cc = pgetc(q)) != '\n') {
520 if (cc == '\\') {
521 if (pgetc(q) == '\n')
522 break;
523 } else if (bw->o.pound_comment && cc == '$' && brch(q)=='#') {
524 pgetc(q);
525 } else if(!bw->o.no_double_quoted && cc=='"') {
526 while ((cc = pgetc(q)) != '\n')
527 if (cc == '"') break;
528 else if (cc == '\\') if ((cc = pgetc(q)) == '\n') break;
529 if (cc == '\n')
530 break;
531 } else if (bw->o.single_quoted && cc == '\'') {
532 while((cc = pgetc(q)) != '\n')
533 if (cc == '\'') break;
534 else if (cc == '\\') if ((cc = pgetc(q)) == '\n') break;
535 if (cc == '\n')
536 break;
537 } else if (bw->o.cpp_comment && cc == '/') {
538 if (brch(q)=='/') {
539 prgetc(q);
540 pset(p,q);
541 break;
542 }
543 } else if (bw->o.vhdl_comment && cc == '-') {
544 if (brch(q)=='-') {
545 prgetc(q);
546 pset(p,q);
547 break;
548 }
549 } else if (bw->o.pound_comment && cc == '#') {
550 pset(p,q);
551 break;
552 } else if (bw->o.semi_comment && cc == ';') {
553 pset(p,q);
554 break;
555 } else if (bw->o.tex_comment && cc == '%') {
556 pset(p,q);
557 break;
558 }
559 }
560 } else if (peek == '\\' && peek1!='\\') {
561 /* Ignore */
562 } else if (!query_highlighter && !bw->o.no_double_quoted && d == '"') {
563 while((d = prgetc(p)) != NO_MORE_DATA) {
564 if (d == '"') {
565 d = prgetc(p);
566 if (d != '\\') {
567 if (d != NO_MORE_DATA)
568 pgetc(p);
569 break;
570 }
571 }
572 }
573 } else if (!query_highlighter && bw->o.single_quoted && d == '\'' && c != '\'' && c != '`') {
574 while((d = prgetc(p)) != NO_MORE_DATA)
575 if (d == '\'') {
576 d = prgetc(p);
577 if (d != '\\') {
578 if (d != NO_MORE_DATA)
579 pgetc(p);
580 break;
581 }
582 }
583 } else if (!query_highlighter && bw->o.c_comment && d == '/') {
584 d = prgetc(p);
585 if (d == '*') {
586 d = prgetc(p);
587 do {
588 do {
589 if (d == '*') break;
590 } while ((d = prgetc(p)) != NO_MORE_DATA);
591 d = prgetc(p);
592 } while (d != NO_MORE_DATA && d != '/');
593 } else if (d != NO_MORE_DATA)
594 pgetc(p);
595 } else if (word_delimiter) {
596 if (joe_isalnum_(p->b->o.charmap, d)) {
597 int x;
598 int flg=0;
599 P *r;
600 len=0;
601 while (joe_isalnum_(p->b->o.charmap, d)) {
602 if(len!=MAX_WORD_SIZE)
603 buf[len++] = d;
604 d=prgetc(p);
605 --col;
606 }
607 /* ifdef hack */
608 r = pdup(p, "tomatch_char_or_word");
609 while (d ==' ' || d=='\t')
610 d=prgetc(r);
611 /* VHDL hack */
612 if ((d=='d' || d=='D') && bw->o.vhdl_comment) {
613 d=prgetc(r);
614 if(d=='n' || d=='N') {
615 d=prgetc(r);
616 if(d=='e' || d=='E') {
617 d=prgetc(r);
618 if(d==' ' || d=='\t' || d=='\n' || d==NO_MORE_DATA)
619 flg=1;
620 }
621 }
622 }
623 prm(r);
624 if (d == utf8_decode_string(set))
625 buf[len++] = d;
626 if(d!=NO_MORE_DATA)
627 pgetc(p);
628 ++col;
629 buf[len]=0;
630 for(x=0;x!=len/2;++x) {
631 int e = buf[x];
632 buf[x] = buf[len-x-1];
633 buf[len-x-1] = e;
634 }
635 if (is_in_group(last_of_set,buf)) {
636 ++cnt;
637 } else if(is_in_group(set,buf) && !flg && !cnt--) {
638 pset(bw->cursor,p);
639 prm(q);
640 prm(p);
641 return 0;
642 }
643 }
644 } else if (d == c) {
645 ++cnt;
646 } else if (d == f && !cnt--) {
647 pset(bw->cursor, p);
648 prm(q);
649 prm(p);
650 return 0;
651 }
652 }
653 } else {
654 /* Forward search */
655 while ((sod = p->byte), ((d = pgetc(p)) != NO_MORE_DATA)) {
656 if (query_highlighter && d == '\n') {
657 parse(bw->o.syntax, q, lattr_get(bw->db, bw->o.syntax, q, q->line), bw->o.charmap);
658 col = 0;
659 continue;
660 }
661
662 if (query_highlighter
663 && (attr_buf[col] & (CONTEXT_COMMENT | CONTEXT_STRING))
664 && (attr_buf[col] & CONTEXT_MASK) != initial_context) {
665 /* Ignore */
666 } else if (d == '\\') {
667 if (!(query_highlighter && brch(p) == '\n')) {
668 pgetc(p);
669 ++col;
670 }
671 } else if (!query_highlighter && !bw->o.no_double_quoted && d == '"') {
672 while ((d = pgetc(p)) != NO_MORE_DATA)
673 if (d == '"') break;
674 else if (d == '\\') pgetc(p);
675 } else if (!query_highlighter && bw->o.single_quoted && d == '\'' && c != '\'' && c != '`') {
676 while((d = pgetc(p)) != NO_MORE_DATA)
677 if (d == '\'') break;
678 else if (d == '\\') pgetc(p);
679 } else if (!query_highlighter && d == '$' && brch(p)=='#' && bw->o.pound_comment) {
680 pgetc(p);
681 } else if (!query_highlighter
682 && ((bw->o.pound_comment && d == '#') ||
683 (bw->o.semi_comment && d == ';') ||
684 (bw->o.tex_comment && d == '%') ||
685 (bw->o.vhdl_comment && d == '-' && brch(p) == '-') ||
686 (bw->o.cpp_comment && d == '/' && brch(p) == '/'))) {
687 while ((d = pgetc(p)) != NO_MORE_DATA)
688 if (d == '\n')
689 break;
690 } else if (!query_highlighter && bw->o.c_comment && d == '/' && brch(p) == '*') {
691 pgetc(p);
692 d = pgetc(p);
693 do {
694 do {
695 if (d == '*') break;
696 } while ((d = pgetc(p)) != NO_MORE_DATA);
697 d = pgetc(p);
698 } while (d != NO_MORE_DATA && d != '/');
699 } else if (word_delimiter) {
700 int set0 = utf8_decode_string(set);
701 if (d == set0) {
702 /* ifdef hack */
703 len = 0;
704 if (!joe_isalnum_(p->b->o.charmap, d)) { /* If it's a # in #ifdef, allow spaces after it */
705 sod = p->byte;
706 while ((d = pgetc(p))!=NO_MORE_DATA) {
707 ++col;
708 if (d!=' ' && d!='\t')
709 break;
710 sod = p->byte;
711 }
712 buf[0] = set0;
713 len=1;
714 }
715 if (joe_isalnum_(p->b->o.charmap, d))
716 goto doit;
717 if (d!=NO_MORE_DATA) {
718 prgetc(p);
719 --col;
720 }
721 } else if (joe_isalpha_(p->b->o.charmap, d)) {
722 len=0;
723 doit:
724 while (joe_isalnum_(p->b->o.charmap, d)) {
725 if(len!=MAX_WORD_SIZE)
726 buf[len++] = d;
727 d=pgetc(p);
728 ++col;
729 }
730 if (d!=NO_MORE_DATA) {
731 prgetc(p);
732 --col;
733 }
734 buf[len]=0;
735 if (is_in_group(set,buf)) {
736 ++cnt;
737 } else if (cnt==0) {
738 if (is_in_any_group(group,buf)) {
739 pgoto(p, sod);
740 pset(bw->cursor,p);
741 prm(q);
742 prm(p);
743 return 0;
744 }
745 } else if(is_in_group(last_of_set,buf)) {
746 /* VHDL hack */
747 if (bw->o.vhdl_comment && (match_word("end", buf) || !match_word("END", buf)))
748 while((d=pgetc(p))!=NO_MORE_DATA) {
749 ++col;
750 if (d==';' || d=='\n') {
751 prgetc(p);
752 --col;
753 break;
754 }
755 }
756 --cnt;
757 }
758 }
759 } else if (d == c) {
760 ++cnt;
761 } else if (d == f && !--cnt) {
762 prgetc(p);
763 pset(bw->cursor, p);
764 prm(q);
765 prm(p);
766 return 0;
767 }
768 ++col;
769 }
770 }
771 prm(q);
772 prm(p);
773 return -1;
774 }
775
tomatch_char(BW * bw,int c,int f,int dir)776 static int tomatch_char(BW *bw,int c,int f,int dir)
777 {
778 return tomatch_char_or_word(bw, 0, c, f, 0, 0, dir == -1);
779 }
780
tomatch_word(BW * bw,const char * set,const char * group)781 static int tomatch_word(BW *bw,const char *set,const char *group)
782 {
783 return tomatch_char_or_word(bw, 1, 0, 0, set, group, !*group || *group==':');
784 }
785
786 /* Return true if <foo /> */
787
xml_startend(P * p)788 static int xml_startend(P *p)
789 {
790 int c, d=0;
791 p=pdup(p, "xml_startend");
792 while((c=pgetc(p)) != NO_MORE_DATA) {
793 if(d=='/' && c=='>') {
794 prm(p);
795 return 1;
796 } else if(c=='>')
797 break;
798 d=c;
799 }
800 prm(p);
801 return 0;
802 }
803
tomatch_xml(BW * bw,int * word,int dir)804 static int tomatch_xml(BW *bw,int *word,int dir)
805 {
806 if (dir== -1) {
807 /* Backward search */
808 P *p=pdup(bw->cursor, "tomatch_xml");
809 int c;
810 int buf[MAX_WORD_SIZE+1];
811 int len;
812 int cnt = 1;
813 p_goto_next(p);
814 p_goto_prev(p);
815 while ((c=prgetc(p)) != NO_MORE_DATA) {
816 if (joe_isalnum_(p->b->o.charmap, c) || c == '.' || c == ':' || c == '-') {
817 int x;
818 len=0;
819 while (joe_isalnum_(p->b->o.charmap, c) || c=='.' || c==':' || c == '-') {
820 if(len!=MAX_WORD_SIZE)
821 buf[len++] = c;
822 c=prgetc(p);
823 }
824 if(c!=NO_MORE_DATA)
825 c = pgetc(p);
826 buf[len]=0;
827 for(x=0;x!=len/2;++x) {
828 int d = buf[x];
829 buf[x] = buf[len-x-1];
830 buf[len-x-1] = d;
831 }
832 if (!Zcmp(word,buf) && !xml_startend(p)) {
833 if (c=='<') {
834 if (!--cnt) {
835 pset(bw->cursor,p);
836 prm(p);
837 return 0;
838 }
839 }
840 else if (c=='/') {
841 ++cnt;
842 }
843 }
844 }
845 }
846 prm(p);
847 return -1;
848 } else {
849 /* Forward search */
850 P *p=pdup(bw->cursor, "tomatch_xml");
851 int c;
852 int buf[MAX_WORD_SIZE+1];
853 int len;
854 int cnt = 1;
855 off_t sod = 0;
856 while ((c=pgetc(p)) != NO_MORE_DATA) {
857 if (c == '<') {
858 int e = 1;
859 sod = p->byte;
860 c = pgetc(p);
861 if (c=='/') {
862 sod = p->byte;
863 e = 0;
864 c = pgetc(p);
865 }
866 if (joe_isalpha_(p->b->o.charmap, c) || c==':' || c=='-' || c=='.') {
867 len=0;
868 while (joe_isalnum_(p->b->o.charmap, c) || c==':' || c=='-' || c=='.') {
869 if(len!=MAX_WORD_SIZE)
870 buf[len++]=c;
871 c=pgetc(p);
872 }
873 if (c!=NO_MORE_DATA)
874 prgetc(p);
875 buf[len]=0;
876 if (!Zcmp(word,buf) && !xml_startend(p)) {
877 if (e) {
878 ++cnt;
879 }
880 else if (!--cnt) {
881 pgoto(p, sod);
882 pset(bw->cursor,p);
883 prm(p);
884 return 0;
885 }
886 }
887 } else if (c!=NO_MORE_DATA) {
888 prgetc(p);
889 }
890 }
891 }
892 prm(p);
893 return -1;
894 }
895 }
896
get_xml_name(P * p,int * buf)897 static void get_xml_name(P *p,int *buf)
898 {
899 int c;
900 int len=0;
901 p=pdup(p, "get_xml_name");
902 c=pgetc(p);
903 while (joe_isalnum_(p->b->o.charmap, c) || c==':' || c=='-' || c=='.') {
904 if(len!=MAX_WORD_SIZE)
905 buf[len++]=c;
906 c=pgetc(p);
907 }
908 buf[len]=0;
909 prm(p);
910 }
911
get_delim_name(P * q,int * buf)912 static void get_delim_name(P *q,int *buf)
913 {
914 int c;
915 int len=0;
916 P *p=pdup(q, "get_delim_name");
917 while ((c=prgetc(p))!=NO_MORE_DATA)
918 if (c!=' ' && c!='\t')
919 break;
920 prm(p);
921 /* preprocessor directive hack */
922 if (c=='#' || c=='`')
923 buf[len++]=c;
924
925 p=pdup(q, "get_delim_name");
926 c=pgetc(p);
927 while (joe_isalnum_(p->b->o.charmap, c)) {
928 if(len!=MAX_WORD_SIZE)
929 buf[len++]=c;
930 c=pgetc(p);
931 }
932 buf[len]=0;
933 prm(p);
934 }
935
utomatch(W * w,int k)936 int utomatch(W *w, int k)
937 {
938 int d;
939 int c, /* Character under cursor */
940 f, /* Character to find */
941 dir; /* 1 to search forward, -1 to search backward */
942 BW *bw;
943 WIND_BW(bw, w);
944
945 c = brch(bw->cursor);
946
947 /* Check for word delimiters */
948 if (joe_isalnum_(bw->cursor->b->o.charmap, c)) {
949 P *p;
950 int buf[MAX_WORD_SIZE+1];
951 char utf8_buf[MAX_WORD_SIZE * 6 + 1]; /* Possibly UTF-8 version of buf */
952 int buf1[MAX_WORD_SIZE+1];
953 const char *list = bw->b->o.text_delimiters;
954 const char *set;
955 const char *group;
956 const char *word;
957 int flg=0;
958 p=pdup(bw->cursor, "utomatch");
959 p_goto_next(p);
960 p_goto_prev(p);
961 get_delim_name(p,buf);
962 get_xml_name(p,buf1);
963 c=prgetc(p);
964 if (c=='<')
965 flg = 1;
966 else if (c=='/') {
967 c=prgetc(p);
968 if (c=='<')
969 flg = -1;
970 }
971 prm(p);
972
973 if (flg) {
974 return tomatch_xml(bw, buf1, flg);
975 }
976
977 for (set = list; set && *set; set = next_set(set)) {
978 for (group = set; *group && *group!='=' && *group!=':'; group=next_group(group)) {
979 for (word = group; *word && *word!='|' && *word!='=' && *word!=':'; word=next_word(word)) {
980 if (match_word(word, buf)) {
981 return tomatch_word(bw, set, next_group(word));
982 }
983 }
984 }
985
986 }
987
988 /* We don't know the word, so start a search */
989 if (bw->b->o.charmap->type) {
990 Ztoutf8(utf8_buf, SIZEOF(utf8_buf), buf);
991 } else {
992 Ztoz(utf8_buf, SIZEOF(utf8_buf), buf);
993 }
994 return dofirst(bw, 0, 0, utf8_buf);
995 }
996
997 switch (c) {
998 case '/':
999 dir = 1;
1000 pgetc(bw->cursor);
1001 f = brch(bw->cursor);
1002 prgetc(bw->cursor);
1003 if(f=='*') f = '/';
1004 else {
1005 dir = -1;
1006 f = prgetc(bw->cursor);
1007 if (f!=NO_MORE_DATA)
1008 pgetc(bw->cursor);
1009 if(f=='*') f = '/';
1010 else
1011 return -1;
1012 }
1013 break;
1014 case '*':
1015 dir = -1;
1016 pgetc(bw->cursor);
1017 f = brch(bw->cursor);
1018 prgetc(bw->cursor);
1019 if(f=='/') f = '*';
1020 else {
1021 dir = 1;
1022 f = prgetc(bw->cursor);
1023 if (f!=NO_MORE_DATA)
1024 pgetc(bw->cursor);
1025 if(f=='/') f = '*';
1026 else
1027 return -1;
1028 }
1029 break;
1030 case '(':
1031 f = ')';
1032 dir = 1;
1033 break;
1034 case '[':
1035 f = ']';
1036 dir = 1;
1037 break;
1038 case '{':
1039 f = '}';
1040 dir = 1;
1041 break;
1042 case '`':
1043 f = '\'';
1044 dir = 1;
1045 break;
1046 case '<':
1047 f = '>';
1048 dir = 1;
1049 break;
1050 case ')':
1051 f = '(';
1052 dir = -1;
1053 break;
1054 case ']':
1055 f = '[';
1056 dir = -1;
1057 break;
1058 case '}':
1059 f = '{';
1060 dir = -1;
1061 break;
1062 case '\'':
1063 f = '`';
1064 dir = -1;
1065 break;
1066 case '>':
1067 f = '<';
1068 dir = -1;
1069 break;
1070 default:
1071 return -1;
1072 }
1073
1074 /* Search for matching C comment */
1075 if (f == '/' || f == '*') {
1076 P *p = pdup(bw->cursor, "utomatch");
1077 if (dir == 1) {
1078 d = pgetc(p);
1079 do {
1080 do {
1081 if (d == '*') break;
1082 } while ((d = pgetc(p)) != NO_MORE_DATA);
1083 d = pgetc(p);
1084 } while (d != NO_MORE_DATA && d != '/');
1085 if (d == '/') {
1086 if (f == '*') {
1087 prgetc(p);
1088 }
1089 pset(bw->cursor,p);
1090 prgetc(bw->cursor);
1091 }
1092 } else {
1093 d = prgetc(p);
1094 do {
1095 do {
1096 if (d == '*') break;
1097 } while ((d = prgetc(p)) != NO_MORE_DATA);
1098 d = prgetc(p);
1099 } while (d != NO_MORE_DATA && d != '/');
1100 if (d == '/') {
1101 if (f == '*') {
1102 pgetc(p);
1103 }
1104 pset(bw->cursor,p);
1105 }
1106 }
1107 prm(p);
1108 if (d == NO_MORE_DATA)
1109 return -1;
1110 else
1111 return 0;
1112 }
1113
1114 return tomatch_char(bw, c, f, dir);
1115 }
1116
1117 /* Move cursor up */
1118
uuparw(W * w,int k)1119 int uuparw(W *w, int k)
1120 {
1121 BW *bw;
1122 WIND_BW(bw, w);
1123 if (bw->o.hex) {
1124 if (bw->cursor->byte<16)
1125 return -1;
1126 else {
1127 pbkwd(bw->cursor, 16);
1128 return 0;
1129 }
1130 }
1131 if (bw->cursor->line) {
1132 pprevl(bw->cursor);
1133 pcol(bw->cursor, bw->cursor->xcol);
1134 return 0;
1135 } else
1136 return -1;
1137 }
1138
1139 /* Move cursor down */
1140
udnarw(W * w,int k)1141 int udnarw(W *w, int k)
1142 {
1143 BW *bw;
1144 WIND_BW(bw, w);
1145 if (bw->o.hex) {
1146 if (bw->cursor->byte+16 <= bw->b->eof->byte) {
1147 pfwrd(bw->cursor, 16);
1148 return 0;
1149 } else if (bw->cursor->byte != bw->b->eof->byte) {
1150 pset(bw->cursor, bw->b->eof);
1151 return 0;
1152 } else {
1153 return -1;
1154 }
1155 }
1156 if (bw->cursor->line != bw->b->eof->line) {
1157 pnextl(bw->cursor);
1158 pcol(bw->cursor, bw->cursor->xcol);
1159 return 0;
1160 } else if(bw->o.picture) {
1161 p_goto_eol(bw->cursor);
1162 binsc(bw->cursor,'\n');
1163 pgetc(bw->cursor);
1164 pcol(bw->cursor, bw->cursor->xcol);
1165 return 0;
1166 } else
1167 return -1;
1168 }
1169
1170 /* Move cursor to top of window */
1171
utos(W * w,int k)1172 int utos(W *w, int k)
1173 {
1174 off_t col;
1175 BW *bw;
1176 WIND_BW(bw, w);
1177 col = bw->cursor->xcol;
1178
1179 pset(bw->cursor, bw->top);
1180 pcol(bw->cursor, col);
1181 bw->cursor->xcol = col;
1182 return 0;
1183 }
1184
1185 /* Move cursor to bottom of window */
1186
ubos(W * w,int k)1187 int ubos(W *w, int k)
1188 {
1189 BW *bw;
1190 off_t col;
1191 WIND_BW(bw, w);
1192 col = bw->cursor->xcol;
1193
1194 pline(bw->cursor, bw->top->line + bw->h - 1);
1195 pcol(bw->cursor, col);
1196 bw->cursor->xcol = col;
1197 return 0;
1198 }
1199
1200 /* Scroll buffer window up n lines
1201 * If beginning of file is close, scrolls as much as it can
1202 * If beginning of file is on-screen, cursor jumps to beginning of file
1203 *
1204 * If flg is set: cursor stays fixed relative to screen edge
1205 * If flg is clr: cursor stays fixed on the buffer line
1206 */
1207
scrup(BW * bw,ptrdiff_t n,int flg)1208 void scrup(BW *bw, ptrdiff_t n, int flg)
1209 {
1210 ptrdiff_t scrollamnt = 0;
1211 ptrdiff_t cursoramnt = 0;
1212 ptrdiff_t x;
1213
1214 /* Decide number of lines we're really going to scroll */
1215
1216 if (bw->o.hex) {
1217 if (bw->top->byte/16 >= n)
1218 scrollamnt = cursoramnt = n;
1219 else if (bw->top->byte/16)
1220 scrollamnt = cursoramnt = (ptrdiff_t)(bw->top->byte/16);
1221 else if (flg)
1222 cursoramnt = (ptrdiff_t)(bw->cursor->byte/16);
1223 else if (bw->cursor->byte/16 >= n)
1224 cursoramnt = n;
1225 } else {
1226 if (bw->top->line >= n)
1227 scrollamnt = cursoramnt = n;
1228 else if (bw->top->line)
1229 scrollamnt = cursoramnt = (ptrdiff_t)bw->top->line;
1230 else if (flg)
1231 cursoramnt = (ptrdiff_t)bw->cursor->line;
1232 else if (bw->cursor->line >= n)
1233 cursoramnt = n;
1234 }
1235
1236 if (bw->o.hex) {
1237 /* Move top-of-window pointer */
1238 pbkwd(bw->top,scrollamnt*16);
1239 /* Move cursor */
1240 pbkwd(bw->cursor,cursoramnt*16);
1241 /* If window is on the screen, give (buffered) scrolling command */
1242 if (bw->parent->y != -1)
1243 nscrldn(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
1244 } else {
1245 /* Move top-of-window pointer */
1246 for (x = 0; x != scrollamnt; ++x)
1247 pprevl(bw->top);
1248 p_goto_bol(bw->top);
1249
1250 /* Move cursor */
1251 for (x = 0; x != cursoramnt; ++x)
1252 pprevl(bw->cursor);
1253 p_goto_bol(bw->cursor);
1254 pcol(bw->cursor, bw->cursor->xcol);
1255
1256 /* If window is on the screen, give (buffered) scrolling command */
1257 if (bw->parent->y != -1)
1258 nscrldn(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
1259 }
1260 }
1261
1262 /* Scroll buffer window down n lines
1263 * If end of file is close, scrolls as much as possible
1264 * If end of file is on-screen, cursor jumps to end of file
1265 *
1266 * If flg is set: cursor stays fixed relative to screen edge
1267 * If flg is clr: cursor stays fixed on the buffer line
1268 */
1269
scrdn(BW * bw,ptrdiff_t n,int flg)1270 void scrdn(BW *bw, ptrdiff_t n, int flg)
1271 {
1272 ptrdiff_t scrollamnt = 0;
1273 ptrdiff_t cursoramnt = 0;
1274 ptrdiff_t x;
1275
1276 /* How much we're really going to scroll... */
1277 if (bw->o.hex) {
1278 if (bw->top->b->eof->byte/16 < bw->top->byte/16 + bw->h) {
1279 cursoramnt = (ptrdiff_t)(bw->top->b->eof->byte/16 - bw->cursor->byte/16);
1280 if (!flg && cursoramnt > n)
1281 cursoramnt = n;
1282 } else if (bw->top->b->eof->byte/16 - (bw->top->byte/16 + bw->h) >= n)
1283 cursoramnt = scrollamnt = n;
1284 else
1285 cursoramnt = scrollamnt = (ptrdiff_t)(bw->top->b->eof->byte/16 - (bw->top->byte/16 + bw->h) + 1);
1286 } else {
1287 if (bw->top->b->eof->line < bw->top->line + bw->h) {
1288 cursoramnt = (ptrdiff_t)(bw->top->b->eof->line - bw->cursor->line);
1289 if (!flg && cursoramnt > n)
1290 cursoramnt = n;
1291 } else if (bw->top->b->eof->line - (bw->top->line + bw->h) >= n)
1292 cursoramnt = scrollamnt = n;
1293 else
1294 cursoramnt = scrollamnt = (ptrdiff_t)(bw->top->b->eof->line - (bw->top->line + bw->h) + 1);
1295 }
1296
1297 if (bw->o.hex) {
1298 /* Move top-of-window pointer */
1299 pfwrd(bw->top,16*scrollamnt);
1300 /* Move cursor */
1301 pfwrd(bw->cursor,16*cursoramnt);
1302 /* If window is on screen, give (buffered) scrolling command to terminal */
1303 if (bw->parent->y != -1)
1304 nscrlup(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
1305 } else {
1306 /* Move top-of-window pointer */
1307 for (x = 0; x != scrollamnt; ++x)
1308 pnextl(bw->top);
1309
1310 /* Move cursor */
1311 for (x = 0; x != cursoramnt; ++x)
1312 pnextl(bw->cursor);
1313 pcol(bw->cursor, bw->cursor->xcol);
1314
1315 /* If window is on screen, give (buffered) scrolling command to terminal */
1316 if (bw->parent->y != -1)
1317 nscrlup(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
1318 }
1319 }
1320
1321 /* Page up */
1322
upgup(W * w,int k)1323 int upgup(W *w, int k)
1324 {
1325 BW *bw;
1326 WIND_BW(bw, w);
1327 if (menu_above) {
1328 if (w->link.prev->watom == &watommenu && w->link.prev->win == w) {
1329 return umpgup(w->link.prev, 0);
1330 }
1331 } else {
1332 if (w->link.next->watom == &watommenu && w->link.next->win == w) {
1333 return umpgup(w->link.next, 0);
1334 }
1335 }
1336 bw = (BW *) bw->parent->main->object;
1337
1338 if (bw->o.hex ? bw->cursor->byte < 16 : !bw->cursor->line)
1339 return -1;
1340 if (pgamnt < 0)
1341 scrup(bw, bw->h / 2 + bw->h % 2, 1);
1342 else if (pgamnt < bw->h)
1343 scrup(bw, bw->h - pgamnt, 1);
1344 else
1345 scrup(bw, 1, 1);
1346 return 0;
1347 }
1348
1349 /* Page down */
1350
upgdn(W * w,int k)1351 int upgdn(W *w, int k)
1352 {
1353 BW *bw;
1354 WIND_BW(bw, w);
1355 if (menu_above) {
1356 if (w->link.prev->watom == &watommenu && w->link.prev->win == w) {
1357 return umpgdn(w->link.prev, 0);
1358 }
1359 } else {
1360 if (w->link.next->watom == &watommenu && w->link.next->win == w) {
1361 return umpgdn(w->link.next, 0);
1362 }
1363 }
1364 bw = (BW *)bw->parent->main->object;
1365 if (bw->o.hex ? bw->cursor->byte/16 == bw->b->eof->byte/16 : bw->cursor->line == bw->b->eof->line)
1366 return -1;
1367 if (pgamnt < 0)
1368 scrdn(bw, bw->h / 2 + bw->h % 2, 1);
1369 else if (pgamnt < bw->h)
1370 scrdn(bw, bw->h - pgamnt, 1);
1371 else
1372 scrdn(bw, 1, 1);
1373 return 0;
1374 }
1375
1376 /* Scroll by a single line. The cursor moves with the scroll */
1377
uupslide(W * w,int k)1378 int uupslide(W *w, int k)
1379 {
1380 BW *bw;
1381 WIND_BW(bw, w);
1382 if (bw->o.hex ? bw->top->byte/16 : bw->top->line) {
1383 if (bw->o.hex ? bw->top->byte/16 + bw->h -1 != bw->cursor->byte/16 : bw->top->line + bw->h - 1 != bw->cursor->line)
1384 udnarw(w, 0);
1385 scrup(bw, 1, 0);
1386 return 0;
1387 } else
1388 /* was return -1; */
1389 return uuparw(w, 0);
1390 }
1391
udnslide(W * w,int k)1392 int udnslide(W *w, int k)
1393 {
1394 BW *bw;
1395 WIND_BW(bw, w);
1396 if (bw->o.hex ? bw->top->line/16 + bw->h <= bw->top->b->eof->byte/16 : bw->top->line + bw->h <= bw->top->b->eof->line) {
1397 if (bw->o.hex ? bw->top->byte/16 != bw->cursor->byte/16 : bw->top->line != bw->cursor->line)
1398 uuparw(w, 0);
1399 scrdn(bw, 1, 0);
1400 return 0;
1401 } else
1402 /* was return -1; */
1403 return udnarw(w, 0);
1404 }
1405
1406 /* Move cursor to specified line number */
1407
1408 static B *linehist = NULL; /* History of previously entered line numbers */
1409
doline(W * w,char * s,void * object,int * notify)1410 static int doline(W *w, char *s, void *object, int *notify)
1411 {
1412 BW *bw;
1413 off_t num;
1414 WIND_BW(bw, w);
1415 num = (off_t)calc(bw, s, 1);
1416
1417 if (notify)
1418 *notify = 1;
1419 vsrm(s);
1420 if (num >= 1 && !merr) {
1421 int tmp = opt_mid;
1422
1423 if (num > bw->b->eof->line)
1424 num = bw->b->eof->line + 1;
1425 pline(bw->cursor, num - 1), bw->cursor->xcol = piscol(bw->cursor);
1426 opt_mid = 1;
1427 dofollows();
1428 opt_mid = tmp;
1429 return 0;
1430 } else {
1431 if (merr)
1432 msgnw(bw->parent, merr);
1433 else
1434 msgnw(bw->parent, joe_gettext(_("Invalid line number")));
1435 return -1;
1436 }
1437 }
1438
uline(W * w,int k)1439 int uline(W *w, int k)
1440 {
1441 BW *bw;
1442 WIND_BW(bw, w);
1443 if (wmkpw(bw->parent, joe_gettext(_("Go to line (%{abort} to abort): ")), &linehist, doline, NULL, NULL, math_cmplt, NULL, NULL, utf8_map, 0))
1444 return 0;
1445 else
1446 return -1;
1447 }
1448
1449 /* Move cursor to specified column number */
1450
1451 static B *colhist = NULL; /* History of previously entered column numbers */
1452
docol(W * w,char * s,void * object,int * notify)1453 static int docol(W *w, char *s, void *object, int *notify)
1454 {
1455 BW *bw;
1456 off_t num;
1457 WIND_BW(bw, w);
1458 num = (off_t)calc(bw, s, 1);
1459
1460 if (notify)
1461 *notify = 1;
1462 vsrm(s);
1463 if (num >= 1 && !merr) {
1464 int tmp = opt_mid;
1465
1466 pcol(bw->cursor, num - 1), bw->cursor->xcol = piscol(bw->cursor);
1467 opt_mid = 1;
1468 dofollows();
1469 opt_mid = tmp;
1470 return 0;
1471 } else {
1472 if (merr)
1473 msgnw(bw->parent, merr);
1474 else
1475 msgnw(bw->parent, joe_gettext(_("Invalid column number")));
1476 return -1;
1477 }
1478 }
1479
ucol(W * w,int k)1480 int ucol(W *w, int k)
1481 {
1482 BW *bw;
1483 WIND_BW(bw, w);
1484 if (wmkpw(bw->parent, joe_gettext(_("Go to column (%{abort} to abort): ")), &colhist, docol, NULL, NULL, math_cmplt, NULL, NULL, utf8_map, 0))
1485 return 0;
1486 else
1487 return -1;
1488 }
1489
1490 /* Move cursor to specified byte number */
1491
1492 static B *bytehist = NULL; /* History of previously entered byte numbers */
1493
dobyte(W * w,char * s,void * object,int * notify)1494 static int dobyte(W *w, char *s, void *object, int *notify)
1495 {
1496 BW *bw;
1497 off_t num;
1498 WIND_BW(bw, w);
1499 num = (off_t)calc(bw, s, 1);
1500
1501 if (notify)
1502 *notify = 1;
1503 vsrm(s);
1504 if (num >= 0 && !merr) {
1505 int tmp = opt_mid;
1506
1507 pgoto(bw->cursor, num), bw->cursor->xcol = piscol(bw->cursor);
1508 opt_mid = 1;
1509 dofollows();
1510 opt_mid = tmp;
1511 return 0;
1512 } else {
1513 if (merr)
1514 msgnw(bw->parent, merr);
1515 else
1516 msgnw(bw->parent, joe_gettext(_("Invalid byte number")));
1517 return -1;
1518 }
1519 }
1520
ubyte(W * w,int k)1521 int ubyte(W *w, int k)
1522 {
1523 BW *bw;
1524 WIND_BW(bw, w);
1525 if (wmkpw(bw->parent, joe_gettext(_("Go to byte (%{abort} to abort): ")), &bytehist, dobyte, NULL, NULL, math_cmplt, NULL, NULL, utf8_map, 0))
1526 return 0;
1527 else
1528 return -1;
1529 }
1530
1531 /* Delete character under cursor
1532 * or write ^D to process if we're at end of file in a shell window
1533 */
1534
udelch(W * w,int k)1535 int udelch(W *w, int k)
1536 {
1537 BW *bw;
1538 P *p;
1539 WIND_BW(bw, w);
1540
1541 if (piseof(bw->cursor))
1542 return -1;
1543 pgetc(p = pdup(bw->cursor, "udelch"));
1544 bdel(bw->cursor, p);
1545 prm(p);
1546 return 0;
1547 }
1548
1549 /* Backspace */
1550
ubacks(W * w,int k)1551 int ubacks(W *w, int k)
1552 {
1553 BW *bw;
1554 WIND_BW(bw, w);
1555 /* Don't backspace when at beginning of line in prompt windows */
1556 if (bw->parent->watom->what == TYPETW || !pisbol(bw->cursor)) {
1557 int c;
1558 off_t indent;
1559 off_t col;
1560 off_t indwid;
1561 off_t wid;
1562
1563 /* Degenerate into ltarw for overtype mode */
1564 if (bw->o.overtype) {
1565 return u_goto_left(bw->parent, 0);
1566 }
1567
1568 if (pisbof(bw->cursor))
1569 return -1;
1570
1571 /* Indentation point of this line */
1572 indent = pisindent(bw->cursor);
1573
1574 /* Column position of cursor */
1575 col = piscol(bw->cursor);
1576
1577 /* Indentation step in columns */
1578 if (bw->o.indentc=='\t')
1579 wid = bw->o.tab;
1580 else
1581 wid = 1;
1582
1583 indwid = (bw->o.istep*wid);
1584
1585 /* Smart backspace when: cursor is at indentation point, indentation point
1586 is a multiple of indentation width, we're not at beginning of line,
1587 'smarthome' option is enabled, and indentation is purely made out of
1588 indent characters (or purify indents is enabled). */
1589
1590 /* Ignore purify for backspace */
1591 if (col == indent && (col%indwid)==0 && col!=0 && bw->o.smartbacks && bw->o.autoindent) {
1592 P *p;
1593
1594 /* Delete all indentation */
1595 p = pdup(bw->cursor, "ubacks");
1596 p_goto_bol(p);
1597 bdel(p,bw->cursor);
1598 prm(p);
1599
1600 /* Indent to new position */
1601 pfill(bw->cursor,col-indwid,bw->o.indentc);
1602 } else if (col<indent && bw->o.smartbacks && !pisbol(bw->cursor)) {
1603 /* We're before indent point: delete indwid worth of space but do not
1604 cross line boundary. We could probably replace the above with this. */
1605 off_t cw=0;
1606 P *p = pdup(bw->cursor, "ubacks");
1607 do {
1608 c = prgetc(bw->cursor);
1609 if(c=='\t') cw += bw->o.tab;
1610 else cw += 1;
1611 bdel(bw->cursor, p);
1612 } while(!pisbol(bw->cursor) && cw<indwid);
1613 prm(p);
1614 } else {
1615 /* Regular backspace */
1616 P *p = pdup(bw->cursor, "ubacks");
1617 if ((c = prgetc(bw->cursor)) != NO_MORE_DATA)
1618 if (!bw->o.overtype || c == '\t' || pisbol(p) || piseol(p))
1619 bdel(bw->cursor, p);
1620 prm(p);
1621 }
1622 return 0;
1623 } else
1624 return -1;
1625 }
1626
1627 /*
1628 * Delete sequence of characters (alphabetic, numeric) or (white-space)
1629 * if cursor is on the white-space it will delete all white-spaces
1630 * until alphanumeric character
1631 * if cursor is on the alphanumeric it will delete all alphanumeric
1632 * characters until character that is not alphanumeric
1633 */
u_word_delete(W * w,int k)1634 int u_word_delete(W *w, int k)
1635 {
1636 BW *bw;
1637 P *p;
1638 struct charmap *map;
1639 int c;
1640 WIND_BW(bw, w);
1641
1642 p = pdup(bw->cursor, "u_word_delete");
1643 map=bw->b->o.charmap;
1644 c = brch(p);
1645
1646 if (joe_isalnum_(map,c))
1647 while (joe_isalnum_(map,(c = brch(p))))
1648 pgetc(p);
1649 else if (joe_isspace(map,c))
1650 while (joe_isspace(map,(c = brch(p))))
1651 pgetc(p);
1652 else
1653 pgetc(p);
1654
1655 if (p->byte == bw->cursor->byte) {
1656 prm(p);
1657 return -1;
1658 }
1659 bdel(bw->cursor, p);
1660 prm(p);
1661 return 0;
1662 }
1663
1664 /* Delete from cursor to beginning of word it's in or immediately after,
1665 * to start of whitespace, or a single character
1666 */
1667
ubackw(W * w,int k)1668 int ubackw(W *w, int k)
1669 {
1670 BW *bw;
1671 P *p;
1672 int c;
1673 struct charmap *map;
1674 WIND_BW(bw, w);
1675
1676 p = pdup(bw->cursor, "ubackw");
1677 c = prgetc(bw->cursor);
1678 map=bw->b->o.charmap;
1679
1680 if (joe_isalnum_(map,c)) {
1681 while (joe_isalnum_(map,(c = prgetc(bw->cursor))))
1682 /* do nothing */;
1683 if (c != NO_MORE_DATA)
1684 pgetc(bw->cursor);
1685 } else if (joe_isspace(map,c)) {
1686 while (joe_isspace(map,(c = prgetc(bw->cursor))))
1687 /* do nothing */;
1688 if (c != NO_MORE_DATA)
1689 pgetc(bw->cursor);
1690 }
1691 if (bw->cursor->byte == p->byte) {
1692 prm(p);
1693 return -1;
1694 }
1695 bdel(bw->cursor, p);
1696 prm(p);
1697 return 0;
1698 }
1699
1700 /* Delete from cursor to end of line, or if there's nothing to delete,
1701 * delete the line-break
1702 */
1703
udelel(W * w,int k)1704 int udelel(W *w,int k)
1705 {
1706 BW *bw;
1707 P *p;
1708 WIND_BW(bw, w);
1709 p = p_goto_eol(pdup(bw->cursor, "udelel"));
1710
1711 if (bw->cursor->byte == p->byte) {
1712 prm(p);
1713 return udelch(w, 0);
1714 } else
1715 bdel(bw->cursor, p);
1716 prm(p);
1717 return 0;
1718 }
1719
1720 /* Delete to beginning of line, or if there's nothing to delete,
1721 * delete the line-break
1722 */
1723
udelbl(W * w,int k)1724 int udelbl(W *w, int k)
1725 {
1726 BW *bw;
1727 P *p;
1728 WIND_BW(bw, w);
1729 p = p_goto_bol(pdup(bw->cursor, "udelbl"));
1730
1731 if (p->byte == bw->cursor->byte) {
1732 prm(p);
1733 return ubacks(w, 8); /* The 8 goes to the process if we're at EOF of shell window */
1734 } else
1735 bdel(p, bw->cursor);
1736 prm(p);
1737 return 0;
1738 }
1739
1740 /* Delete entire line */
1741
udelln(W * w,int k)1742 int udelln(W *w, int k)
1743 {
1744 BW *bw;
1745 P *p;
1746 WIND_BW(bw, w);
1747 p = pdup(bw->cursor, "udelln");
1748
1749 p_goto_bol(bw->cursor);
1750 pnextl(p);
1751 if (bw->cursor->byte == p->byte) {
1752 prm(p);
1753 return -1;
1754 }
1755 bdel(bw->cursor, p);
1756 prm(p);
1757 return 0;
1758 }
1759
1760 /* Insert a space */
1761
uinsc(W * w,int k)1762 int uinsc(W *w, int k)
1763 {
1764 BW *bw;
1765 WIND_BW(bw, w);
1766 binsc(bw->cursor, ' ');
1767 return 0;
1768 }
1769
1770 /* Move p backwards to first non-blank line and return its indentation */
1771
find_indent(P * p)1772 static off_t find_indent(P *p)
1773 {
1774 int x;
1775 for (x=0; x != 10; ++x) {
1776 if (!pprevl(p)) return -1;
1777 p_goto_bol(p);
1778 if (!pisblank(p)) break;
1779 }
1780 if (x==10)
1781 return -1;
1782 else
1783 return pisindent(p);
1784 }
1785
1786 /* Type a character into the buffer (deal with left margin, overtype mode and
1787 * word-wrap), if cursor is at end of shell window buffer, just send character
1788 * to process.
1789 */
1790
utypebw_raw(BW * bw,int k,int no_decode)1791 static int utypebw_raw(BW *bw, int k, int no_decode)
1792 {
1793 /* Character map of buffer */
1794 struct charmap *map = bw->b->o.charmap;
1795
1796
1797 /* Send data to shell window */
1798 if ((bw->b->pid && !bw->b->vt && piseof(bw->cursor)) ||
1799 ( bw->b->pid && bw->b->vt && bw->cursor->byte == bw->b->vt->vtcur->byte)) {
1800 if (locale_map->type) {
1801 char buf[8];
1802 ptrdiff_t len = utf8_encode(buf, k);
1803 joe_write(bw->b->out, buf, len);
1804 } else {
1805 if (!no_decode) {
1806 k = from_uni(locale_map, k);
1807 }
1808 if (k != -1) {
1809 char c = TO_CHAR_OK(k);
1810 joe_write(bw->b->out, &c, 1);
1811 }
1812 }
1813 return 0;
1814 }
1815
1816 /* Hex mode overtype needs to preserve file size */
1817 if (bw->o.hex && bw->o.overtype) {
1818 char buf[8];
1819 ptrdiff_t x;
1820 ptrdiff_t len;
1821 if (map->type) {
1822 len = utf8_encode(buf, k);
1823 } else {
1824 if (!no_decode)
1825 k = from_uni(map, k);
1826 if (k == -1)
1827 return 1;
1828 buf[0] = TO_CHAR_OK(k);
1829 len = 1;
1830 }
1831 binsm(bw->cursor, buf, len);
1832 for (x = 0; x != len; ++x)
1833 pgetb(bw->cursor);
1834 while (len--) {
1835 P *p;
1836 if (piseof(bw->cursor))
1837 return 0;
1838 p = pdup(bw->cursor, "utypebw_raw");
1839 pgetb(p);
1840 bdel(bw->cursor, p);
1841 prm(p);
1842 }
1843 return 0;
1844 }
1845
1846 if (k == '\t' && bw->o.overtype && !piseol(bw->cursor) && !no_decode) { /* TAB in overtype mode is supposed to be just cursor motion */
1847 off_t col = bw->cursor->xcol; /* Current cursor column */
1848 col = col + bw->o.tab - (col%bw->o.tab);/* Move to next tab stop */
1849 pcol(bw->cursor,col); /* Try to position cursor there */
1850 if (!bw->o.picture && piseol(bw->cursor) && piscol(bw->cursor)<col) { /* We moved past end of line, insert a tab (unless in picture mode) */
1851 if (bw->o.spaces)
1852 pfill(bw->cursor,col,' ');
1853 else
1854 pfill(bw->cursor,col,'\t');
1855 }
1856 bw->cursor->xcol = col; /* Put cursor there even if we can't really go there */
1857 } else if (k == '\t' && bw->o.smartbacks && bw->o.autoindent && pisindent(bw->cursor)>=piscol(bw->cursor) && !no_decode) {
1858 P *p = pdup(bw->cursor, "utypebw_raw");
1859 off_t n = find_indent(p);
1860 if (n != -1 && pisindent(bw->cursor)==piscol(bw->cursor) && n > pisindent(bw->cursor)) {
1861 if (!pisbol(bw->cursor))
1862 udelbl(bw->parent, 0);
1863 while (joe_isspace(map,(k = pgetc(p))) && k != '\n') {
1864 binsc(bw->cursor, k);
1865 pgetc(bw->cursor);
1866 }
1867 } else {
1868 int x;
1869 for (x=0;x<bw->o.istep;++x) {
1870 binsc(bw->cursor,bw->o.indentc);
1871 pgetc(bw->cursor);
1872 }
1873 }
1874 bw->cursor->xcol = piscol(bw->cursor);
1875 prm (p);
1876 } else if (k == '\t' && bw->o.spaces && !no_decode) {
1877 off_t n;
1878
1879 if (bw->o.picture)
1880 n = bw->cursor->xcol;
1881 else
1882 n = piscol(bw->cursor);
1883
1884 n = bw->o.tab - n % bw->o.tab;
1885 while (n--)
1886 utypebw(bw, ' ');
1887 } else {
1888 int upd;
1889 int simple;
1890 ptrdiff_t x;
1891
1892 /* Picture mode */
1893 if (bw->o.picture && bw->cursor->xcol!=piscol(bw->cursor))
1894 pfill(bw->cursor,bw->cursor->xcol,' '); /* Why no tabs? */
1895
1896 upd = bw->parent->t->t->updtab[bw->y + bw->cursor->line - bw->top->line];
1897 simple = 1;
1898
1899 if (pisblank(bw->cursor))
1900 while (piscol(bw->cursor) < bw->o.lmargin) {
1901 binsc(bw->cursor, ' ');
1902 pgetc(bw->cursor);
1903 }
1904
1905 if (!no_decode) {
1906 if(!map->type) {
1907 /* Convert to byte code */
1908 k = from_uni(map, k);
1909 }
1910 }
1911
1912 binsc(bw->cursor, k);
1913
1914 /* We need x position before we move cursor */
1915 x = piscol(bw->cursor) - bw->offset;
1916 pgetc(bw->cursor);
1917
1918 /* Tabs are weird here... */
1919 if (bw->o.overtype && !piseol(bw->cursor) && k != '\t')
1920 udelch(bw->parent, 0);
1921
1922 /* Not sure if we're in right position for wordwrap when we're in overtype mode */
1923 if (bw->o.wordwrap && piscol(bw->cursor) > bw->o.rmargin && !joe_isblank(map,k)) {
1924 wrapword(bw, bw->cursor, bw->o.lmargin, bw->o.french, 0, NULL);
1925 simple = 0;
1926 }
1927
1928 bw->cursor->xcol = piscol(bw->cursor);
1929 #ifndef __MSDOS__
1930 if (x < 0 || x >= bw->w)
1931 simple = 0;
1932 if (bw->cursor->line < bw->top->line || bw->cursor->line >= bw->top->line + bw->h)
1933 simple = 0;
1934 if (simple && bw->parent->t->t->sary[bw->y + bw->cursor->line - bw->top->line])
1935 simple = 0;
1936 if (cclass_lookup(cclass_combining, k))
1937 simple = 0;
1938 if (simple && k != '\t' && k != '\n' && !curmacro) {
1939 int atr;
1940 SCRN *t = bw->parent->t->t;
1941 ptrdiff_t y = bw->y + TO_DIFF_OK(bw->cursor->line - bw->top->line);
1942 int (*screen)[COMPOSE] = t->scrn + y * t->co;
1943 int *attr = t->attr + y * t->co;
1944 x += bw->x;
1945
1946 atr = BG_COLOR(bg_text);
1947
1948 if (!upd && piseol(bw->cursor) && !bw->o.highlight)
1949 t->updtab[y] = 0;
1950 if (markb &&
1951 markk &&
1952 markb->b == bw->b &&
1953 markk->b == bw->b &&
1954 ((!square && bw->cursor->byte >= markb->byte && bw->cursor->byte < markk->byte) ||
1955 ( square && bw->cursor->line >= markb->line && bw->cursor->line <= markk->line && piscol(bw->cursor) >= markb->xcol && piscol(bw->cursor) < markk->xcol)))
1956 atr |= INVERSE;
1957 outatr(bw->b->o.charmap, t, screen + x, attr + x, x, y, k, atr);
1958 }
1959 #endif
1960 }
1961 return 0;
1962 }
1963
utypebw(BW * bw,int k)1964 int utypebw(BW *bw, int k)
1965 {
1966 return utypebw_raw(bw, k, 0);
1967 }
1968
utypew(W * w,int k)1969 int utypew(W *w, int k)
1970 {
1971 BW *bw;
1972 WIND_BW(bw, w);
1973 return utypebw(bw, k);
1974 }
1975
1976 /* Quoting */
1977
1978 static B *unicodehist = NULL; /* History of previously entered unicode characters */
1979
dounicode(W * w,char * s,void * object,int * notify)1980 static int dounicode(W *w, char *s, void *object, int *notify)
1981 {
1982 BW *bw;
1983 int num;
1984 WIND_BW(bw, w);
1985 num = zhtoi(s);
1986 if (notify)
1987 *notify = 1;
1988 vsrm(s);
1989 utypebw_raw(bw, num, 1);
1990 bw->cursor->xcol = piscol(bw->cursor);
1991 return 0;
1992 }
1993
1994 int quotestate;
1995 int quoteval;
1996
doquote(W * w,int c,void * object,int * notify)1997 static int doquote(W *w, int c, void *object, int *notify)
1998 {
1999 BW *bw;
2000 char buf[40];
2001 WIND_BW(bw, w);
2002
2003 /*
2004 if (c < 0 || c >= 256) {
2005 nungetc(c);
2006 return -1;
2007 }
2008 */
2009 switch (quotestate) {
2010 case 0:
2011 if (c >= '0' && c <= '9') {
2012 quoteval = c - '0';
2013 quotestate = 1;
2014 joe_snprintf_1(buf, SIZEOF(buf), "ASCII %c--", c);
2015 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
2016 return -1;
2017 else
2018 return 0;
2019 } else if (c == 'x' || c == 'X') {
2020 if (bw->b->o.charmap->type) {
2021 if (!wmkpw(bw->parent, joe_gettext(_("Unicode (ISO-10646) character in hex (%{abort} to abort): ")), &unicodehist, dounicode,
2022 NULL, NULL, NULL, NULL, NULL, locale_map, 0))
2023 return 0;
2024 else
2025 return -1;
2026 } else {
2027 quotestate = 3;
2028 if (!mkqwna(bw->parent, sc("ASCII 0x--"), doquote, NULL, NULL, notify))
2029 return -1;
2030 else
2031 return 0;
2032 }
2033 } else if (c == 'o' || c == 'O') {
2034 quotestate = 5;
2035 if (!mkqwna(bw->parent, sc("ASCII 0---"), doquote, NULL, NULL, notify))
2036 return -1;
2037 else
2038 return 0;
2039 } else {
2040 if ((c >= 0x40 && c <= 0x5F) || (c >= 'a' && c <= 'z'))
2041 c &= 0x1F;
2042 if (c == '?')
2043 c = 127;
2044 utypebw_raw(bw, c, 1);
2045 bw->cursor->xcol = piscol(bw->cursor);
2046 }
2047 break;
2048 case 1:
2049 if (c >= '0' && c <= '9') {
2050 joe_snprintf_2(buf, SIZEOF(buf), "ASCII %c%c-", quoteval + '0', c);
2051 quoteval = quoteval * 10 + c - '0';
2052 quotestate = 2;
2053 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
2054 return -1;
2055 else
2056 return 0;
2057 }
2058 break;
2059 case 2:
2060 if (c >= '0' && c <= '9') {
2061 quoteval = quoteval * 10 + c - '0';
2062 utypebw_raw(bw, quoteval, 1);
2063 bw->cursor->xcol = piscol(bw->cursor);
2064 }
2065 break;
2066 case 3:
2067 if (c >= '0' && c <= '9') {
2068 joe_snprintf_1(buf, SIZEOF(buf), "ASCII 0x%c-", c);
2069 quoteval = c - '0';
2070 quotestate = 4;
2071 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
2072 return -1;
2073 else
2074 return 0;
2075 } else if (c >= 'a' && c <= 'f') {
2076 joe_snprintf_1(buf, SIZEOF(buf), "ASCII 0x%c-", c + 'A' - 'a');
2077 quoteval = c - 'a' + 10;
2078 quotestate = 4;
2079 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
2080 return -1;
2081 else
2082 return 0;
2083 } else if (c >= 'A' && c <= 'F') {
2084 joe_snprintf_1(buf, SIZEOF(buf), "ASCII 0x%c-", c);
2085 quoteval = c - 'A' + 10;
2086 quotestate = 4;
2087 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
2088 return -1;
2089 else
2090 return 0;
2091 }
2092 break;
2093 case 4:
2094 if (c >= '0' && c <= '9') {
2095 quoteval = quoteval * 16 + c - '0';
2096 utypebw_raw(bw, quoteval, 1);
2097 bw->cursor->xcol = piscol(bw->cursor);
2098 } else if (c >= 'a' && c <= 'f') {
2099 quoteval = quoteval * 16 + c - 'a' + 10;
2100 utypebw_raw(bw, quoteval, 1);
2101 bw->cursor->xcol = piscol(bw->cursor);
2102 } else if (c >= 'A' && c <= 'F') {
2103 quoteval = quoteval * 16 + c - 'A' + 10;
2104 utypebw_raw(bw, quoteval, 1);
2105 bw->cursor->xcol = piscol(bw->cursor);
2106 }
2107 break;
2108 case 5:
2109 if (c >= '0' && c <= '7') {
2110 joe_snprintf_1(buf, SIZEOF(buf), "ASCII 0%c--", c);
2111 quoteval = c - '0';
2112 quotestate = 6;
2113 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
2114 return -1;
2115 else
2116 return 0;
2117 }
2118 break;
2119 case 6:
2120 if (c >= '0' && c <= '7') {
2121 joe_snprintf_2(buf, SIZEOF(buf), "ASCII 0%c%c-", quoteval + '0', c);
2122 quoteval = quoteval * 8 + c - '0';
2123 quotestate = 7;
2124 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
2125 return -1;
2126 else
2127 return 0;
2128 }
2129 break;
2130 case 7:
2131 if (c >= '0' && c <= '7') {
2132 quoteval = quoteval * 8 + c - '0';
2133 utypebw_raw(bw, quoteval, 1);
2134 bw->cursor->xcol = piscol(bw->cursor);
2135 }
2136 break;
2137 }
2138 if (notify)
2139 *notify = 1;
2140 return 0;
2141 }
2142
uquote(W * w,int k)2143 int uquote(W *w, int k)
2144 {
2145 BW *bw;
2146 WIND_BW(bw, w);
2147 quotestate = 0;
2148 if (mkqwna(bw->parent, sz(joe_gettext(_("Ctrl- (or 0-9 for dec. ascii, x for hex, or o for octal)"))), doquote, NULL, NULL, NULL))
2149 return 0;
2150 else
2151 return -1;
2152 }
2153
doquote9(W * w,int c,void * object,int * notify)2154 static int doquote9(W *w, int c, void *object, int *notify)
2155 {
2156 BW *bw;
2157 WIND_BW(bw, w);
2158 if (notify)
2159 *notify = 1;
2160 if ((c >= 0x40 && c <= 0x5F) || (c >= 'a' && c <= 'z'))
2161 c &= 0x1F;
2162 if (c == '?')
2163 c = 127;
2164 if (c >= 0 && c <= 127)
2165 c |= 128;
2166 utypebw_raw(bw, c, 1);
2167 bw->cursor->xcol = piscol(bw->cursor);
2168 return 0;
2169 }
2170
doquote8(W * w,int c,void * object,int * notify)2171 static int doquote8(W *w, int c, void *object, int *notify)
2172 {
2173 BW *bw;
2174 WIND_BW(bw, w);
2175 if (c == '`') {
2176 if (mkqwna(bw->parent, sc("Meta-Ctrl-"), doquote9, NULL, NULL, notify))
2177 return 0;
2178 else
2179 return -1;
2180 }
2181 if (notify)
2182 *notify = 1;
2183 if (c >= 0 && c <= 127)
2184 c |= 128;
2185 utypebw_raw(bw, c, 1);
2186 bw->cursor->xcol = piscol(bw->cursor);
2187 return 0;
2188 }
2189
uquote8(W * w,int k)2190 int uquote8(W *w, int k)
2191 {
2192 if (mkqwna(w, sc("Meta-"), doquote8, NULL, NULL, NULL))
2193 return 0;
2194 else
2195 return -1;
2196 }
2197
doctrl(W * w,int c,void * object,int * notify)2198 static int doctrl(W *w, int c, void *object, int *notify)
2199 {
2200 BW *bw;
2201 int org;
2202 WIND_BW(bw, w);
2203 org = bw->o.overtype;
2204
2205 if (notify)
2206 *notify = 1;
2207 bw->o.overtype = 0;
2208 if ((bw->parent->huh == srchstr || bw->parent->huh == replstr) && c == '\n') {
2209 utypebw(bw, '\\');
2210 utypebw(bw, 'n');
2211 } else
2212 utypebw_raw(bw, c, 1);
2213 bw->o.overtype = org;
2214 bw->cursor->xcol = piscol(bw->cursor);
2215 return 0;
2216 }
2217
uctrl(W * w,int k)2218 int uctrl(W *w, int k)
2219 {
2220 BW *bw;
2221 WIND_BW(bw, w);
2222 if (mkqwna(bw->parent, sz(joe_gettext(_("Quote"))), doctrl, NULL, NULL, NULL))
2223 return 0;
2224 else
2225 return -1;
2226 }
2227
2228 /* User hit Return. Deal with autoindent.
2229 */
2230
rtntw(W * w)2231 int rtntw(W *w)
2232 {
2233 BW *bw;
2234 WIND_BW(bw, w);
2235 if (bw->o.overtype) {
2236 p_goto_eol(bw->cursor);
2237 if (piseof(bw->cursor))
2238 binsc(bw->cursor, '\n');
2239 pgetc(bw->cursor);
2240 bw->cursor->xcol = piscol(bw->cursor);
2241 } else {
2242 P *p = pdup(bw->cursor, "rtntw");
2243 int c;
2244
2245 binsc(bw->cursor, '\n'), pgetc(bw->cursor);
2246 /* Suppress autoindent if we're on a space or tab... */
2247 if (bw->o.autoindent /* && (brch(bw->cursor)!=' ' && brch(bw->cursor)!='\t')*/) {
2248 p_goto_bol(p);
2249 while (joe_isspace(bw->b->o.charmap,(c = pgetc(p))) && c != '\n') {
2250 binsc(bw->cursor, c);
2251 pgetc(bw->cursor);
2252 }
2253 }
2254 prm(p);
2255 bw->cursor->xcol = piscol(bw->cursor);
2256 }
2257 return 0;
2258 }
2259
2260 /* Open a line */
2261
uopen(W * w,int k)2262 int uopen(W *w, int k)
2263 {
2264 BW *bw;
2265 WIND_BW(bw, w);
2266 binsc(bw->cursor,'\n');
2267 if (bw->o.autoindent && (brch(bw->cursor)!=' ' && brch(bw->cursor)!='\t')) {
2268 P *p = pdup(bw->cursor, "uopen");
2269 P *q = pdup(p, "uopen");
2270 int c;
2271 pgetc(q);
2272 p_goto_bol(p);
2273 while (joe_isspace(bw->b->o.charmap,(c = pgetc(p))) && c != '\n') {
2274 binsc(q, c);
2275 pgetc(q);
2276 }
2277 prm(p); prm(q);
2278 }
2279
2280 return 0;
2281 }
2282
2283 /* Set book-mark */
2284
dosetmark(W * w,int c,void * object,int * notify)2285 static int dosetmark(W *w, int c, void *object, int *notify)
2286 {
2287 BW *bw;
2288 WIND_BW(bw, w);
2289 if (notify)
2290 *notify = 1;
2291 if (c >= '0' && c <= ':') {
2292 pdupown(bw->cursor, bw->b->marks + c - '0', "dosetmark");
2293 poffline(bw->b->marks[c - '0']);
2294 if (c!=':') {
2295 joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("Mark %d set")), c - '0');
2296 msgnw(bw->parent, msgbuf);
2297 }
2298 return 0;
2299 } else {
2300 nungetc(c);
2301 return -1;
2302 }
2303 }
2304
usetmark(W * w,int c)2305 int usetmark(W *w, int c)
2306 {
2307 if (c >= '0' && c <= ':')
2308 return dosetmark(w, c, NULL, NULL);
2309 else if (mkqwna(w, sz(joe_gettext(_("Set mark (0-9):"))), dosetmark, NULL, NULL, NULL))
2310 return 0;
2311 else
2312 return -1;
2313 }
2314
2315 /* Goto book-mark */
2316
dogomark(W * w,int c,void * object,int * notify)2317 static int dogomark(W *w, int c, void *object, int *notify)
2318 {
2319 BW *bw;
2320 WIND_BW(bw, w);
2321 if (notify)
2322 *notify = 1;
2323 if (c >= '0' && c <= ':')
2324 if (bw->b->marks[c - '0']) {
2325 pset(bw->cursor, bw->b->marks[c - '0']);
2326 bw->cursor->xcol = piscol(bw->cursor);
2327 return 0;
2328 } else {
2329 joe_snprintf_1(msgbuf, JOE_MSGBUFSIZE, joe_gettext(_("Mark %d not set")), c - '0');
2330 msgnw(bw->parent, msgbuf);
2331 return -1;
2332 } else {
2333 nungetc(c);
2334 return -1;
2335 }
2336 }
2337
ugomark(W * w,int c)2338 int ugomark(W *w, int c)
2339 {
2340 if (c >= '0' && c <= '9')
2341 return dogomark(w, c, NULL, NULL);
2342 else if (mkqwna(w, sz(joe_gettext(_("Goto bookmark (0-9):"))), dogomark, NULL, NULL, NULL))
2343 return 0;
2344 else
2345 return -1;
2346 }
2347
2348 /* Goto next instance of character */
2349
2350 static int dobkwdc;
2351
dofwrdc(W * w,int k,void * object,int * notify)2352 static int dofwrdc(W *w, int k, void *object, int *notify)
2353 {
2354 BW *bw;
2355 int c;
2356 P *q;
2357 WIND_BW(bw, w);
2358
2359 if (notify)
2360 *notify = 1;
2361 if (k < 0 || k >= 256) {
2362 nungetc(k);
2363 return -1;
2364 }
2365 q = pdup(bw->cursor, "dofwrdc");
2366 if (dobkwdc) {
2367 while ((c = prgetc(q)) != NO_MORE_DATA)
2368 if (c == k)
2369 break;
2370 } else {
2371 while ((c = pgetc(q)) != NO_MORE_DATA)
2372 if (c == k)
2373 break;
2374 }
2375 if (c == NO_MORE_DATA) {
2376 msgnw(bw->parent, joe_gettext(_("Not found")));
2377 prm(q);
2378 return -1;
2379 } else {
2380 pset(bw->cursor, q);
2381 bw->cursor->xcol = piscol(bw->cursor);
2382 prm(q);
2383 return 0;
2384 }
2385 }
2386
ufwrdc(W * w,int k)2387 int ufwrdc(W *w, int k)
2388 {
2389 dobkwdc = 0;
2390 if (k >= 0 && k < 256)
2391 return dofwrdc(w, k, NULL, NULL);
2392 else if (mkqw(w, sz(joe_gettext(_("Forward to char: "))), dofwrdc, NULL, NULL, NULL))
2393 return 0;
2394 else
2395 return -1;
2396 }
2397
ubkwdc(W * w,int k)2398 int ubkwdc(W *w, int k)
2399 {
2400 dobkwdc = 1;
2401 if (k >= 0 && k < 256)
2402 return dofwrdc(w, k, NULL, NULL);
2403 else if (mkqw(w, sz(joe_gettext(_("Backward to char: "))), dofwrdc, NULL, NULL, NULL))
2404 return 0;
2405 else
2406 return -1;
2407 }
2408
2409 /* Display a message */
2410
domsg(W * w,char * s,void * object,int * notify)2411 static int domsg(W *w, char *s, void *object, int *notify)
2412 {
2413 if (notify)
2414 *notify = 1;
2415 zlcpy(msgbuf, SIZEOF(msgbuf), s);
2416 vsrm(s);
2417 msgnw(w, msgbuf);
2418 return 0;
2419 }
2420
umsg(W * w,int k)2421 int umsg(W *w, int k)
2422 {
2423 if (wmkpw(w, joe_gettext(_("Message (%{abort} to abort): ")), NULL, domsg, NULL, NULL, NULL, NULL, NULL, locale_map, 0))
2424 return 0;
2425 else
2426 return -1;
2427 }
2428
2429 /* Insert text */
2430
dotxt(W * w,char * s,void * object,int * notify)2431 static int dotxt(W *w, char *s, void *object, int *notify)
2432 {
2433 char fill;
2434 char *str;
2435 BW *bw;
2436 WIND_BW(bw, w);
2437
2438 if (notify)
2439 *notify = 1;
2440 if (s[0] == '`') {
2441 str = vsmk(1024);
2442 fill = ' ';
2443 str = stagen(str, bw, &s[1], fill);
2444 vsrm(s);
2445 s = str;
2446 }
2447 if (s) {
2448 const char *t = s;
2449 ptrdiff_t len = sLEN(s);
2450 while (len) {
2451 int c;
2452 if (bw->b->o.charmap->type)
2453 c = utf8_decode_fwrd(&t, &len);
2454 else {
2455 c = *(const unsigned char *)t++;
2456 --len;
2457 }
2458 if (c >= 0)
2459 utypebw_raw(bw, c, 1);
2460 }
2461 vsrm(s);
2462 }
2463 return 0;
2464 }
2465
utxt(W * w,int k)2466 int utxt(W *w, int k)
2467 {
2468 BW *bw;
2469 WIND_BW(bw, w);
2470 if (wmkpw(w, joe_gettext(_("Insert (%{abort} to abort): ")), NULL, dotxt, NULL, NULL, utypebw, NULL, NULL, bw->b->o.charmap, 0))
2471 return 0;
2472 else
2473 return -1;
2474 }
2475
2476 /* Insert current file name */
2477
uname_joe(W * w,int k)2478 int uname_joe(W *w, int k)
2479 {
2480 const char *s;
2481 s=((BW *)w->main->object)->b->name;
2482 if (!s || !*s)
2483 return -1;
2484 while (*s)
2485 if (utypew(w,*(const unsigned char *)s++))
2486 return -1;
2487 return 0;
2488 }
2489
2490 /* Insert until non-base64 character received */
2491
upaste(W * w,int k)2492 int upaste(W *w, int k)
2493 {
2494 int c;
2495 int accu = 0;
2496 int count;
2497 int tmp_ww;
2498 int tmp_ai;
2499 BW *bw;
2500 WIND_BW(bw, w);
2501 tmp_ww = bw->o.wordwrap;
2502 tmp_ai = bw->o.autoindent;
2503
2504 bw->o.wordwrap = 0;
2505 bw->o.autoindent = 0;
2506 count = 0;
2507
2508 /* We have to wait for the second ';' */
2509 while ((c = ttgetch()) != -1)
2510 if (c == ';')
2511 break;
2512 if (c == -1)
2513 goto bye;
2514
2515 while ((c = ttgetch()) != -1) {
2516 if (c >= 'A' && c <= 'Z')
2517 c = c - 'A';
2518 else if (c >= 'a' && c <= 'z')
2519 c = c - 'a' + 26;
2520 else if (c >= '0' && c <= '9')
2521 c = c - '0' + 52;
2522 else if (c == '+')
2523 c = 62;
2524 else if (c == '/')
2525 c = 63;
2526 else if (c == '=')
2527 continue;
2528 else
2529 break;
2530
2531 switch (count) {
2532 case 0:
2533 accu = c;
2534 count = 6;
2535 break;
2536 case 2:
2537 accu = (accu << 6) + c;
2538 if (accu == 13)
2539 rtntw(bw->parent);
2540 else
2541 utypebw(bw, accu);
2542 count = 0;
2543 break;
2544 case 4:
2545 accu = (accu << 4) + (c >> 2);
2546 if (accu == 13)
2547 rtntw(bw->parent);
2548 else
2549 utypebw(bw, accu);
2550 accu = (c & 0x3);
2551 count = 2;
2552 break;
2553 case 6:
2554 accu = (accu << 2) + (c >> 4);
2555 if (accu == 13)
2556 rtntw(bw->parent);
2557 else
2558 utypebw(bw, accu);
2559 accu = (c & 0xF);
2560 count = 4;
2561 break;
2562 }
2563 }
2564 /* Terminator is ESC \ */
2565 if (c == 033) {
2566 ttgetch();
2567 }
2568
2569 bye:
2570
2571 bw->o.wordwrap = tmp_ww;
2572 bw->o.autoindent = tmp_ai;
2573
2574 return 0;
2575 }
2576
2577 /* Bracketed paste */
2578
2579 int saved_ww;
2580 int saved_ai;
2581 int saved_sp;
2582
ubrpaste(W * w,int k)2583 int ubrpaste(W *w, int k)
2584 {
2585 BW *bw;
2586
2587 WIND_BW(bw, w);
2588
2589 saved_ww = bw->o.wordwrap;
2590 saved_ai = bw->o.autoindent;
2591 saved_sp = bw->o.spaces;
2592
2593 bw->o.wordwrap = bw->o.autoindent = bw->o.spaces = 0;
2594
2595 return 0;
2596 }
2597
ubrpaste_done(W * w,int k)2598 int ubrpaste_done(W *w, int k)
2599 {
2600 BW *bw;
2601
2602 WIND_BW(bw, w);
2603
2604 bw->o.wordwrap = saved_ww;
2605 bw->o.autoindent = saved_ai;
2606 bw->o.spaces = saved_sp;
2607
2608 return 0;
2609 }
2610