|
|
1.1 root 1: /* vcmd.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 14407 SW Teal Blvd. #C
6: * Beaverton, OR 97005
7: * [email protected]
8: */
9:
10:
11: /* This file contains the functions that handle VI commands */
12:
13:
14: #include "config.h"
15: #include "ctype.h"
16: #include "vi.h"
17: #if MSDOS
18: # include <process.h>
19: # include <string.h>
20: #endif
21: #if TOS
22: # include <osbind.h>
23: # include <string.h>
24: #endif
25: #if OSK
26: # include <stdio.h>
27: #endif
28:
29:
30: /* This function puts the editor in EX mode */
31: MARK v_quit()
32: {
33: move(LINES - 1, 0);
34: mode = MODE_EX;
35: return cursor;
36: }
37:
38: /* This function causes the screen to be redrawn */
39: MARK v_redraw()
40: {
41: redraw(MARK_UNSET, FALSE);
42: return cursor;
43: }
44:
45: /* This function executes a string of EX commands, and waits for a user keystroke
46: * before returning to the VI screen. If that keystroke is another ':', then
47: * another EX command is read and executed.
48: */
49: /*ARGSUSED*/
50: MARK v_1ex(m, text)
51: MARK m; /* the current line */
52: char *text; /* the first command to execute */
53: {
54: /* run the command. be careful about modes & output */
55: exwrote = (mode == MODE_COLON);
56: doexcmd(text);
57: exrefresh();
58:
59: /* if mode is no longer MODE_VI, then we should quit right away! */
60: if (mode != MODE_VI && mode != MODE_COLON)
61: return cursor;
62:
63: /* The command did some output. Wait for a keystoke. */
64: if (exwrote)
65: {
66: mode = MODE_VI;
67: msg("[Hit <RETURN> to continue]");
68: if (getkey(0) == ':')
69: { mode = MODE_COLON;
70: addch('\n');
71: }
72: else
73: redraw(MARK_UNSET, FALSE);
74: }
75:
76: return cursor;
77: }
78:
79: /* This function undoes the last change */
80: /*ARGSUSED*/
81: MARK v_undo(m)
82: MARK m; /* (ignored) */
83: {
84: if (undo())
85: {
86: redraw(MARK_UNSET, FALSE);
87: }
88: return cursor;
89: }
90:
91: /* This function deletes the character(s) that the cursor is on */
92: MARK v_xchar(m, cnt, cmd)
93: MARK m; /* where to start deletions */
94: long cnt; /* number of chars to delete */
95: int cmd; /* either 'x' or 'X' */
96: {
97: DEFAULT(1);
98:
99: /* for 'X', adjust so chars are deleted *BEFORE* cursor */
100: if (cmd == 'X')
101: {
102: if (markidx(m) < cnt)
103: return MARK_UNSET;
104: m -= cnt;
105: }
106:
107: /* make sure we don't try to delete more thars than there are */
108: pfetch(markline(m));
109: if (markidx(m + cnt) > plen)
110: {
111: cnt = plen - markidx(m);
112: }
113: if (cnt == 0L)
114: {
115: return MARK_UNSET;
116: }
117:
118: /* do it */
119: ChangeText
120: {
121: cut(m, m + cnt);
122: delete(m, m + cnt);
123: }
124: return m;
125: }
126:
127: /* This function defines a mark */
128: /*ARGSUSED*/
129: MARK v_mark(m, count, key)
130: MARK m; /* where the mark will be */
131: long count; /* (ignored) */
132: int key; /* the ASCII label of the mark */
133: {
134: if (key < 'a' || key > 'z')
135: {
136: msg("Marks must be from a to z");
137: }
138: else
139: {
140: mark[key - 'a'] = m;
141: }
142: return m;
143: }
144:
145: /* This function toggles upper & lower case letters */
146: MARK v_ulcase(m, cnt)
147: MARK m; /* where to make the change */
148: long cnt; /* number of chars to flip */
149: {
150: REG char *pos;
151: REG int j;
152:
153: DEFAULT(1);
154:
155: /* fetch the current version of the line */
156: pfetch(markline(m));
157:
158: /* for each position in the line */
159: for (j = 0, pos = &ptext[markidx(m)]; j < cnt && *pos; j++, pos++)
160: {
161: if (isupper(*pos))
162: {
163: tmpblk.c[j] = tolower(*pos);
164: }
165: else
166: {
167: tmpblk.c[j] = toupper(*pos);
168: }
169: }
170:
171: /* if the new text is different from the old, then change it */
172: if (strncmp(tmpblk.c, &ptext[markidx(m)], j))
173: {
174: ChangeText
175: {
176: tmpblk.c[j] = '\0';
177: change(m, m + j, tmpblk.c);
178: }
179: }
180:
181: return m + j;
182: }
183:
184:
185: MARK v_replace(m, cnt, key)
186: MARK m; /* first char to be replaced */
187: long cnt; /* number of chars to replace */
188: int key; /* what to replace them with */
189: {
190: REG char *text;
191: REG int i;
192:
193: DEFAULT(1);
194:
195: /* map ^M to '\n' */
196: if (key == '\r')
197: {
198: key = '\n';
199: }
200:
201: /* make sure the resulting line isn't too long */
202: if (cnt > BLKSIZE - 2 - markidx(m))
203: {
204: cnt = BLKSIZE - 2 - markidx(m);
205: }
206:
207: /* build a string of the desired character with the desired length */
208: for (text = tmpblk.c, i = cnt; i > 0; i--)
209: {
210: *text++ = key;
211: }
212: *text = '\0';
213:
214: /* make sure cnt doesn't extend past EOL */
215: pfetch(markline(m));
216: key = markidx(m);
217: if (key + cnt > plen)
218: {
219: cnt = plen - key;
220: }
221:
222: /* do the replacement */
223: ChangeText
224: {
225: change(m, m + cnt, tmpblk.c);
226: }
227:
228: if (*tmpblk.c == '\n')
229: {
230: return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
231: }
232: else
233: {
234: return m + cnt - 1;
235: }
236: }
237:
238: MARK v_overtype(m)
239: MARK m; /* where to start overtyping */
240: {
241: MARK end; /* end of a substitution */
242: static long width; /* width of a single-line replace */
243:
244: /* the "doingdot" version of replace is really a substitution */
245: if (doingdot)
246: {
247: /* was the last one really repeatable? */
248: if (width < 0)
249: {
250: msg("Can't repeat a multi-line overtype command");
251: return MARK_UNSET;
252: }
253:
254: /* replacing nothing by nothing? Don't bother */
255: if (width == 0)
256: {
257: return m;
258: }
259:
260: /* replace some chars by repeated text */
261: return v_subst(m, width);
262: }
263:
264: /* Normally, we input starting here, in replace mode */
265: ChangeText
266: {
267: end = input(m, m, WHEN_VIREP, 0);
268: }
269:
270: /* if we ended on the same line we started on, then this
271: * overtype is repeatable via the dot key.
272: */
273: if (markline(end) == markline(m) && end >= m - 1L)
274: {
275: width = end - m + 1L;
276: }
277: else /* it isn't repeatable */
278: {
279: width = -1L;
280: }
281:
282: return end;
283: }
284:
285:
286: /* This function selects which cut buffer to use */
287: /*ARGSUSED*/
288: MARK v_selcut(m, cnt, key)
289: MARK m;
290: long cnt;
291: int key;
292: {
293: cutname(key);
294: return m;
295: }
296:
297: /* This function pastes text from a cut buffer */
298: /*ARGSUSED*/
299: MARK v_paste(m, cnt, cmd)
300: MARK m; /* where to paste the text */
301: long cnt; /* (ignored) */
302: int cmd; /* either 'p' or 'P' */
303: {
304: MARK dest;
305:
306: ChangeText
307: {
308: /* paste the text, and find out where it ends */
309: dest = paste(m, cmd == 'p', TRUE);
310:
311: /* was that a line-mode paste? */
312: if (dest && markline(dest) != markline(m))
313: {
314: /* line-mode pastes leave the cursor at the front
315: * of the first pasted line.
316: */
317: dest = m;
318: if (cmd == 'p')
319: {
320: dest += BLKSIZE;
321: }
322: force_flags |= FRNT;
323: }
324: }
325: return dest;
326: }
327:
328: /* This function yanks text into a cut buffer */
329: MARK v_yank(m, n)
330: MARK m, n; /* range of text to yank */
331: {
332: cut(m, n);
333: return m;
334: }
335:
336: /* This function deletes a range of text */
337: MARK v_delete(m, n)
338: MARK m, n; /* range of text to delete */
339: {
340: /* illegal to try and delete nothing */
341: if (n <= m)
342: {
343: return MARK_UNSET;
344: }
345:
346: /* Do it */
347: ChangeText
348: {
349: cut(m, n);
350: delete(m, n);
351: }
352: return m;
353: }
354:
355:
356: /* This starts input mode without deleting anything */
357: MARK v_insert(m, cnt, key)
358: MARK m; /* where to start (sort of) */
359: long cnt; /* repeat how many times? */
360: int key; /* what command is this for? {a,A,i,I,o,O} */
361: {
362: int wasdot;
363: long reps;
364: int delta = 0;/* 1 to take autoindent from line below, -1 for above */
365:
366: DEFAULT(1);
367:
368: ChangeText
369: {
370: /* tweak the insertion point, based on command key */
371: switch (key)
372: {
373: case 'i':
374: break;
375:
376: case 'a':
377: pfetch(markline(m));
378: if (plen > 0)
379: {
380: m++;
381: }
382: break;
383:
384: case 'I':
385: m = m_front(m, 1L);
386: break;
387:
388: case 'A':
389: pfetch(markline(m));
390: m = (m & ~(BLKSIZE - 1)) + plen;
391: break;
392:
393: case 'O':
394: m &= ~(BLKSIZE - 1);
395: add(m, "\n");
396: delta = 1;
397: break;
398:
399: case 'o':
400: m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
401: add(m, "\n");
402: delta = -1;
403: break;
404: }
405:
406: /* insert the same text once or more */
407: for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
408: {
409: m = input(m, m, WHEN_VIINP, delta) + 1;
410: }
411: if (markidx(m) > 0)
412: {
413: m--;
414: }
415:
416: doingdot = wasdot;
417: }
418:
419: #ifndef CRUNCH
420: # ifndef NO_EXTENSIONS
421: if (key == 'i' && *o_inputmode && mode == MODE_VI)
422: {
423: msg("Now in command mode! To return to input mode, hit <i>");
424: }
425: # endif
426: #endif
427:
428: return m;
429: }
430:
431: /* This starts input mode with some text deleted */
432: MARK v_change(m, n)
433: MARK m, n; /* the range of text to change */
434: {
435: int lnmode; /* is this a line-mode change? */
436:
437: /* swap them if they're in reverse order */
438: if (m > n)
439: {
440: MARK tmp;
441: tmp = m;
442: m = n;
443: n = tmp;
444: }
445:
446: /* for line mode, retain the last newline char */
447: lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
448: if (lnmode)
449: {
450: n -= BLKSIZE;
451: pfetch(markline(n));
452: n = (n & ~(BLKSIZE - 1)) + plen;
453: }
454:
455: ChangeText
456: {
457: cut(m, n);
458: m = input(m, n, WHEN_VIINP, 0);
459: }
460:
461: return m;
462: }
463:
464: /* This function replaces a given number of characters with input */
465: MARK v_subst(m, cnt)
466: MARK m; /* where substitutions start */
467: long cnt; /* number of chars to replace */
468: {
469: DEFAULT(1);
470:
471: /* make sure we don't try replacing past EOL */
472: pfetch(markline(m));
473: if (markidx(m) + cnt > plen)
474: {
475: cnt = plen - markidx(m);
476: }
477:
478: /* Go for it! */
479: ChangeText
480: {
481: cut(m, m + cnt);
482: m = input(m, m + cnt, WHEN_VIINP, 0);
483: }
484: return m;
485: }
486:
487: /* This calls the ex "join" command to join some lines together */
488: MARK v_join(m, cnt)
489: MARK m; /* the first line to be joined */
490: long cnt; /* number of other lines to join */
491: {
492: MARK joint; /* where the lines were joined */
493:
494: DEFAULT(1);
495:
496: /* figure out where the joint will be */
497: pfetch(markline(m));
498: joint = (m & ~(BLKSIZE - 1)) + plen;
499:
500: /* join the lines */
501: cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
502:
503: /* the cursor should be left at the joint */
504: return joint;
505: }
506:
507:
508: /* This calls the ex "<" command to shift some lines left */
509: MARK v_lshift(m, n)
510: MARK m, n; /* range of lines to shift */
511: {
512: /* adjust for inclusive endmarks in ex */
513: n -= BLKSIZE;
514:
515: cmd_shift(m, n, CMD_SHIFTL, FALSE, (char *)0);
516:
517: return m;
518: }
519:
520: /* This calls the ex ">" command to shift some lines right */
521: MARK v_rshift(m, n)
522: MARK m, n; /* range of lines to shift */
523: {
524: /* adjust for inclusive endmarks in ex */
525: n -= BLKSIZE;
526:
527: cmd_shift(m, n, CMD_SHIFTR, FALSE, (char *)0);
528:
529: return m;
530: }
531:
532: /* This filters some lines through a preset program, to reformat them */
533: MARK v_reformat(m, n)
534: MARK m, n; /* range of lines to shift */
535: {
536: /* adjust for inclusive endmarks in ex */
537: n -= BLKSIZE;
538:
539: /* run the filter command */
540: filter(m, n, o_equalprg, TRUE);
541:
542: redraw(MARK_UNSET, FALSE);
543: return m;
544: }
545:
546:
547: /* This runs some lines through a filter program */
548: MARK v_filter(m, n)
549: MARK m, n; /* range of lines to shift */
550: {
551: char cmdln[150]; /* a shell command line */
552:
553: /* adjust for inclusive endmarks in ex */
554: n -= BLKSIZE;
555:
556: if (vgets('!', cmdln, sizeof(cmdln)) > 0)
557: {
558: filter(m, n, cmdln, TRUE);
559: }
560:
561: redraw(MARK_UNSET, FALSE);
562: return m;
563: }
564:
565:
566: /* This function runs the ex "file" command to show the file's status */
567: MARK v_status()
568: {
569: cmd_file(cursor, cursor, CMD_FILE, 0, "");
570: return cursor;
571: }
572:
573:
574: /* This function runs the ":&" command to repeat the previous :s// */
575: MARK v_again(m, n)
576: MARK m, n;
577: {
578: cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, "");
579: return cursor;
580: }
581:
582:
583:
584: /* This function switches to the previous file, if possible */
585: MARK v_switch()
586: {
587: if (!*prevorig)
588: msg("No previous file");
589: else
590: { strcpy(tmpblk.c, prevorig);
591: cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
592: }
593: return cursor;
594: }
595:
596: /* This function does a tag search on a keyword */
597: /*ARGSUSED*/
598: MARK v_tag(keyword, m, cnt)
599: char *keyword;
600: MARK m;
601: long cnt;
602: {
603: /* move the cursor to the start of the tag name, where m is */
604: cursor = m;
605:
606: /* perform the tag search */
607: cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
608:
609: return cursor;
610: }
611:
612: #ifndef NO_EXTENSIONS
613: /* This function looks up a keyword by calling the helpprog program */
614: /*ARGSUSED*/
615: MARK v_keyword(keyword, m, cnt)
616: char *keyword;
617: MARK m;
618: long cnt;
619: {
620: int waswarn;
621: char cmdline[130];
622:
623: move(LINES - 1, 0);
624: addstr("---------------------------------------------------------\n");
625: clrtoeol();
626: refresh();
627: sprintf(cmdline, "%s %s", o_keywordprg, keyword);
628: waswarn = *o_warn;
629: *o_warn = FALSE;
630: suspend_curses();
631: if (system(cmdline))
632: {
633: addstr("<<< failed >>>\n");
634: }
635: resume_curses(FALSE);
636: mode = MODE_VI;
637: redraw(MARK_UNSET, FALSE);
638: *o_warn = waswarn;
639:
640: return m;
641: }
642:
643:
644:
645: MARK v_increment(keyword, m, cnt)
646: char *keyword;
647: MARK m;
648: long cnt;
649: {
650: static sign;
651: char newval[12];
652: long atol();
653:
654: DEFAULT(1);
655:
656: /* get one more keystroke, unless doingdot */
657: if (!doingdot)
658: {
659: sign = getkey(0);
660: }
661:
662: /* adjust the number, based on that second keystroke */
663: switch (sign)
664: {
665: case '+':
666: case '#':
667: cnt = atol(keyword) + cnt;
668: break;
669:
670: case '-':
671: cnt = atol(keyword) - cnt;
672: break;
673:
674: case '=':
675: break;
676:
677: default:
678: return MARK_UNSET;
679: }
680: sprintf(newval, "%ld", cnt);
681:
682: ChangeText
683: {
684: change(m, m + strlen(keyword), newval);
685: }
686:
687: return m;
688: }
689: #endif
690:
691:
692: /* This function acts like the EX command "xit" */
693: /*ARGSUSED*/
694: MARK v_xit(m, cnt, key)
695: MARK m; /* ignored */
696: long cnt; /* ignored */
697: int key; /* must be a second 'Z' */
698: {
699: /* if second char wasn't 'Z', fail */
700: if (key != 'Z')
701: {
702: return MARK_UNSET;
703: }
704:
705: /* move the cursor to the bottom of the screen */
706: move(LINES - 1, 0);
707: clrtoeol();
708:
709: /* do the xit command */
710: cmd_xit(m, m, CMD_XIT, FALSE, "");
711:
712: /* return the cursor */
713: return m;
714: }
715:
716:
717: /* This function undoes changes to a single line, if possible */
718: MARK v_undoline(m)
719: MARK m; /* where we hope to undo the change */
720: {
721: /* make sure we have the right line in the buffer */
722: if (markline(m) != U_line)
723: {
724: return MARK_UNSET;
725: }
726:
727: /* fix it */
728: ChangeText
729: {
730: strcat(U_text, "\n");
731: change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text);
732: }
733:
734: /* nothing in the buffer anymore */
735: U_line = -1L;
736:
737: /* return, with the cursor at the front of the line */
738: return m & ~(BLKSIZE - 1);
739: }
740:
741:
742: #ifndef NO_ERRLIST
743: MARK v_errlist(m)
744: MARK m;
745: {
746: cmd_errlist(m, m, CMD_ERRLIST, FALSE, "");
747: return cursor;
748: }
749: #endif
750:
751:
752: #ifndef NO_AT
753: /*ARGSUSED*/
754: MARK v_at(m, cnt, key)
755: MARK m;
756: long cnt;
757: int key;
758: {
759: int size;
760:
761: size = cb2str(key, tmpblk.c, BLKSIZE);
762: if (size <= 0 || size == BLKSIZE)
763: {
764: return MARK_UNSET;
765: }
766:
767: execmap(0, tmpblk.c, FALSE);
768: return cursor;
769: }
770: #endif
771:
772:
773: #ifdef SIGTSTP
774: MARK v_suspend()
775: {
776: cmd_suspend(MARK_UNSET, MARK_UNSET, CMD_SUSPEND, FALSE, "");
777: return MARK_UNSET;
778: }
779: #endif
780:
781:
782: #ifndef NO_VISIBLE
783: /*ARGSUSED*/
784: MARK v_start(m, cnt, cmd)
785: MARK m; /* starting point for a v or V command */
786: long cnt; /* ignored */
787: int cmd; /* either 'v' or 'V' */
788: {
789: if (V_from)
790: {
791: V_from = MARK_UNSET;
792: }
793: else
794: {
795: V_from = m;
796: V_linemd = isupper(cmd);
797: }
798: return m;
799: }
800: #endif
801:
802: #ifndef NO_POPUP
803: # define MENU_HEIGHT 11
804: # define MENU_WIDTH 23
805: MARK v_popup(m, n)
806: MARK m, n; /* the range of text to change */
807: {
808: int i;
809: int y, x; /* position where the window will pop up at */
810: int key; /* keystroke from the user */
811: int sel; /* index of the selected operation */
812: static int dfltsel;/* default value of sel */
813: static char *labels[11] =
814: {
815: "ESC cancel! ",
816: " d delete (cut) ",
817: " y yank (copy) ",
818: " p paste after ",
819: " P paste before ",
820: " > more indented ",
821: " < less indented ",
822: " = reformat ",
823: " ! external filter ",
824: " ZZ save & exit ",
825: " u undo previous "
826: };
827:
828: /* try to position the menu near the cursor */
829: x = physcol - (MENU_WIDTH / 2);
830: if (x < 0)
831: x = 0;
832: else if (x + MENU_WIDTH + 2 > COLS)
833: x = COLS - MENU_WIDTH - 2;
834: if (markline(cursor) < topline || markline(cursor) > botline)
835: y = 0;
836: else if (markline(cursor) + 1L + MENU_HEIGHT > botline)
837: y = (int)(markline(cursor) - topline) - MENU_HEIGHT;
838: else
839: y = (int)(markline(cursor) - topline) + 1L;
840:
841: /* draw the menu */
842: for (sel = 0; sel < MENU_HEIGHT; sel++)
843: {
844: move(y + sel, x);
845: do_POPUP();
846: if (sel == dfltsel)
847: qaddstr("-->");
848: else
849: qaddstr(" ");
850: qaddstr(labels[sel]);
851: do_SE();
852: }
853:
854: /* get a selection */
855: move(y + dfltsel, x + 4);
856: for (sel = dfltsel; (key = getkey(WHEN_POPUP)) != '\\' && key != '\r'; )
857: {
858: /* erase the selection arrow */
859: move(y + sel, x);
860: do_POPUP();
861: qaddstr(" ");
862: qaddstr(labels[sel]);
863: do_SE();
864:
865: /* process the user's keystroke */
866: if (key == 'j' && sel < MENU_HEIGHT - 1)
867: {
868: sel++;
869: }
870: else if (key == 'k' && sel > 0)
871: {
872: sel--;
873: }
874: else if (key == '\033')
875: {
876: sel = 0;
877: break;
878: }
879: else
880: {
881: for (i = 1; i < MENU_HEIGHT && labels[i][1] != key; i++)
882: {
883: }
884: if (i < MENU_HEIGHT)
885: {
886: sel = i;
887: break;
888: }
889: }
890:
891: /* redraw the arrow, possibly in a new place */
892: move(y + sel, x);
893: do_POPUP();
894: qaddstr("-->");
895: qaddstr(labels[sel]);
896: do_SE();
897: move(y + sel, x + 4);
898: }
899:
900: /* in most cases, the default selection is "paste after" */
901: dfltsel = 3;
902:
903: /* perform the appropriate action */
904: switch (sel)
905: {
906: case 0:
907: m = cursor;
908: dfltsel = 0;
909: break;
910:
911: case 1: /* delete (cut) */
912: m = v_delete(m, n);
913: break;
914:
915: case 2: /* yank (copy) */
916: m = v_yank(m, n);
917: break;
918:
919: case 3: /* paste after */
920: m = v_paste(n, 1L, 'P');
921: break;
922:
923: case 4: /* paste before */
924: m = v_paste(m, 1L, 'P');
925: dfltsel = 4;
926: break;
927:
928: case 5: /* more indented */
929: m = v_rshift(m, n);
930: dfltsel = 5;
931: break;
932:
933: case 6: /* less indented */
934: m = v_lshift(m, n);
935: dfltsel = 6;
936: break;
937:
938: case 7: /* reformat */
939: m = v_reformat(m, n);
940: dfltsel = 7;
941: break;
942:
943: case 8: /* external filter */
944: m = v_filter(m, n);
945: dfltsel = 0;
946: break;
947:
948: case 9: /* save & exit */
949: /* get confirmation first */
950: do
951: {
952: key = getkey(0);
953: } while (key != '\\' && key != 'Z' && key != '\r' /* good */
954: && key != '\033'); /* bad */
955: if (key != '\033')
956: {
957: m = v_xit(m, 0L, 'Z');
958: }
959: break;
960:
961: case 10: /* undo previous */
962: m = v_undo(m);
963: dfltsel = 9;
964: break;
965: }
966:
967: /* arrange for the menu to be erased (except "save & exit" doesn't care)
968: */
969: if (sel != 9)
970: redraw(MARK_UNSET, FALSE);
971:
972: return m;
973: }
974: #endif /* undef NO_POPUP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.