00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "config.h"
00016 #include "ctype.h"
00017 #include "vi.h"
00018 #include "regexp.h"
00019
00020 #ifdef DEBUG
00021
00022
00023 void cmd_debug(frommark, tomark, cmd, bang, extra)
00024 MARK frommark;
00025 MARK tomark;
00026 CMD cmd;
00027 int bang;
00028 char *extra;
00029 {
00030 REG char *scan;
00031 REG long l;
00032 REG int i;
00033 int len;
00034
00035
00036 l = markline(frommark);
00037 for (i = 1; l > lnum[i]; i++)
00038 {
00039 }
00040
00041 do
00042 {
00043
00044 scan = blkget(i)->c;
00045
00046
00047 if (scan[BLKSIZE - 1])
00048 {
00049 len = BLKSIZE;
00050 }
00051 else
00052 {
00053 len = strlen(scan);
00054 }
00055
00056
00057 msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
00058 i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
00059 msg("##### len=%d, buf=0x%lx, %sdirty",
00060 len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
00061 if (bang)
00062 {
00063 while (--len >= 0)
00064 {
00065 addch(*scan);
00066 scan++;
00067 }
00068 }
00069 exrefresh();
00070
00071
00072 i++;
00073 } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
00074 }
00075
00076
00077
00078
00079 void cmd_validate(frommark, tomark, cmd, bang, extra)
00080 MARK frommark;
00081 MARK tomark;
00082 CMD cmd;
00083 int bang;
00084 char *extra;
00085 {
00086 char *scan;
00087 int i;
00088 int nlcnt;
00089 int len;
00090
00091
00092 if (lnum[0] != 0L)
00093 {
00094 msg("lnum[0] = %ld", lnum[0]);
00095 }
00096
00097
00098 for (i = 1; lnum[i] <= nlines; i++)
00099 {
00100 scan = blkget(i)->c;
00101 if (scan[BLKSIZE - 1])
00102 {
00103 msg("block %d has no NUL at the end", i);
00104 }
00105 else
00106 {
00107 for (nlcnt = len = 0; *scan; scan++, len++)
00108 {
00109 if (*scan == '\n')
00110 {
00111 nlcnt++;
00112 }
00113 }
00114 if (scan[-1] != '\n')
00115 {
00116 msg("block %d doesn't end with '\\n' (length %d)", i, len);
00117 }
00118 if (bang || nlcnt != lnum[i] - lnum[i - 1])
00119 {
00120 msg("block %d (line %ld?) has %d lines, but should have %ld",
00121 i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
00122 }
00123 }
00124 exrefresh();
00125 }
00126
00127
00128 if (lnum[i] != INFINITY)
00129 {
00130 msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
00131 i, hdr.n[i], i, lnum[i]);
00132 }
00133
00134 msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
00135 msg("V_from=%ld.%d, cursor=%ld.%d", markline(V_from), markidx(V_from), markline(cursor), markidx(cursor));
00136 }
00137 #endif
00138
00139
00140
00141 void cmd_mark(frommark, tomark, cmd, bang, extra)
00142 MARK frommark;
00143 MARK tomark;
00144 CMD cmd;
00145 int bang;
00146 char *extra;
00147 {
00148
00149 if (*extra == '"')
00150 {
00151 extra++;
00152 }
00153
00154 if (!isascii(*extra) || !islower(*extra) || extra[1])
00155 {
00156 msg("Invalid mark name");
00157 return;
00158 }
00159
00160 mark[*extra - 'a'] = tomark;
00161 }
00162
00163
00164 void cmd_write(frommark, tomark, cmd, bang, extra)
00165 MARK frommark;
00166 MARK tomark;
00167 CMD cmd;
00168 int bang;
00169 char *extra;
00170 {
00171 int fd;
00172 int append;
00173 REG long l;
00174 REG char *scan;
00175 REG int i;
00176
00177
00178 if (*extra == '!')
00179 {
00180 filter(frommark, tomark, extra + 1, FALSE);
00181 return;
00182 }
00183
00184
00185 if (frommark == MARK_FIRST && tomark == MARK_LAST && cmd == CMD_WRITE)
00186 {
00187 tmpsave(extra, bang);
00188 return;
00189 }
00190
00191
00192 append = FALSE;
00193 if (extra[0] == '>' && extra[1] == '>')
00194 {
00195 extra += 2;
00196 append = TRUE;
00197 }
00198
00199
00200 if (access(extra, 0) == 0 && !bang && !append)
00201 {
00202 msg("File already exists - Use :w! to overwrite");
00203 return;
00204 }
00205
00206
00207 if (append)
00208 {
00209 #ifdef O_APPEND
00210 fd = open(extra, O_WRONLY|O_APPEND);
00211 #else
00212 fd = open(extra, O_WRONLY);
00213 if (fd >= 0)
00214 {
00215 lseek(fd, 0L, 2);
00216 }
00217 #endif
00218 }
00219 else
00220 {
00221 fd = -1;
00222 }
00223
00224 if (fd < 0)
00225 {
00226 fd = creat(extra, FILEPERMS);
00227 if (fd < 0)
00228 {
00229 msg("Can't write to \"%s\"", extra);
00230 return;
00231 }
00232 }
00233 for (l = markline(frommark); l <= markline(tomark); l++)
00234 {
00235
00236 scan = fetchline(l);
00237 i = strlen(scan);
00238 scan[i++] = '\n';
00239
00240
00241 if (twrite(fd, scan, i) < i)
00242 {
00243 msg("Write failed");
00244 break;
00245 }
00246 }
00247 rptlines = markline(tomark) - markline(frommark) + 1;
00248 rptlabel = "written";
00249 close(fd);
00250 }
00251
00252
00253
00254 void cmd_shell(frommark, tomark, cmd, bang, extra)
00255 MARK frommark, tomark;
00256 CMD cmd;
00257 int bang;
00258 char *extra;
00259 {
00260 static char prevextra[80];
00261
00262
00263 if (cmd == CMD_SHELL)
00264 {
00265 extra = o_shell;
00266 frommark = tomark = 0L;
00267 }
00268
00269
00270 if (*extra == '!')
00271 {
00272 if (!*prevextra)
00273 {
00274 msg("No previous shell command to substitute for '!'");
00275 return;
00276 }
00277 extra = prevextra;
00278 }
00279 else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1)
00280 {
00281 strcpy(prevextra, extra);
00282 }
00283
00284
00285 if (*o_warn && tstflag(file, MODIFIED))
00286 {
00287 if (mode == MODE_VI)
00288 {
00289 mode = MODE_COLON;
00290 }
00291 msg("Warning: \"%s\" has been modified but not yet saved", origname);
00292 }
00293
00294
00295 suspend_curses();
00296 if (frommark == 0L)
00297 {
00298 system(extra);
00299 }
00300 else
00301 {
00302 filter(frommark, tomark, extra, TRUE);
00303 }
00304
00305
00306 resume_curses(mode == MODE_EX);
00307 }
00308
00309
00310
00311 void cmd_global(frommark, tomark, cmd, bang, extra)
00312 MARK frommark, tomark;
00313 CMD cmd;
00314 int bang;
00315 char *extra;
00316 {
00317 char *cmdptr;
00318 char cmdln[100];
00319 char *line;
00320 long l;
00321 long lqty;
00322 long nchanged;
00323 regexp *re;
00324
00325
00326 if (doingglobal)
00327 {
00328 msg("Can't nest global commands.");
00329 rptlines = -1L;
00330 return;
00331 }
00332
00333
00334 if (bang)
00335 {
00336 cmd = CMD_VGLOBAL;
00337 }
00338
00339
00340 if (*extra != '/' && *extra != '?')
00341 {
00342 msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
00343 return;
00344 }
00345
00346
00347 cmdptr = parseptrn(extra);
00348 if (!extra[1])
00349 {
00350 msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
00351 return;
00352 }
00353 re = regcomp(extra + 1);
00354 if (!re)
00355 {
00356
00357 return;
00358 }
00359
00360
00361 doingglobal = TRUE;
00362 ChangeText
00363 {
00364
00365
00366
00367
00368
00369
00370 for (l = nlines - markline(frommark),
00371 lqty = markline(tomark) - markline(frommark) + 1L,
00372 nchanged = 0L;
00373 lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
00374 l--, lqty--)
00375 {
00376
00377 line = fetchline(nlines - l);
00378
00379
00380 if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
00381 {
00382
00383 cursor = MARK_AT_LINE(nlines - l);
00384
00385
00386
00387
00388 strcpy(cmdln, cmdptr);
00389 rptlines = 0L;
00390 doexcmd(cmdln);
00391 nchanged += rptlines;
00392 }
00393 }
00394 }
00395 doingglobal = FALSE;
00396
00397
00398 free(re);
00399
00400
00401 rptlines = nchanged;
00402 }
00403
00404
00405
00406 void cmd_file(frommark, tomark, cmd, bang, extra)
00407 MARK frommark, tomark;
00408 CMD cmd;
00409 int bang;
00410 char *extra;
00411 {
00412 #ifndef CRUNCH
00413
00414 if (extra && *extra)
00415 {
00416 strcpy(origname, extra);
00417 storename(origname);
00418 setflag(file, NOTEDITED);
00419 }
00420 #endif
00421 if (cmd == CMD_FILE)
00422 {
00423 #ifndef CRUNCH
00424 msg("\"%s\" %s%s%s %ld lines, line %ld [%ld%%]",
00425 #else
00426 msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]",
00427 #endif
00428 *origname ? origname : "[NO FILE]",
00429 tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
00430 #ifndef CRUNCH
00431 tstflag(file, NOTEDITED) ?"[NOT EDITED]":"",
00432 #endif
00433 tstflag(file, READONLY) ? "[READONLY]" : "",
00434 nlines,
00435 markline(frommark),
00436 markline(frommark) * 100 / nlines);
00437 }
00438 #ifndef CRUNCH
00439 else if (markline(frommark) != markline(tomark))
00440 {
00441 msg("range \"%ld,%ld\" contains %ld lines",
00442 markline(frommark),
00443 markline(tomark),
00444 markline(tomark) - markline(frommark) + 1L);
00445 }
00446 #endif
00447 else
00448 {
00449 msg("%ld", markline(frommark));
00450 }
00451 }
00452
00453
00454
00455 void cmd_edit(frommark, tomark, cmd, bang, extra)
00456 MARK frommark, tomark;
00457 CMD cmd;
00458 int bang;
00459 char *extra;
00460 {
00461 long line = 1L;
00462 #ifndef CRUNCH
00463 char *init = (char *)0;
00464 #endif
00465
00466
00467
00468
00469
00470 if (cmd == CMD_VISUAL)
00471 {
00472 mode = MODE_VI;
00473 msg("");
00474 if (!*extra)
00475 {
00476 return;
00477 }
00478 }
00479
00480
00481 if (!strcmp(extra, prevorig))
00482 {
00483 line = prevline;
00484 }
00485
00486 #ifndef CRUNCH
00487
00488 if (*extra == '+')
00489 {
00490 for (init = ++extra; !isspace(*extra); extra++)
00491 {
00492 }
00493 while (isspace(*extra))
00494 {
00495 *extra++ = '\0';
00496 }
00497 if (!*init)
00498 {
00499 init = "$";
00500 }
00501 if (!extra)
00502 {
00503 extra = origname;
00504 }
00505 }
00506 #endif
00507
00508
00509 if (tmpabort(bang))
00510 {
00511 tmpstart(extra);
00512 if (line <= nlines && line >= 1L)
00513 {
00514 cursor = MARK_AT_LINE(line);
00515 }
00516 #ifndef CRUNCH
00517 if (init)
00518 {
00519 doexcmd(init);
00520 }
00521 #endif
00522 }
00523 else
00524 {
00525 msg("Use edit! to abort changes, or w to save changes");
00526
00527
00528 strcpy(prevorig, extra);
00529 prevline = 1L;
00530 }
00531 }
00532
00533
00534
00535
00536 void cmd_next(frommark, tomark, cmd, bang, extra)
00537 MARK frommark, tomark;
00538 CMD cmd;
00539 int bang;
00540 char *extra;
00541 {
00542 int i, j;
00543 char *scan;
00544
00545
00546 if (cmd == CMD_NEXT && extra && *extra)
00547 {
00548 cmd_args(frommark, tomark, cmd, bang, extra);
00549 }
00550
00551
00552 if (cmd == CMD_NEXT)
00553 {
00554 i = argno + 1;
00555 }
00556 else if (cmd == CMD_PREVIOUS)
00557 {
00558 i = argno - 1;
00559 }
00560 else
00561 {
00562 i = 0;
00563 }
00564 if (i < 0 || i >= nargs)
00565 {
00566 msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more ");
00567 return;
00568 }
00569
00570
00571 for (j = i, scan = args; j > 0; j--)
00572 {
00573 while(*scan++)
00574 {
00575 }
00576 }
00577
00578
00579 if (tmpabort(bang))
00580 {
00581 tmpstart(scan);
00582 argno = i;
00583 }
00584 else
00585 {
00586 msg("Use :%s! to abort changes, or w to save changes",
00587 cmd == CMD_NEXT ? "next" :
00588 cmd == CMD_PREVIOUS ? "previous" :
00589 "rewind");
00590 }
00591 }
00592
00593
00594
00595
00596 void cmd_xit(frommark, tomark, cmd, bang, extra)
00597 MARK frommark, tomark;
00598 CMD cmd;
00599 int bang;
00600 char *extra;
00601 {
00602 static long whenwarned;
00603 int oldflag;
00604
00605
00606 if (argno >= 0 && argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT))
00607 {
00608 msg("More files to edit -- Use \":n\" to go to next file");
00609 whenwarned = changes;
00610 return;
00611 }
00612
00613 if (cmd == CMD_QUIT)
00614 {
00615 oldflag = *o_autowrite;
00616 *o_autowrite = FALSE;
00617 if (tmpabort(bang))
00618 {
00619 mode = MODE_QUIT;
00620 }
00621 else
00622 {
00623 msg("Use q! to abort changes, or wq to save changes");
00624 }
00625 *o_autowrite = oldflag;
00626 }
00627 else
00628 {
00629
00630 oldflag = tstflag(file, MODIFIED);
00631 if (cmd == CMD_WQUIT)
00632 setflag(file, MODIFIED);
00633 if (tmpend(bang))
00634 {
00635 mode = MODE_QUIT;
00636 }
00637 else
00638 {
00639 msg("Could not save file -- use quit! to abort changes, or w filename");
00640 }
00641 if (!oldflag)
00642 clrflag(file, MODIFIED);
00643 }
00644 }
00645
00646
00647
00648 void cmd_args(frommark, tomark, cmd, bang, extra)
00649 MARK frommark, tomark;
00650 CMD cmd;
00651 int bang;
00652 char *extra;
00653 {
00654 char *scan;
00655 int col;
00656 int arg;
00657 int scrolled = FALSE;
00658 int width;
00659
00660
00661
00662
00663 if (!extra || !*extra)
00664 {
00665
00666 if (nargs == 1 && !*args)
00667 {
00668 return;
00669 }
00670
00671
00672 for (scan = args, col = arg = 0;
00673 arg < nargs;
00674 scan += width + 1, col += width, arg++)
00675 {
00676 width = strlen(scan);
00677 if (col + width >= COLS - 4)
00678 {
00679 addch('\n');
00680 col = 0;
00681 scrolled = TRUE;
00682 }
00683 else if (col > 0)
00684 {
00685 addch(' ');
00686 col++;
00687 }
00688 if (arg == argno)
00689 {
00690 addch('[');
00691 addstr(scan);
00692 addch(']');
00693 col += 2;
00694 }
00695 else
00696 {
00697 addstr(scan);
00698 }
00699 }
00700
00701
00702 if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col)
00703 {
00704 addch('\n');
00705 }
00706 exrefresh();
00707 }
00708 else
00709 {
00710 for (scan = args, nargs = 1; *extra; )
00711 {
00712 if (isspace(*extra))
00713 {
00714 *scan++ = '\0';
00715 while (isspace(*extra))
00716 {
00717 extra++;
00718 }
00719 if (*extra)
00720 {
00721 nargs++;
00722 }
00723 }
00724 else
00725 {
00726 *scan++ = *extra++;
00727 }
00728 }
00729 *scan = '\0';
00730
00731
00732 argno = -1;
00733
00734 if (nargs != 1)
00735 {
00736 msg("%d files to edit", nargs);
00737 }
00738 }
00739 }
00740
00741
00742
00743 void cmd_cd(frommark, tomark, cmd, bang, extra)
00744 MARK frommark, tomark;
00745 CMD cmd;
00746 int bang;
00747 char *extra;
00748 {
00749 char *getenv();
00750
00751 #ifndef CRUNCH
00752
00753 if (tstflag(file, MODIFIED) && !bang)
00754 {
00755 msg("File modified; use \"cd! %s\" to switch anyway", extra);
00756 }
00757 #endif
00758
00759
00760 if (!*extra)
00761 {
00762 extra = getenv("HOME");
00763 if (!extra)
00764 {
00765 msg("environment variable $HOME not set");
00766 return;
00767 }
00768 }
00769
00770
00771 if (chdir(extra) < 0)
00772 {
00773 perror(extra);
00774 }
00775 }
00776
00777
00778
00779 void cmd_map(frommark, tomark, cmd, bang, extra)
00780 MARK frommark, tomark;
00781 CMD cmd;
00782 int bang;
00783 char *extra;
00784 {
00785 char *mapto;
00786 char *build, *scan;
00787 #ifndef NO_FKEY
00788 static char *fnames[NFKEYS] =
00789 {
00790 "#10", "#1", "#2", "#3", "#4",
00791 "#5", "#6", "#7", "#8", "#9",
00792 # ifndef NO_SHIFT_FKEY
00793 "#10s", "#1s", "#2s", "#3s", "#4s",
00794 "#5s", "#6s", "#7s", "#8s", "#9s",
00795 # ifndef NO_CTRL_FKEY
00796 "#10c", "#1c", "#2c", "#3c", "#4c",
00797 "#5c", "#6c", "#7c", "#8c", "#9c",
00798 # ifndef NO_ALT_FKEY
00799 "#10a", "#1a", "#2a", "#3a", "#4a",
00800 "#5a", "#6a", "#7a", "#8a", "#9a",
00801 # endif
00802 # endif
00803 # endif
00804 };
00805 int key;
00806 #endif
00807
00808
00809 if (!*extra)
00810 {
00811 #ifndef NO_ABBR
00812 if (cmd == CMD_ABBR)
00813 {
00814 dumpkey(bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, TRUE);
00815 }
00816 else
00817 #endif
00818 {
00819 dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, FALSE);
00820 }
00821 }
00822 else
00823 {
00824
00825
00826
00827 for (build = mapto = extra;
00828 *mapto && (*mapto != ' ' && *mapto != '\t');
00829 *build++ = *mapto++)
00830 {
00831 if (*mapto == ctrl('V') && mapto[1])
00832 {
00833 mapto++;
00834 }
00835 }
00836
00837
00838 while ((*mapto == ' ' || *mapto == '\t'))
00839 {
00840 *mapto++ = '\0';
00841 }
00842 *build = '\0';
00843
00844
00845 for (scan = build = mapto; *scan; *build++ = *scan++)
00846 {
00847 if (*scan == ctrl('V') && scan[1])
00848 {
00849 scan++;
00850 }
00851 }
00852 *build = '\0';
00853
00854 #ifndef NO_FKEY
00855
00856
00857
00858 if (extra[0] == '#' && isdigit(extra[1]))
00859 {
00860 key = atoi(extra + 1) % 10;
00861 # ifndef NO_SHIFT_FKEY
00862 build = extra + strlen(extra) - 1;
00863 if (*build == 's')
00864 key += 10;
00865 # ifndef NO_CTRL_FKEY
00866 else if (*build == 'c')
00867 key += 20;
00868 # ifndef NO_ALT_FKEY
00869 else if (*build == 'a')
00870 key += 30;
00871 # endif
00872 # endif
00873 # endif
00874 if (FKEY[key])
00875 mapkey(FKEY[key], mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, fnames[key]);
00876 else
00877 msg("This terminal has no %s key", fnames[key]);
00878 }
00879 else
00880 #endif
00881 #ifndef NO_ABBR
00882 if (cmd == CMD_ABBR || cmd == CMD_UNABBR)
00883 {
00884 mapkey(extra, mapto, bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP, "abbr");
00885 }
00886 else
00887 #endif
00888 {
00889 mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0);
00890 }
00891 }
00892 }
00893
00894
00895
00896 void cmd_set(frommark, tomark, cmd, bang, extra)
00897 MARK frommark, tomark;
00898 CMD cmd;
00899 int bang;
00900 char *extra;
00901 {
00902 if (!*extra)
00903 {
00904 dumpopts(FALSE);
00905 }
00906 else if (!strcmp(extra, "all"))
00907 {
00908 dumpopts(TRUE);
00909 }
00910 else
00911 {
00912 setopts(extra);
00913
00914
00915 changes++;
00916 }
00917 }
00918
00919
00920 void cmd_tag(frommark, tomark, cmd, bang, extra)
00921 MARK frommark, tomark;
00922 CMD cmd;
00923 int bang;
00924 char *extra;
00925 {
00926 int fd;
00927 char *scan;
00928 #ifdef INTERNAL_TAGS
00929 char *cmp;
00930 char *end;
00931 #else
00932 int i;
00933 #endif
00934 #ifndef NO_MAGIC
00935 char wasmagic;
00936 #endif
00937 static char prevtag[30];
00938
00939
00940 if (!extra || !*extra)
00941 {
00942 if (!*prevtag)
00943 {
00944 msg("No previous tag");
00945 return;
00946 }
00947 extra = prevtag;
00948 }
00949 else
00950 {
00951 strncpy(prevtag, extra, sizeof prevtag);
00952 prevtag[sizeof prevtag - 1] = '\0';
00953 }
00954
00955 #ifndef INTERNAL_TAGS
00956
00957 sprintf(tmpblk.c, "ref -t %s%s %s", (*origname ? "-f" : ""),origname, prevtag);
00958 fd = rpipe(tmpblk.c, 0);
00959 if (fd < 0)
00960 {
00961 msg("Can't run \"%s\"", tmpblk.c);
00962 return;
00963 }
00964
00965
00966 for (scan = tmpblk.c;
00967 (i = tread(fd, scan, scan - tmpblk.c + BLKSIZE)) > 0;
00968 scan += i)
00969 {
00970 }
00971 *scan = '\0';
00972
00973
00974 if (rpclose(fd) != 0 || scan < tmpblk.c + 3)
00975 {
00976 msg("tag \"%s\" not found", extra);
00977 return;
00978 }
00979
00980 #else
00981
00982 fd = open(TAGS, O_RDONLY);
00983 if (fd < 0)
00984 {
00985 msg("No tags file");
00986 return;
00987 }
00988
00989
00990
00991
00992 for(scan = end = tmpblk.c, cmp = extra; ; scan++)
00993 {
00994
00995 if (scan >= end)
00996 {
00997 end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE);
00998 scan = tmpblk.c;
00999 if (scan >= end)
01000 {
01001 msg("tag \"%s\" not found", extra);
01002 close(fd);
01003 return;
01004 }
01005 }
01006
01007
01008 if (cmp)
01009 {
01010
01011 if (!*cmp && *scan == '\t')
01012 {
01013 break;
01014 }
01015 if (*cmp++ != *scan)
01016 {
01017
01018 cmp = (char *)0;
01019 }
01020 }
01021
01022
01023 if (!cmp)
01024 {
01025 while (scan < end && *scan != '\n')
01026 {
01027 scan++;
01028 }
01029 if (scan < end)
01030 {
01031 cmp = extra;
01032 }
01033 }
01034 }
01035
01036
01037 for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; )
01038 {
01039 *cmp++ = *scan++;
01040 }
01041 if (scan == end)
01042 {
01043 tread(fd, cmp, BLKSIZE - (int)(cmp - tmpblk.c));
01044 }
01045 else
01046 *cmp = *scan;
01047
01048
01049 close(fd);
01050 #endif
01051
01052
01053 for (scan = tmpblk.c; *scan != '\t'; scan++)
01054 {
01055 }
01056 *scan++ = '\0';
01057 if (strcmp(origname, tmpblk.c) != 0)
01058 {
01059 if (!tmpabort(bang))
01060 {
01061 msg("Use :tag! to abort changes, or :w to save changes");
01062 return;
01063 }
01064 tmpstart(tmpblk.c);
01065 }
01066
01067
01068 #ifndef NO_MAGIC
01069 wasmagic = *o_magic;
01070 *o_magic = FALSE;
01071 #endif
01072 cursor = MARK_FIRST;
01073 linespec(scan, &cursor);
01074 if (cursor == MARK_UNSET)
01075 {
01076 cursor = MARK_FIRST;
01077 msg("Tag's address is out of date");
01078 }
01079 #ifndef NO_MAGIC
01080 *o_magic = wasmagic;
01081 #endif
01082 }
01083
01084
01085
01086
01087
01088
01089
01090 void cmd_version(frommark, tomark, cmd, bang, extra)
01091 MARK frommark;
01092 MARK tomark;
01093 CMD cmd;
01094 int bang;
01095 char *extra;
01096 {
01097 msg("%s", VERSION);
01098 #ifdef CREDIT
01099 msg("%s", CREDIT);
01100 #endif
01101 #ifdef CREDIT2
01102 msg("%s", CREDIT2);
01103 #endif
01104 #ifdef COMPILED_BY
01105 msg("Compiled by %s", COMPILED_BY);
01106 #endif
01107 #ifdef COPYING
01108 msg("%s", COPYING);
01109 #endif
01110 }
01111
01112
01113 #ifndef NO_MKEXRC
01114
01115
01116 void cmd_mkexrc(frommark, tomark, cmd, bang, extra)
01117 MARK frommark;
01118 MARK tomark;
01119 CMD cmd;
01120 int bang;
01121 char *extra;
01122 {
01123 int fd;
01124
01125
01126 if (!*extra)
01127 {
01128 extra = EXRC;
01129 }
01130
01131
01132 fd = creat(extra, FILEPERMS);
01133 if (fd < 0)
01134 {
01135 msg("Couldn't create a new \"%s\" file", extra);
01136 return;
01137 }
01138
01139
01140 saveopts(fd);
01141 savemaps(fd, FALSE);
01142 #ifndef NO_ABBR
01143 savemaps(fd, TRUE);
01144 #endif
01145 #ifndef NO_DIGRAPH
01146 savedigs(fd);
01147 #endif
01148 #ifndef NO_COLOR
01149 savecolor(fd);
01150 #endif
01151
01152
01153 close(fd);
01154 msg("Configuration saved");
01155 }
01156 #endif
01157
01158 #ifndef NO_DIGRAPH
01159
01160 void cmd_digraph(frommark, tomark, cmd, bang, extra)
01161 MARK frommark;
01162 MARK tomark;
01163 CMD cmd;
01164 int bang;
01165 char *extra;
01166 {
01167 do_digraph(bang, extra);
01168 }
01169 #endif
01170
01171
01172 #ifndef NO_ERRLIST
01173 static char errfile[256];
01174 static long errline;
01175 static int errfd = -2;
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190 static char *parse_errmsg(text)
01191 REG char *text;
01192 {
01193 REG char *cpy;
01194 long atol();
01195 # if COHERENT || TOS
01196
01197 errline = atol(text);
01198 if (errline == 0L)
01199 return (char *)0;
01200
01201
01202 while (*text && *text++ != ':')
01203 {
01204 }
01205 if (!*text++)
01206 return (char *)0;
01207
01208
01209 for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; )
01210 {
01211 }
01212 if (!*text++)
01213 return (char *)0;
01214 cpy[-1] = '\0';
01215
01216 return text;
01217 # else
01218 char *errmsg;
01219
01220
01221 errmsg = text;
01222
01223
01224 while (*text && !isalnum(*text))
01225 {
01226 text++;
01227 }
01228
01229
01230 cpy = errfile;
01231 while(isalnum(*text) || *text == '.')
01232 {
01233 *cpy++ = *text++;
01234 }
01235 *cpy = '\0';
01236
01237
01238 if (*text == '/' || !*errfile || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0)
01239 {
01240 return (char *)0;
01241 }
01242
01243
01244 while (*text && !isdigit(*text))
01245 {
01246 text++;
01247 }
01248
01249
01250 if (*text && isalpha(text[-1]))
01251 {
01252 return (char *)0;
01253 }
01254
01255
01256 errline = 0L;
01257 while (isdigit(*text))
01258 {
01259 errline *= 10;
01260 errline += (*text - '0');
01261 text++;
01262 }
01263
01264
01265 if (!errfile[0] || !errline)
01266 {
01267 return (char *)0;
01268 }
01269
01270
01271 while (*text && !isspace(*text))
01272 {
01273 text++;
01274 }
01275 while (*text)
01276 {
01277 # ifndef CRUNCH
01278
01279 if (!strncmp(text + 1, "rror ", 5)
01280 || !strncmp(text + 1, "arning ", 7)
01281 || !strncmp(text + 1, "atal error", 10))
01282 {
01283 do
01284 {
01285 text++;
01286 } while (*text && *text != ':');
01287 continue;
01288 }
01289 # endif
01290
01291
01292 if (!isspace(*text) && *text != ':')
01293 {
01294 errmsg = text;
01295 break;
01296 }
01297
01298
01299 text++;
01300 }
01301
01302 return errmsg;
01303 # endif
01304 }
01305
01306
01307 void cmd_errlist(frommark, tomark, cmd, bang, extra)
01308 MARK frommark, tomark;
01309 CMD cmd;
01310 int bang;
01311 char *extra;
01312 {
01313 static long endline;
01314 static long offset;
01315 int i;
01316 char *errmsg;
01317
01318
01319 if (extra && extra[0])
01320 {
01321
01322 if (errfd >= 0)
01323 {
01324 close(errfd);
01325 }
01326
01327
01328 errfd = open(extra, O_RDONLY);
01329 offset = 0L;
01330 endline = nlines;
01331 }
01332 else if (errfd < 0)
01333 {
01334
01335 errfd = open(ERRLIST, O_RDONLY);
01336 offset = 0L;
01337 endline = nlines;
01338 }
01339
01340
01341 if (errfd < 0)
01342 {
01343 msg("There is no errlist file");
01344 beep();
01345 return;
01346 }
01347
01348
01349 do
01350 {
01351
01352 lseek(errfd, offset, 0);
01353 if (tread(errfd, tmpblk.c, (unsigned)BLKSIZE) <= 0)
01354 {
01355 msg("No more errors");
01356 beep();
01357 close(errfd);
01358 errfd = -2;
01359 return;
01360 }
01361 for (i = 0; tmpblk.c[i] != '\n'; i++)
01362 {
01363 }
01364 tmpblk.c[i++] = 0;
01365
01366
01367 errmsg = parse_errmsg(tmpblk.c);
01368 if (!errmsg)
01369 {
01370 offset += i;
01371 }
01372
01373 } while (!errmsg);
01374
01375
01376 if (strcmp(origname, errfile))
01377 {
01378 if (!tmpabort(bang))
01379 {
01380 msg("Use :er! to abort changes, or :w to save changes");
01381 beep();
01382 return;
01383 }
01384 tmpstart(errfile);
01385 endline = nlines;
01386 }
01387 else if (endline == 0L)
01388 {
01389 endline = nlines;
01390 }
01391
01392
01393 cursor = MARK_AT_LINE(errline + (nlines - endline));
01394 if (cursor > MARK_LAST)
01395 {
01396 cursor = MARK_LAST;
01397 }
01398 if (mode == MODE_VI)
01399 {
01400 redraw(cursor, FALSE);
01401 }
01402
01403
01404 #ifdef CRUNCH
01405 msg("%.70s", errmsg);
01406 #else
01407 if (nlines > endline)
01408 {
01409 msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg);
01410 }
01411 else if (nlines < endline)
01412 {
01413 msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg);
01414 }
01415 else
01416 {
01417 msg("line %ld: %.65s", errline, errmsg);
01418 }
01419 #endif
01420
01421
01422 offset += i;
01423 }
01424
01425
01426
01427 void cmd_make(frommark, tomark, cmd, bang, extra)
01428 MARK frommark, tomark;
01429 CMD cmd;
01430 int bang;
01431 char *extra;
01432 {
01433 BLK buf;
01434
01435
01436 if (tstflag(file, MODIFIED) && !bang)
01437 {
01438 msg("\"%s\" not saved yet", origname);
01439 return;
01440 }
01441
01442
01443 sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST);
01444 qaddstr(buf.c);
01445 addch('\n');
01446
01447
01448 if (errfd >= 0)
01449 {
01450 close(errfd);
01451 errfd = -3;
01452 }
01453
01454
01455 suspend_curses();
01456 system(buf.c);
01457 resume_curses(mode == MODE_EX);
01458 if (mode == MODE_COLON)
01459 mode = MODE_VI;
01460
01461
01462 cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST);
01463 }
01464 #endif
01465
01466
01467
01468 #ifndef NO_COLOR
01469
01470
01471 # ifndef NO_POPUP
01472 # ifndef NO_VISIBLE
01473 # define NCOLORS 7
01474 # else
01475 # define NCOLORS 6
01476 # endif
01477 # else
01478 # ifndef NO_VISIBLE
01479 # define NCOLORS 6
01480 # else
01481 # define NCOLORS 5
01482 # endif
01483 # endif
01484
01485
01486 static char bytes[NCOLORS];
01487
01488 static struct
01489 {
01490 char *word;
01491 int type;
01492 int val;
01493 }
01494 words[] =
01495 {
01496 {"normal", 1, A_NORMAL},
01497 {"standout", 1, A_STANDOUT},
01498 {"bold", 1, A_BOLD},
01499 {"underlined", 1, A_UNDERLINE},
01500 {"italics", 1, A_ALTCHARSET},
01501 #ifndef NO_POPUP
01502 {"popup", 1, A_POPUP},
01503 #endif
01504 #ifndef NO_VISIBLE
01505 {"visible", 1, A_VISIBLE},
01506 #endif
01507
01508 {"black", 3, 0x00},
01509 {"blue", 3, 0x01},
01510 {"green", 3, 0x02},
01511 {"cyan", 3, 0x03},
01512 {"red", 3, 0x04},
01513 {"magenta", 3, 0x05},
01514 {"brown", 3, 0x06},
01515 {"white", 3, 0x07},
01516 {"yellow", 3, 0x0E},
01517 {"gray", 3, 0x08},
01518 {"grey", 3, 0x08},
01519
01520 {"bright", 2, 0x08},
01521 {"light", 2, 0x08},
01522 {"blinking", 2, 0x80},
01523 {"on", 0, 0},
01524 {"n", 1, A_NORMAL},
01525 {"s", 1, A_STANDOUT},
01526 {"b", 1, A_BOLD},
01527 {"u", 1, A_UNDERLINE},
01528 {"i", 1, A_ALTCHARSET},
01529 #ifndef NO_POPUP
01530 {"p", 1, A_POPUP},
01531 {"menu", 1, A_POPUP},
01532 #endif
01533 #ifndef NO_VISIBLE
01534 {"v", 1, A_VISIBLE},
01535 #endif
01536 {(char *)0, 0, 0}
01537 };
01538
01539
01540 void cmd_color(frommark, tomark, cmd, bang, extra)
01541 MARK frommark, tomark;
01542 CMD cmd;
01543 int bang;
01544 char *extra;
01545 {
01546 int attrbyte;
01547 int cmode;
01548 int nowbg;
01549
01550 REG char *scan;
01551 REG i;
01552
01553
01554 #ifndef CRUNCH
01555
01556 if (!*extra)
01557 {
01558
01559 if (!bytes[0])
01560 {
01561 msg("no colors have been set");
01562 return;
01563 }
01564
01565
01566 for (i = 0; i < NCOLORS; i++)
01567 {
01568 qaddstr("color ");
01569 qaddstr(words[i].word);
01570 qaddch(' ');
01571 if (bytes[i] & 0x80)
01572 qaddstr("blinking ");
01573 switch (bytes[i] & 0xf)
01574 {
01575 case 0x08: qaddstr("gray"); break;
01576 case 0x0e: qaddstr("yellow"); break;
01577 case 0x0f: qaddstr("bright white");break;
01578 default:
01579 if (bytes[i] & 0x08)
01580 qaddstr("light ");
01581 qaddstr(words[(bytes[i] & 0x07) + NCOLORS].word);
01582 }
01583 qaddstr(" on ");
01584 qaddstr(words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
01585 addch('\n');
01586 exrefresh();
01587 }
01588 return;
01589 }
01590 #endif
01591
01592
01593
01594
01595 cmode = A_NORMAL;
01596 attrbyte = bytes[0] & 0x70;
01597 nowbg = FALSE;
01598
01599
01600 for (scan = extra; *extra; extra = scan)
01601 {
01602
01603 while (*scan && *scan != ' ')
01604 {
01605 scan++;
01606 }
01607
01608
01609 while(*scan == ' ')
01610 {
01611 *scan++ = '\0';
01612 }
01613
01614
01615 for (i = 0; words[i].word && strcmp(words[i].word, extra); i++)
01616 {
01617 }
01618
01619
01620 if (!words[i].word)
01621 {
01622 msg("Invalid color name: %s", extra);
01623 return;
01624 }
01625
01626
01627 switch (words[i].type)
01628 {
01629 case 1:
01630 cmode = words[i].val;
01631 break;
01632
01633 case 2:
01634 attrbyte |= words[i].val;
01635 break;
01636
01637 case 3:
01638 if (nowbg)
01639 attrbyte = ((attrbyte & ~0x70) | ((words[i].val & 0x07) << 4));
01640 else
01641 attrbyte |= words[i].val;
01642 nowbg = TRUE;
01643 break;
01644 }
01645 }
01646
01647
01648 if (!nowbg)
01649 {
01650 msg("usage: color [when] [\"bright\"] [\"blinking\"] foreground [background]");
01651 return;
01652 }
01653
01654
01655 if (!bytes[0])
01656 cmode = A_NORMAL;
01657
01658
01659
01660
01661 setcolor(cmode, attrbyte);
01662
01663
01664 bytes[cmode] = attrbyte;
01665
01666
01667 if (!bytes[1])
01668 {
01669
01670 bytes[1] = ((attrbyte << 4) & 0x70 | (attrbyte >> 4) & 0x07);
01671 setcolor(A_STANDOUT, bytes[1]);
01672
01673
01674
01675
01676 bytes[2] = attrbyte | ((attrbyte & 0x08) ? 0x0f : 0x08);
01677 setcolor(A_BOLD, bytes[2]);
01678
01679
01680 for (i = 3; i < NCOLORS; i++)
01681 {
01682 bytes[i] = (bytes[1] & 0x7f);
01683 setcolor(words[i].val, bytes[i]);
01684 }
01685 }
01686
01687
01688 redraw(MARK_UNSET, FALSE);
01689 }
01690
01691
01692
01693 void savecolor(fd)
01694 int fd;
01695 {
01696 int i;
01697 char buf[80];
01698
01699
01700 if (!bytes[0])
01701 {
01702 return;
01703 }
01704
01705
01706 for (i = 0; i < NCOLORS; i++)
01707 {
01708 strcpy(buf, "color ");
01709 strcat(buf, words[i].word);
01710 strcat(buf, " ");
01711 if (bytes[i] & 0x80)
01712 strcat(buf, "blinking ");
01713 switch (bytes[i] & 0xf)
01714 {
01715 case 0x08: strcat(buf, "gray"); break;
01716 case 0x0e: strcat(buf, "yellow"); break;
01717 case 0x0f: strcat(buf, "bright white");break;
01718 default:
01719 if (bytes[i] & 0x08)
01720 strcat(buf, "light ");
01721 strcat(buf, words[(bytes[i] & 0x07) + NCOLORS].word);
01722 }
01723 strcat(buf, " on ");
01724 strcat(buf, words[((bytes[i] >> 4) & 0x07) + NCOLORS].word);
01725 strcat(buf, "\n");
01726 twrite(fd, buf, (unsigned)strlen(buf));
01727 }
01728 }
01729 #endif
01730
01731 #ifdef SIGTSTP
01732
01733
01734 void cmd_suspend(frommark, tomark, cmd, bang, extra)
01735 MARK frommark;
01736 MARK tomark;
01737 CMD cmd;
01738 int bang;
01739 char *extra;
01740 {
01741 void (*func)();
01742
01743 #if ANY_UNIX
01744
01745 if (!strcmp(o_shell, "/bin/sh"))
01746 {
01747 msg("The /bin/sh shell doesn't support ^Z");
01748 return;
01749 }
01750 #endif
01751
01752 move(LINES - 1, 0);
01753 if (tstflag(file, MODIFIED))
01754 {
01755 addstr("Warning: \"");
01756 addstr(origname);
01757 addstr("\" modified but not yet saved");
01758 clrtoeol();
01759 }
01760 refresh();
01761 suspend_curses();
01762 func = signal(SIGTSTP, SIG_DFL);
01763 kill (0, SIGTSTP);
01764
01765
01766
01767 signal(SIGTSTP, func);
01768 resume_curses(TRUE);
01769 if (mode == MODE_VI || mode == MODE_COLON)
01770 redraw(MARK_UNSET, FALSE);
01771 else
01772 refresh ();
01773 }
01774 #endif