1 /* $MirOS: contrib/code/jupp/uedit.c,v 1.15 2017/01/11 22:56:49 tg Exp $ */
3 * Basic user edit functions
5 * (C) 1992 Joseph H. Allen
7 * This file is part of JOE (Joe's Own Editor)
14 #ifdef HAVE_BSD_STRING_H
15 #include <bsd/string.h>
36 int pgamnt = -1; /* No. of PgUp/PgDn lines to keep */
38 /******** i don't like global var ******/
41 * Move cursor to beginning of line
43 int u_goto_bol(BW *bw)
46 pbkwd(bw->cursor,bw->cursor->byte%16);
48 p_goto_bol(bw->cursor);
54 * Move cursor to first non-whitespace character, unless it is
55 * already there, in which case move it to beginning of line
62 return u_goto_bol(bw);
67 if (bw->o.indentfirst) {
68 if ((bw->o.smarthome) && (piscol(p) > pisindent(p))) {
70 while (joe_isblank(p->b->o.charmap,brc(p)))
75 if (bw->o.smarthome && piscol(p)==0 && pisindent(p)) {
76 while (joe_isblank(p->b->o.charmap,brc(p)))
88 * Move cursor to end of line
90 int u_goto_eol(BW *bw)
93 if (bw->cursor->byte + 15 - bw->cursor->byte%16 > bw->b->eof->byte)
94 pset(bw->cursor,bw->b->eof);
96 pfwrd(bw->cursor, 15 - bw->cursor->byte%16);
98 p_goto_eol(bw->cursor);
103 * Move cursor to beginning of file
105 int u_goto_bof(BW *bw)
107 p_goto_bof(bw->cursor);
112 * Move cursor to end of file
114 int u_goto_eof(BW *bw)
116 p_goto_eof(bw->cursor);
123 int u_goto_left(BW *bw)
126 if (prgetb(bw->cursor) != NO_MORE_DATA) {
133 if (bw->cursor->xcol) {
135 pcol(bw->cursor,bw->cursor->xcol);
139 /* Have to do ECHKXCOL here because of picture mode */
140 if (bw->cursor->xcol != piscol(bw->cursor)) {
141 bw->cursor->xcol = piscol(bw->cursor);
143 } else if (prgetc(bw->cursor) != NO_MORE_DATA) {
144 bw->cursor->xcol = piscol(bw->cursor);
154 int u_goto_right(BW *bw)
157 if (pgetb(bw->cursor) != NO_MORE_DATA) {
165 pcol(bw->cursor,bw->cursor->xcol);
169 if (pgetc(bw->cursor) != NO_MORE_DATA) {
170 bw->cursor->xcol = piscol(bw->cursor);
175 /* Have to do EFIXXCOL here because of picture mode */
176 if (bw->cursor->xcol != piscol(bw->cursor))
177 bw->cursor->xcol = piscol(bw->cursor);
183 * Move cursor to beginning of previous word or if there isn't
184 * previous word then go to beginning of the file
186 * WORD is a sequence non-white-space characters
188 int u_goto_prev(BW *bw)
190 P *p = pdup(bw->cursor);
191 struct charmap *map=bw->b->o.charmap;
194 if (joe_isalnum_(map,c)) {
195 while (joe_isalnum_(map,(c=prgetc(p))))
197 if (c != NO_MORE_DATA)
199 } else if (joe_isspace(map,c) || joe_ispunct(map,c)) {
200 while ((c=prgetc(p)), (joe_isspace(map,c) || joe_ispunct(map,c)))
202 while(joe_isalnum_(map,(c=prgetc(p))))
204 if (c != NO_MORE_DATA)
208 if (p->byte == bw->cursor->byte) {
219 * Move cursor to end of next word or if there isn't
220 * next word then go to end of the file
222 * WORD is a sequence non-white-space characters
224 int u_goto_next(BW *bw)
226 P *p = pdup(bw->cursor);
227 struct charmap *map=bw->b->o.charmap;
231 if (joe_isalnum_(map,c)) {
233 while (joe_isalnum_(map,(c = brch(p))))
235 } else if (joe_isspace(map,c) || joe_ispunct(map,c)) {
236 while (joe_isspace(map, (c = brch(p))) || joe_ispunct(map,c))
238 while (joe_isalnum_(map,(c = brch(p)))) {
252 while (joe_isblank(p->b->o.charmap,brch(p)))
257 static int pisedge(P *p)
268 if (q->byte == p->byte)
270 if (joe_isblank(p->b->o.charmap,(c = brch(p)))) {
272 if (joe_isblank(p->b->o.charmap,prgetc(q)))
288 if (prgetc(q) == ' ')
303 if (prgetc(bw->cursor) == NO_MORE_DATA)
305 while (pisedge(bw->cursor) != -1)
312 if (pgetc(bw->cursor) == NO_MORE_DATA)
314 while (pisedge(bw->cursor) != 1)
319 /* Move cursor to matching delimiter */
322 utomatch_i(BW *bw, int dir)
325 int c; /* character under cursor */
326 int f; /* character to find */
328 int cnt = 0; /* delimiter depth */
330 switch (c = brch(bw->cursor)) {
372 p = pdup(bw->cursor);
374 while ((d = pgetc(p)) != NO_MORE_DATA) {
375 if (d == f && f != c && !--cnt) {
385 while ((d = prgetc(p)) != NO_MORE_DATA) {
386 if (d == f && !cnt--)
392 if (/* CONSTCOND */ 0) {
397 return ((d == NO_MORE_DATA) ? -1 : 0);
402 return (utomatch_i(bw, 1));
407 return (utomatch_i(bw, -1));
415 if (bw->cursor->byte<16)
418 pbkwd(bw->cursor, 16);
422 if (bw->cursor->line) {
424 pcol(bw->cursor, bw->cursor->xcol);
430 /* Move cursor down */
435 if (bw->cursor->byte+16 <= bw->b->eof->byte) {
436 pfwrd(bw->cursor, 16);
438 } else if (bw->cursor->byte != bw->b->eof->byte) {
439 pset(bw->cursor, bw->b->eof);
445 if (bw->cursor->line != bw->b->eof->line) {
447 pcol(bw->cursor, bw->cursor->xcol);
449 } else if(bw->o.picture) {
450 p_goto_eol(bw->cursor);
451 binsc(bw->cursor,'\n');
453 pcol(bw->cursor, bw->cursor->xcol);
459 /* Move cursor to top of window */
463 long col = bw->cursor->xcol;
465 pset(bw->cursor, bw->top);
466 pcol(bw->cursor, col);
467 bw->cursor->xcol = col;
471 /* Move cursor to bottom of window */
475 long col = bw->cursor->xcol;
477 pline(bw->cursor, bw->top->line + bw->h - 1);
478 pcol(bw->cursor, col);
479 bw->cursor->xcol = col;
483 /* Scroll buffer window up n lines
484 * If beginning of file is close, scrolls as much as it can
485 * If beginning of file is on-screen, cursor jumps to beginning of file
487 * If flg is set: cursor stays fixed relative to screen edge
488 * If flg is clr: cursor stays fixed on the buffer line
491 void scrup(BW *bw, int n, int flg)
497 /* Decide number of lines we're really going to scroll */
500 if (bw->top->byte/16 >= n)
501 scrollamnt = cursoramnt = n;
502 else if (bw->top->byte/16)
503 scrollamnt = cursoramnt = bw->top->byte/16;
505 cursoramnt = bw->cursor->byte/16;
506 else if (bw->cursor->byte/16 >= n)
509 if (bw->top->line >= n)
510 scrollamnt = cursoramnt = n;
511 else if (bw->top->line)
512 scrollamnt = cursoramnt = bw->top->line;
514 cursoramnt = bw->cursor->line;
515 else if (bw->cursor->line >= n)
520 /* Move top-of-window pointer */
521 pbkwd(bw->top,scrollamnt*16);
523 pbkwd(bw->cursor,cursoramnt*16);
524 /* If window is on the screen, give (buffered) scrolling command */
525 if (bw->parent->y != -1)
526 nscrldn(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
528 /* Move top-of-window pointer */
529 for (x = 0; x != scrollamnt; ++x)
534 for (x = 0; x != cursoramnt; ++x)
536 p_goto_bol(bw->cursor);
537 pcol(bw->cursor, bw->cursor->xcol);
539 /* If window is on the screen, give (buffered) scrolling command */
540 if (bw->parent->y != -1)
541 nscrldn(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
545 /* Scroll buffer window down n lines
546 * If end of file is close, scrolls as much as possible
547 * If end of file is on-screen, cursor jumps to end of file
549 * If flg is set: cursor stays fixed relative to screen edge
550 * If flg is clr: cursor stays fixed on the buffer line
553 void scrdn(BW *bw, int n, int flg)
559 /* How much we're really going to scroll... */
561 if (bw->top->b->eof->byte/16 < bw->top->byte/16 + bw->h) {
562 cursoramnt = bw->top->b->eof->byte/16 - bw->cursor->byte/16;
563 if (!flg && cursoramnt > n)
565 } else if (bw->top->b->eof->byte/16 - (bw->top->byte/16 + bw->h) >= n)
566 cursoramnt = scrollamnt = n;
568 cursoramnt = scrollamnt = bw->top->b->eof->byte/16 - (bw->top->byte/16 + bw->h) + 1;
570 if (bw->top->b->eof->line < bw->top->line + bw->h) {
571 cursoramnt = bw->top->b->eof->line - bw->cursor->line;
572 if (!flg && cursoramnt > n)
574 } else if (bw->top->b->eof->line - (bw->top->line + bw->h) >= n)
575 cursoramnt = scrollamnt = n;
577 cursoramnt = scrollamnt = bw->top->b->eof->line - (bw->top->line + bw->h) + 1;
581 /* Move top-of-window pointer */
582 pfwrd(bw->top,16*scrollamnt);
584 pfwrd(bw->cursor,16*cursoramnt);
585 /* If window is on screen, give (buffered) scrolling command to terminal */
586 if (bw->parent->y != -1)
587 nscrlup(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
589 /* Move top-of-window pointer */
590 for (x = 0; x != scrollamnt; ++x)
594 for (x = 0; x != cursoramnt; ++x)
596 pcol(bw->cursor, bw->cursor->xcol);
598 /* If window is on screen, give (buffered) scrolling command to terminal */
599 if (bw->parent->y != -1)
600 nscrlup(bw->parent->t->t, bw->y, bw->y + bw->h, scrollamnt);
608 bw = (BW *) bw->parent->main->object;
609 if (bw->o.hex ? bw->cursor->byte < 16 : !bw->cursor->line)
612 scrup(bw, bw->h / 2 + bw->h % 2, 1);
613 else if (pgamnt < bw->h)
614 scrup(bw, bw->h - pgamnt, 1);
624 bw = (BW *) bw->parent->main->object;
625 if (bw->o.hex ? bw->cursor->byte/16 == bw->b->eof->byte/16 : bw->cursor->line == bw->b->eof->line)
628 scrdn(bw, bw->h / 2 + bw->h % 2, 1);
629 else if (pgamnt < bw->h)
630 scrdn(bw, bw->h - pgamnt, 1);
636 /* Scroll by a single line. The cursor moves with the scroll */
640 bw = (BW *) bw->parent->main->object;
641 if (bw->o.hex ? bw->top->byte/16 : bw->top->line) {
642 if (bw->o.hex ? bw->top->byte/16 + bw->h -1 != bw->cursor->byte/16 : bw->top->line + bw->h - 1 != bw->cursor->line)
652 bw = (BW *) bw->parent->main->object;
653 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) {
654 if (bw->o.hex ? bw->top->byte/16 != bw->cursor->byte/16 : bw->top->line != bw->cursor->line)
662 /* Move cursor to specified line number */
664 static B *linehist = NULL; /* History of previously entered line numbers */
666 static int doline(BW *bw, unsigned char *s, void *object, int *notify)
668 long num = calc(bw, s);
673 if (num >= 1 && !merr) {
676 if (num > bw->b->eof->line)
677 num = bw->b->eof->line + 1;
678 pline(bw->cursor, num - 1), bw->cursor->xcol = piscol(bw->cursor);
685 msgnw(bw->parent, merr);
687 msgnw(bw->parent, US "Invalid line number");
694 if (wmkpw(bw->parent, US "Go to line (^C to abort): ", &linehist, doline, NULL, NULL, NULL, NULL, NULL, locale_map))
700 /* Move cursor to specified column number */
702 static B *colhist = NULL; /* History of previously entered column numbers */
704 static int docol(BW *bw, unsigned char *s, void *object, int *notify)
706 long num = calc(bw, s);
711 if (num >= 1 && !merr) {
714 pcol(bw->cursor, num - 1), bw->cursor->xcol = piscol(bw->cursor);
721 msgnw(bw->parent, merr);
723 msgnw(bw->parent, US "Invalid column number");
730 if (wmkpw(bw->parent, US "Go to column (^C to abort): ", &colhist, docol, NULL, NULL, NULL, NULL, NULL, locale_map))
736 /* Move cursor to specified byte number */
738 static B *bytehist = NULL; /* History of previously entered byte numbers */
740 static int dobyte(BW *bw, unsigned char *s, void *object, int *notify)
742 long num = calc(bw, s);
747 if (num >= 0 && !merr) {
750 pgoto(bw->cursor, num), bw->cursor->xcol = piscol(bw->cursor);
757 msgnw(bw->parent, merr);
759 msgnw(bw->parent, US "Invalid byte number");
766 if (wmkpw(bw->parent, US "Go to byte (^C to abort): ", &bytehist, dobyte, NULL, NULL, NULL, NULL, NULL, locale_map))
772 /* Delete character under cursor
773 * or write ^D to process if we're at end of file in a shell window
780 if (piseof(bw->cursor))
782 pgetc(p = pdup(bw->cursor));
790 int ubacks(BW *bw, int k)
792 /* Don't backspace when at beginning of line in prompt windows */
793 if (bw->parent->watom->what == TYPETW || !pisbol(bw->cursor)) {
800 if (pisbof(bw->cursor))
803 /* Indentation point of this line */
804 indent = pisindent(bw->cursor);
806 /* Column position of cursor */
807 col = piscol(bw->cursor);
809 /* Indentation step in columns */
810 if (bw->o.indentc=='\t')
815 indwid = (bw->o.istep*wid);
817 /* Smart backspace when: cursor is at indentation point, indentation point
818 is a multiple of indentation width, we're not at beginning of line,
819 'smarthome' option is enabled, and indentation is purely made out of
820 indent characters (or purify indents is enabled). */
822 /* Ignore purify for backspace */
823 if (col == indent && (col%indwid)==0 && col!=0 && bw->o.smartbacks) {
826 /* Delete all indentation */
827 p = pdup(bw->cursor);
832 /* Indent to new position */
833 pfill(bw->cursor,col-indwid,bw->o.indentc);
834 } else if (col<indent && !pisbol(bw->cursor) && bw->o.smartbacks) {
835 /* We're before indent point: delete indwid worth of space but do not
836 cross line boundary. We could probably replace the above with this. */
838 P *p = pdup(bw->cursor);
840 c = prgetc(bw->cursor);
841 if(c=='\t') cw += bw->o.tab;
844 } while(!pisbol(bw->cursor) && cw<indwid);
847 /* Regular backspace */
848 P *p = pdup(bw->cursor);
849 if ((c = prgetc(bw->cursor)) != NO_MORE_DATA)
850 if (!bw->o.overtype || c == '\t' || pisbol(p) || piseol(p))
860 * Delete sequence of characters (alphabetic, numeric) or (white-space)
861 * if cursor is on the white-space it will delete all white-spaces
862 * until alphanumeric character
863 * if cursor is on the alphanumeric it will delete all alphanumeric
864 * characters until character that is not alphanumeric
866 int u_word_delete(BW *bw)
868 P *p = pdup(bw->cursor);
869 struct charmap *map=bw->b->o.charmap;
872 if (joe_isalnum_(map,c))
873 while (joe_isalnum_(map,(c = brch(p))))
875 else if (joe_isspace(map,c))
876 while (joe_isspace(map,(c = brch(p))))
881 if (p->byte == bw->cursor->byte) {
890 /* Delete from cursor to beginning of word it's in or immediately after,
891 * to start of whitespace, or a single character
896 P *p = pdup(bw->cursor);
897 int c = prgetc(bw->cursor);
898 struct charmap *map=bw->b->o.charmap;
900 if (joe_isalnum_(map,c)) {
901 while (joe_isalnum_(map,(c = prgetc(bw->cursor))))
903 if (c != NO_MORE_DATA)
905 } else if (joe_isspace(map,c)) {
906 while (joe_isspace(map,(c = prgetc(bw->cursor))))
908 if (c != NO_MORE_DATA)
911 if (bw->cursor->byte == p->byte) {
920 /* Delete from cursor to end of line, or if there's nothing to delete,
921 * delete the line-break
926 P *p = p_goto_eol(pdup(bw->cursor));
928 if (bw->cursor->byte == p->byte) {
937 /* Delete to beginning of line, or if there's nothing to delete,
938 * delete the line-break
943 P *p = p_goto_bol(pdup(bw->cursor));
945 if (p->byte == bw->cursor->byte) {
947 return ubacks(bw, 8); /* The 8 goes to the process if we're at EOF of shell window */
954 /* Delete entire line */
958 P *p = pdup(bw->cursor);
960 p_goto_bol(bw->cursor);
962 if (bw->cursor->byte == p->byte) {
975 binsc(bw->cursor, ' ');
979 /* Move p backwards to first non-blank line and return its indentation */
981 int find_indent(P *p)
984 for (x=0; x != 10; ++x) {
985 if (!pprevl(p)) return -1;
987 if (!pisblank(p)) break;
995 /* Type a character into the buffer (deal with left margin, overtype mode and
996 * word-wrap), if cursor is at end of shell window buffer, just send character
1000 struct utf8_sm utype_utf8_sm;
1002 int utypebw_raw(BW *bw, int k, int no_decode)
1004 struct charmap *map=bw->b->o.charmap;
1006 /* Hex mode overtype is real simple */
1007 if (bw->o.hex && bw->o.overtype) {
1009 unsigned char c = k;
1010 binsm(bw->cursor, &c, 1);
1012 if (piseof(bw->cursor))
1014 pgetb(p = pdup(bw->cursor));
1015 bdel(bw->cursor, p);
1020 if (k == '\t' && bw->o.overtype && !piseol(bw->cursor)) { /* TAB in overtype mode is supposed to be just cursor motion */
1021 int col = bw->cursor->xcol; /* Current cursor column */
1022 col = col + bw->o.tab - (col%bw->o.tab);/* Move to next tab stop */
1023 pcol(bw->cursor,col); /* Try to position cursor there */
1024 if (!bw->o.picture && piseol(bw->cursor) && piscol(bw->cursor)<col) { /* We moved past end of line, insert a tab (unless in picture mode) */
1026 pfill(bw->cursor,col,' ');
1028 pfill(bw->cursor,col,'\t');
1030 bw->cursor->xcol = col; /* Put cursor there even if we can't really go there */
1031 } else if (k == '\t' && bw->o.smartbacks && bw->o.autoindent && pisindent(bw->cursor)>=piscol(bw->cursor)) {
1032 P *p = pdup(bw->cursor);
1033 int n = find_indent(p);
1034 if (n != -1 && pisindent(bw->cursor)==piscol(bw->cursor) && n > pisindent(bw->cursor)) {
1035 if (!pisbol(bw->cursor))
1037 while (joe_isspace(map,(k = pgetc(p))) && k != '\n') {
1038 binsc(bw->cursor, k);
1043 for (x=0;x<bw->o.istep;++x) {
1044 binsc(bw->cursor,bw->o.indentc);
1048 bw->cursor->xcol = piscol(bw->cursor);
1050 } else if (k == '\t' && bw->o.spaces) {
1054 n = bw->cursor->xcol;
1056 n = piscol(bw->cursor);
1058 utype_utf8_sm.state = 0;
1059 utype_utf8_sm.ptr = 0;
1061 n = bw->o.tab - n % bw->o.tab;
1063 utypebw_raw(bw, ' ', 0);
1070 if (bw->o.picture && bw->cursor->xcol!=piscol(bw->cursor))
1071 pfill(bw->cursor,bw->cursor->xcol,' '); /* Why no tabs? */
1074 if(locale_map->type && !no_decode) {
1075 int utf8_char = utf8_decode(&utype_utf8_sm,k);
1083 upd = bw->parent->t->t->updtab[bw->y + bw->cursor->line - bw->top->line];
1086 if (pisblank(bw->cursor))
1087 while (piscol(bw->cursor) < bw->o.lmargin) {
1088 binsc(bw->cursor, ' ');
1092 if (no_decode == 2) {
1093 unsigned char ch = k;
1095 binsm(bw->cursor, &ch, 1);
1096 if (!bw->b->o.charmap->type)
1100 if(locale_map->type && !bw->b->o.charmap->type) {
1101 unsigned char buf[10];
1103 k = from_utf8(bw->b->o.charmap,buf);
1104 } else if(!locale_map->type && bw->b->o.charmap->type) {
1105 unsigned char buf[10];
1106 to_utf8(locale_map,buf,k);
1107 k = utf8_decode_string(buf);
1111 binsc(bw->cursor, k);
1114 /* We need x position before we move cursor */
1115 x = piscol(bw->cursor) - bw->offset;
1118 /* Tabs are weird here... */
1119 if (bw->o.overtype && !piseol(bw->cursor) && k != '\t')
1122 /* Not sure if we're in right position for wordwrap when we're in overtype mode */
1123 if (bw->o.wordwrap && piscol(bw->cursor) > bw->o.rmargin && !joe_isblank(map,k)) {
1124 wrapword(bw->cursor, (long) bw->o.lmargin, bw->o.french, NULL);
1128 bw->cursor->xcol = piscol(bw->cursor);
1130 if (x < 0 || x >= bw->w)
1132 if (bw->cursor->line < bw->top->line || bw->cursor->line >= bw->top->line + bw->h)
1134 if (simple && bw->parent->t->t->sary[bw->y + bw->cursor->line - bw->top->line])
1146 if (simple && !curmacro) {
1148 SCRN *t = bw->parent->t->t;
1149 int y = bw->y + bw->cursor->line - bw->top->line;
1150 int *screen = t->scrn + y * t->co;
1151 int *attr = t->attr + y * t->co;
1154 if (!upd && piseol(bw->cursor) && !bw->o.highlight)
1158 markb->b == bw->b &&
1159 markk->b == bw->b &&
1160 ((!square && bw->cursor->byte >= markb->byte && bw->cursor->byte < markk->byte) ||
1161 ( square && bw->cursor->line >= markb->line && bw->cursor->line <= markk->line && piscol(bw->cursor) >= markb->xcol && piscol(bw->cursor) < markk->xcol)))
1163 outatr(bw->b->o.charmap, t, screen + x, attr + x, x, y, no_decode == 2 ? 0xFFFD : k, atr);
1170 int utypebw(BW *bw, int k)
1172 return utypebw_raw(bw, k, 0);
1177 static B *unicodehist = NULL; /* History of previously entered unicode characters */
1179 static int dounicode(BW *bw, unsigned char *s, void *object, int *notify)
1183 sscanf((char *)s,"%x",&num);
1187 if (bw->b->o.charmap->type)
1188 utypebw_raw(bw, num, 1);
1190 unsigned char buf[8];
1193 utf8_encode(buf,num);
1195 utypebw_raw(bw, buf[x], 1);
1197 bw->cursor->xcol = piscol(bw->cursor);
1204 static int doquote(BW *bw, int c, void *object, int *notify)
1206 unsigned char buf[40];
1208 if (c < 0 || c >= 256) {
1212 switch (quotestate) {
1214 if (c >= '0' && c <= '9') {
1217 joe_snprintf_1((char *)buf, sizeof(buf), "ASCII %c--", c);
1218 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
1222 } else if (c == 'u' || c == 'U') {
1223 if (bw->b->o.charmap->type)
1226 if (!wmkpw(bw->parent, US "Unicode (ISO-10646) character in hex (^C to abort): ", &unicodehist, dounicode,
1227 NULL, NULL, NULL, NULL, NULL, locale_map))
1231 } else if (c == 'r' || c == 'R') {
1232 if (!bw->b->o.charmap->type)
1236 if (!mkqwna(bw->parent, sc("ASCII 0x--"), doquote, NULL, NULL, notify))
1240 } else if (c == 'x' || c == 'X') {
1241 if (bw->b->o.charmap->type)
1245 } else if (c == 'o' || c == 'O') {
1247 if (!mkqwna(bw->parent, sc("ASCII 0---"), doquote, NULL, NULL, notify))
1253 if ((c >= 0x40 && c <= 0x5F) || (c >= 'a' && c <= 'z'))
1257 utypebw_raw(bw, c, 1);
1258 bw->cursor->xcol = piscol(bw->cursor);
1262 if (c >= '0' && c <= '9') {
1263 joe_snprintf_2((char *)buf, sizeof(buf), "ASCII %c%c-", quoteval + '0', c);
1264 quoteval = quoteval * 10 + c - '0';
1266 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
1273 if (c >= '0' && c <= '9') {
1274 quoteval = quoteval * 10 + c - '0';
1275 utypebw_raw(bw, quoteval, 1);
1276 bw->cursor->xcol = piscol(bw->cursor);
1280 if (c >= '0' && c <= '9') {
1281 joe_snprintf_1((char *)buf, sizeof(buf), "ASCII 0x%c-", c);
1284 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
1288 } else if (c >= 'a' && c <= 'f') {
1289 joe_snprintf_1((char *)buf, sizeof(buf), "ASCII 0x%c-", c + 'A' - 'a');
1290 quoteval = c - 'a' + 10;
1292 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
1296 } else if (c >= 'A' && c <= 'F') {
1297 joe_snprintf_1((char *)buf, sizeof(buf), "ASCII 0x%c-", c);
1298 quoteval = c - 'A' + 10;
1300 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
1307 if (c >= '0' && c <= '9') {
1308 quoteval = quoteval * 16 + c - '0';
1310 utypebw_raw(bw, quoteval, 2);
1311 bw->cursor->xcol = piscol(bw->cursor);
1312 } else if (c >= 'a' && c <= 'f') {
1313 quoteval = quoteval * 16 + c - 'a' + 10;
1315 } else if (c >= 'A' && c <= 'F') {
1316 quoteval = quoteval * 16 + c - 'A' + 10;
1321 if (c >= '0' && c <= '7') {
1322 joe_snprintf_1((char *)buf, sizeof(buf), "ASCII 0%c--", c);
1325 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
1332 if (c >= '0' && c <= '7') {
1333 joe_snprintf_2((char *)buf, sizeof(buf), "ASCII 0%c%c-", quoteval + '0', c);
1334 quoteval = quoteval * 8 + c - '0';
1336 if (!mkqwna(bw->parent, sz(buf), doquote, NULL, NULL, notify))
1343 if (c >= '0' && c <= '7') {
1344 quoteval = quoteval * 8 + c - '0';
1345 utypebw_raw(bw, quoteval, 1);
1346 bw->cursor->xcol = piscol(bw->cursor);
1359 if (bw->b->o.charmap->type)
1360 qs = "Ctrl- (or 0-9 for dec. r for hex, o for octal ASCII, x for hex UTF-8)";
1362 qs = "Ctrl- (or 0-9 for dec. x for hex, o for octal ASCII, u for hex UTF-8)";
1364 if (mkqwna(bw->parent, US qs, strlen(qs), doquote, NULL, NULL, NULL))
1370 static int doquote9(BW *bw, int c, void *object, int *notify)
1374 if ((c >= 0x40 && c <= 0x5F) || (c >= 'a' && c <= 'z'))
1379 utypebw_raw(bw, c, 1);
1380 bw->cursor->xcol = piscol(bw->cursor);
1384 static int doquote8(BW *bw, int c, void *object, int *notify)
1387 if (mkqwna(bw->parent, sc("Meta-Ctrl-"), doquote9, NULL, NULL, notify))
1395 utypebw_raw(bw, c, 1);
1396 bw->cursor->xcol = piscol(bw->cursor);
1402 if (mkqwna(bw->parent, sc("Meta-"), doquote8, NULL, NULL, NULL))
1408 extern const unsigned char srchstr[];
1410 static int doctrl(BW *bw, int c, void *object, int *notify)
1412 int org = bw->o.overtype;
1417 if (bw->parent->huh == srchstr && c == '\n') {
1421 utypebw_raw(bw, c, 1);
1422 bw->o.overtype = org;
1423 bw->cursor->xcol = piscol(bw->cursor);
1429 if (mkqwna(bw->parent, sc("Quote"), doctrl, NULL, NULL, NULL))
1435 /* User hit Return. Deal with autoindent.
1440 if (bw->o.overtype) {
1441 p_goto_eol(bw->cursor);
1442 if (piseof(bw->cursor))
1443 binsc(bw->cursor, '\n');
1445 bw->cursor->xcol = piscol(bw->cursor);
1447 P *p = pdup(bw->cursor);
1450 binsc(bw->cursor, '\n'), pgetc(bw->cursor);
1451 /* Suppress autoindent if we're on a space or tab... */
1452 if (bw->o.autoindent && (brch(bw->cursor)!=' ' && brch(bw->cursor)!='\t')) {
1454 while (joe_isspace(bw->b->o.charmap,(c = pgetc(p))) && c != '\n') {
1455 binsc(bw->cursor, c);
1460 bw->cursor->xcol = piscol(bw->cursor);
1469 binsc(bw->cursor,'\n');
1475 static int dosetmark(BW *bw, int c, void *object, int *notify)
1479 if (c >= '0' && c <= ':') {
1480 pdupown(bw->cursor, bw->b->marks + c - '0');
1481 poffline(bw->b->marks[c - '0']);
1483 joe_snprintf_1((char *)msgbuf, JOE_MSGBUFSIZE, "Mark %d set", c - '0');
1484 msgnw(bw->parent, msgbuf);
1493 int usetmark(BW *bw, int c)
1495 if (c >= '0' && c <= ':')
1496 return dosetmark(bw, c, NULL, NULL);
1497 else if (mkqwna(bw->parent, sc("Set mark (0-9):"), dosetmark, NULL, NULL, NULL))
1503 /* Goto book-mark */
1505 static int dogomark(BW *bw, int c, void *object, int *notify)
1509 if (c >= '0' && c <= ':')
1510 if (bw->b->marks[c - '0']) {
1511 pset(bw->cursor, bw->b->marks[c - '0']);
1512 bw->cursor->xcol = piscol(bw->cursor);
1515 joe_snprintf_1((char *)msgbuf, JOE_MSGBUFSIZE, "Mark %d not set", c - '0');
1516 msgnw(bw->parent, msgbuf);
1524 int ugomark(BW *bw, int c)
1526 if (c >= '0' && c <= '9')
1527 return dogomark(bw, c, NULL, NULL);
1528 else if (mkqwna(bw->parent, sc("Goto bookmark (0-9):"), dogomark, NULL, NULL, NULL))
1534 /* Goto next instance of character */
1538 static int dofwrdc(BW *bw, int k, void *object, int *notify)
1545 if (k < 0 || k >= 256) {
1549 q = pdup(bw->cursor);
1551 while ((c = prgetc(q)) != NO_MORE_DATA)
1555 while ((c = pgetc(q)) != NO_MORE_DATA)
1559 if (c == NO_MORE_DATA) {
1560 msgnw(bw->parent, US "Not found");
1564 pset(bw->cursor, q);
1565 bw->cursor->xcol = piscol(bw->cursor);
1571 int ufwrdc(BW *bw, int k)
1574 if (k >= 0 && k < 256)
1575 return dofwrdc(bw, k, NULL, NULL);
1576 else if (mkqw(bw->parent, sc("Fwrd to char: "), dofwrdc, NULL, NULL, NULL))
1582 int ubkwdc(BW *bw, int k)
1585 if (k >= 0 && k < 256)
1586 return dofwrdc(bw, k, NULL, NULL);
1587 else if (mkqw(bw->parent, sc("Bkwd to char: "), dofwrdc, NULL, NULL, NULL))
1593 /* Display a message */
1595 static int domsg(BASE *b, unsigned char *s, void *object, int *notify)
1599 strlcpy((char *)msgbuf, (char *)s, JOE_MSGBUFSIZE);
1601 msgnw(b->parent, *msgbuf ? msgbuf : NULL);
1607 if (wmkpw(b->parent, US "Msg (^C to abort): ", NULL, domsg, NULL, NULL, NULL, NULL, NULL, locale_map))
1615 static int dotxt(BW *bw, unsigned char *s, void *object, int *notify)
1621 for (x = 0; x != sLEN(s); ++x)
1629 if (wmkpw(bw->parent, US "Insert (^C to abort): ", NULL, dotxt, NULL, NULL, utypebw, NULL, NULL, bw->b->o.charmap))