00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "config.h"
00014 #include "ctype.h"
00015 #include "vi.h"
00016 #include "regexp.h"
00017 #if TOS
00018 # include <stat.h>
00019 #else
00020 # if OSK
00021 # include "osk.h"
00022 # else
00023 # if AMIGA
00024 # include "amistat.h"
00025 # else
00026 # include <sys/stat.h>
00027 # endif
00028 # endif
00029 #endif
00030
00031
00032
00033 void cmd_substitute(frommark, tomark, cmd, bang, extra)
00034 MARK frommark;
00035 MARK tomark;
00036 CMD cmd;
00037 int bang;
00038 char *extra;
00039 {
00040 char *line;
00041 regexp *re;
00042 char *subst;
00043 char *opt;
00044 long l;
00045 char *s, *d;
00046 char *conf;
00047 long chline;
00048 long chsub;
00049 static optp;
00050 static optg;
00051 static optc;
00052 #ifndef CRUNCH
00053 long oldnlines;
00054 #endif
00055
00056
00057
00058 rptlines = -1L;
00059
00060 if (cmd == CMD_SUBAGAIN)
00061 {
00062 #ifndef NO_MAGIC
00063 if (*o_magic)
00064 subst = "~";
00065 else
00066 #endif
00067 subst = "\\~";
00068 re = regcomp("");
00069
00070
00071 if (bang)
00072 {
00073 optp = optc = FALSE;
00074 }
00075 }
00076 else
00077 {
00078
00079 if (*extra != '/' && *extra != '?')
00080 {
00081 msg("Usage: s/regular expression/new text/");
00082 return;
00083 }
00084
00085
00086 subst = parseptrn(extra);
00087 re = regcomp(extra + 1);
00088 }
00089
00090
00091 if (!re)
00092 {
00093 return;
00094 }
00095
00096 if (cmd == CMD_SUBSTITUTE)
00097 {
00098
00099 for (opt = subst; *opt && *opt != *extra; opt++)
00100 {
00101 if (*opt == '\\' && opt[1])
00102 {
00103 opt++;
00104 }
00105 }
00106 if (*opt)
00107 {
00108 *opt++ = '\0';
00109 }
00110
00111
00112 if (!*o_edcompatible)
00113 {
00114 optp = optg = optc = FALSE;
00115 }
00116 while (*opt)
00117 {
00118 switch (*opt++)
00119 {
00120 case 'p': optp = !optp; break;
00121 case 'g': optg = !optg; break;
00122 case 'c': optc = !optc; break;
00123 case ' ':
00124 case '\t': break;
00125 default:
00126 msg("Subst options are p, c, and g -- not %c", opt[-1]);
00127 return;
00128 }
00129 }
00130 }
00131
00132
00133 if ((optc || optp) && mode == MODE_VI)
00134 {
00135 addch('\n');
00136 exrefresh();
00137 }
00138
00139 ChangeText
00140 {
00141
00142 chline = chsub = 0L;
00143
00144
00145 for (l = markline(frommark); l <= markline(tomark); l++)
00146 {
00147
00148 line = fetchline(l);
00149
00150
00151 if (regexec(re, line, TRUE))
00152 {
00153
00154 chline++;
00155
00156
00157 s = line;
00158 d = tmpblk.c;
00159
00160
00161 do
00162 {
00163 #ifndef CRUNCH
00164
00165 if (optc)
00166 {
00167 for (conf = line; conf < re->startp[0]; conf++)
00168 addch(*conf);
00169 standout();
00170 for ( ; conf < re->endp[0]; conf++)
00171 addch(*conf);
00172 standend();
00173 for (; *conf; conf++)
00174 addch(*conf);
00175 addch('\n');
00176 exrefresh();
00177 if (getkey(0) != 'y')
00178 {
00179
00180 while (s < re->endp[0])
00181 *d++ = *s++;
00182
00183
00184 goto Continue;
00185 }
00186 }
00187 #endif
00188
00189
00190 chsub++;
00191
00192
00193 while (s < re->startp[0])
00194 {
00195 *d++ = *s++;
00196 }
00197
00198
00199 regsub(re, subst, d);
00200 s = re->endp[0];
00201 d += strlen(d);
00202
00203 Continue:
00204
00205
00206
00207
00208
00209 if (re->minlen == 0)
00210 {
00211 if (!*s)
00212 break;
00213 *d++ = *s++;
00214 }
00215
00216 } while (optg && regexec(re, s, FALSE));
00217
00218
00219 while (*d++ = *s++)
00220 {
00221 }
00222
00223 #ifndef CRUNCH
00224
00225
00226
00227
00228
00229 oldnlines = nlines;
00230 #endif
00231
00232
00233 d[-1] = '\n';
00234 d[0] = '\0';
00235 change(MARK_AT_LINE(l), MARK_AT_LINE(l + 1), tmpblk.c);
00236
00237 #ifndef CRUNCH
00238 l += nlines - oldnlines;
00239 tomark += MARK_AT_LINE(nlines - oldnlines);
00240 #endif
00241
00242
00243 if (optp)
00244 {
00245 addstr(tmpblk.c);
00246 exrefresh();
00247 }
00248
00249
00250 cursor = MARK_AT_LINE(l);
00251 }
00252 }
00253 }
00254
00255
00256 free(re);
00257
00258
00259 if (doingglobal)
00260 {
00261 rptlines = chline;
00262 rptlabel = "changed";
00263 return;
00264 }
00265
00266
00267 if (chsub == 0)
00268 {
00269 msg("Substitution failed");
00270 }
00271 else if (chline >= *o_report)
00272 {
00273 msg("%ld substitutions on %ld lines", chsub, chline);
00274 }
00275 rptlines = 0L;
00276 }
00277
00278
00279
00280
00281
00282 void cmd_delete(frommark, tomark, cmd, bang, extra)
00283 MARK frommark;
00284 MARK tomark;
00285 CMD cmd;
00286 int bang;
00287 char *extra;
00288 {
00289 MARK curs2;
00290
00291
00292 if (*extra == '"')
00293 {
00294 extra++;
00295 }
00296 if (*extra)
00297 {
00298 cutname(*extra);
00299 }
00300
00301
00302 frommark = frommark & ~(BLKSIZE - 1);
00303 tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
00304
00305
00306 cut(frommark, tomark);
00307
00308
00309 if (cmd != CMD_YANK)
00310 {
00311 curs2 = cursor;
00312 ChangeText
00313 {
00314
00315 delete(frommark, tomark);
00316 }
00317 if (curs2 > tomark)
00318 {
00319 cursor = curs2 - tomark + frommark;
00320 }
00321 else if (curs2 > frommark)
00322 {
00323 cursor = frommark;
00324 }
00325 }
00326 }
00327
00328
00329
00330 void cmd_append(frommark, tomark, cmd, bang, extra)
00331 MARK frommark;
00332 MARK tomark;
00333 CMD cmd;
00334 int bang;
00335 char *extra;
00336 {
00337 long l;
00338
00339 #ifndef CRUNCH
00340
00341 if (bang)
00342 {
00343 *o_autoindent = !*o_autoindent;
00344 }
00345 #endif
00346
00347 ChangeText
00348 {
00349
00350 if (cmd == CMD_CHANGE)
00351 {
00352
00353 cmd_delete(frommark, tomark, cmd, bang, extra);
00354 }
00355
00356
00357 l = markline(frommark);
00358 if (cmd == CMD_APPEND)
00359 {
00360 l++;
00361 }
00362
00363
00364 while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
00365 {
00366 addch('\n');
00367 if (!strcmp(tmpblk.c, "."))
00368 {
00369 break;
00370 }
00371
00372 strcat(tmpblk.c, "\n");
00373 add(MARK_AT_LINE(l), tmpblk.c);
00374 l++;
00375 }
00376 }
00377
00378
00379 redraw(MARK_UNSET, FALSE);
00380 }
00381
00382
00383
00384 void cmd_put(frommark, tomark, cmd, bang, extra)
00385 MARK frommark;
00386 MARK tomark;
00387 CMD cmd;
00388 int bang;
00389 char *extra;
00390 {
00391
00392 if (*extra == '"')
00393 {
00394 extra++;
00395 }
00396 if (*extra)
00397 {
00398 cutname(*extra);
00399 }
00400
00401
00402 ChangeText
00403 {
00404 cursor = paste(frommark, TRUE, FALSE);
00405 }
00406 }
00407
00408
00409
00410 void cmd_join(frommark, tomark, cmd, bang, extra)
00411 MARK frommark;
00412 MARK tomark;
00413 CMD cmd;
00414 int bang;
00415 char *extra;
00416 {
00417 long l;
00418 char *scan;
00419 int len;
00420
00421
00422 if (markline(frommark) == nlines)
00423 {
00424 msg("Nothing to join with this line");
00425 return;
00426 }
00427 if (markline(frommark) == markline(tomark))
00428 {
00429 tomark += BLKSIZE;
00430 }
00431
00432
00433 l = markline(frommark);
00434 strcpy(tmpblk.c, fetchline(l));
00435 len = strlen(tmpblk.c);
00436
00437
00438 while (++l <= markline(tomark))
00439 {
00440
00441 scan = fetchline(l);
00442
00443
00444 while (*scan == '\t' || *scan == ' ')
00445 {
00446 scan++;
00447 }
00448
00449
00450 if (strlen(scan) + len + 3 > BLKSIZE)
00451 {
00452 msg("Can't join -- the resulting line would be too long");
00453 return;
00454 }
00455
00456
00457 if (!bang)
00458 {
00459 if (len >= 1)
00460 {
00461 if (tmpblk.c[len - 1] == '.'
00462 || tmpblk.c[len - 1] == '?'
00463 || tmpblk.c[len - 1] == '!')
00464 {
00465 tmpblk.c[len++] = ' ';
00466 }
00467 tmpblk.c[len++] = ' ';
00468 }
00469 }
00470 strcpy(tmpblk.c + len, scan);
00471 len += strlen(scan);
00472 }
00473 tmpblk.c[len++] = '\n';
00474 tmpblk.c[len] = '\0';
00475
00476
00477 ChangeText
00478 {
00479 frommark &= ~(BLKSIZE - 1);
00480 tomark &= ~(BLKSIZE - 1);
00481 tomark += BLKSIZE;
00482 change(frommark, tomark, tmpblk.c);
00483 }
00484
00485
00486 rptlines = markline(tomark) - markline(frommark) - 1L;
00487 rptlabel = "joined";
00488 }
00489
00490
00491
00492
00493 void cmd_shift(frommark, tomark, cmd, bang, extra)
00494 MARK frommark;
00495 MARK tomark;
00496 CMD cmd;
00497 int bang;
00498 char *extra;
00499 {
00500 long l;
00501 int oldidx;
00502 int newidx;
00503 int oldcol;
00504 int newcol;
00505 char *text;
00506
00507 ChangeText
00508 {
00509
00510 for (l = markline(frommark); l <= markline(tomark); l++)
00511 {
00512
00513 text = fetchline(l);
00514 if (!*text && !bang)
00515 continue;
00516
00517
00518 for (oldidx = 0, oldcol = 0;
00519 text[oldidx] == ' ' || text[oldidx] == '\t';
00520 oldidx++)
00521 {
00522 if (text[oldidx] == ' ')
00523 {
00524 oldcol += 1;
00525 }
00526 else
00527 {
00528 oldcol += *o_tabstop - (oldcol % *o_tabstop);
00529 }
00530 }
00531
00532
00533 if (cmd == CMD_SHIFTR)
00534 {
00535 newcol = oldcol + (*o_shiftwidth & 0xff);
00536 }
00537 else
00538 {
00539 newcol = oldcol - (*o_shiftwidth & 0xff);
00540 if (newcol < 0)
00541 newcol = 0;
00542 }
00543
00544
00545 if (oldcol == newcol)
00546 continue;
00547
00548
00549 newidx = 0;
00550 if (*o_autotab)
00551 {
00552 while (newcol >= *o_tabstop)
00553 {
00554 tmpblk.c[newidx++] = '\t';
00555 newcol -= *o_tabstop;
00556 }
00557 }
00558 while (newcol > 0)
00559 {
00560 tmpblk.c[newidx++] = ' ';
00561 newcol--;
00562 }
00563 tmpblk.c[newidx] = '\0';
00564
00565
00566 change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c);
00567 }
00568 }
00569
00570
00571 rptlines = markline(tomark) - markline(frommark) + 1L;
00572 if (cmd == CMD_SHIFTR)
00573 {
00574 rptlabel = ">ed";
00575 }
00576 else
00577 {
00578 rptlabel = "<ed";
00579 }
00580 }
00581
00582
00583
00584 void cmd_read(frommark, tomark, cmd, bang, extra)
00585 MARK frommark;
00586 MARK tomark;
00587 CMD cmd;
00588 int bang;
00589 char *extra;
00590 {
00591 int fd, rc;
00592 char *scan;
00593 int hadnul;
00594 int addnl;
00595 int len;
00596 long lines;
00597 struct stat statb;
00598
00599
00600 if (extra[0] == '!')
00601 {
00602 filter(frommark, MARK_UNSET, extra + 1, TRUE);
00603 return;
00604 }
00605
00606
00607 fd = open(extra, O_RDONLY);
00608 if (fd < 0)
00609 {
00610 msg("Can't open \"%s\"", extra);
00611 return;
00612 }
00613
00614 #ifndef CRUNCH
00615 if (stat(extra, &statb) < 0)
00616 {
00617 msg("Can't stat \"%s\"", extra);
00618 }
00619 # if TOS
00620 if (statb.st_mode & S_IJDIR)
00621 # else
00622 # if OSK
00623 if (statb.st_mode & S_IFDIR)
00624 # else
00625 if ((statb.st_mode & S_IFMT) != S_IFREG)
00626 # endif
00627 # endif
00628 {
00629 msg("\"%s\" is not a regular file", extra);
00630 return;
00631 }
00632 #endif
00633
00634
00635 ChangeText
00636 {
00637
00638 tomark = frommark = (frommark | (BLKSIZE - 1L)) + 1L;
00639 len = 0;
00640 hadnul = addnl = FALSE;
00641
00642
00643
00644
00645 add(tomark, "\n");
00646
00647
00648 while ((rc = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
00649 {
00650
00651 for (lines = 0, scan = tmpblk.c; rc > 0; rc--, scan++)
00652 {
00653
00654 if (*scan != '\n' && len + 2 > BLKSIZE)
00655 {
00656 *scan = '\n';
00657 addnl = TRUE;
00658 }
00659
00660
00661 if (!*scan)
00662 {
00663 *scan = 0x80;
00664 hadnul = TRUE;
00665 }
00666
00667
00668 if (*scan == '\n')
00669 {
00670
00671 len = 0;
00672 lines++;
00673 }
00674 else
00675 {
00676 len++;
00677 }
00678 }
00679
00680
00681 *scan = '\0';
00682 add(tomark, tmpblk.c);
00683 tomark += MARK_AT_LINE(lines) + len - markidx(tomark);
00684 }
00685
00686
00687 if (len > 0)
00688 {
00689 msg("Last line had no newline");
00690 tomark += BLKSIZE;
00691 }
00692 else
00693 {
00694 delete(tomark, (tomark | (BLKSIZE - 1L)) + 1L);
00695 }
00696 }
00697
00698
00699 close(fd);
00700
00701
00702 rptlines = markline(tomark) - markline(frommark);
00703 rptlabel = "read";
00704 if (mode == MODE_EX)
00705 {
00706 cursor = (tomark & ~BLKSIZE) - BLKSIZE;
00707 }
00708 else
00709 {
00710 cursor = frommark;
00711 }
00712
00713 if (addnl)
00714 msg("Newlines were added to break up long lines");
00715 if (hadnul)
00716 msg("NULs were converted to 0x80");
00717 }
00718
00719
00720
00721
00722 void cmd_undo(frommark, tomark, cmd, bang, extra)
00723 MARK frommark;
00724 MARK tomark;
00725 CMD cmd;
00726 int bang;
00727 char *extra;
00728 {
00729 undo();
00730 }
00731
00732
00733
00734
00735 void cmd_print(frommark, tomark, cmd, bang, extra)
00736 MARK frommark;
00737 MARK tomark;
00738 CMD cmd;
00739 int bang;
00740 char *extra;
00741 {
00742 REG char *scan;
00743 REG long l;
00744 REG int col;
00745
00746 for (l = markline(frommark); l <= markline(tomark); l++)
00747 {
00748
00749 if (cmd == CMD_NUMBER)
00750 {
00751 sprintf(tmpblk.c, "%6ld ", l);
00752 qaddstr(tmpblk.c);
00753 col = 8;
00754 }
00755 else
00756 {
00757 col = 0;
00758 }
00759
00760
00761 for (scan = fetchline(l); *scan; scan++)
00762 {
00763
00764 if (*scan == '\t' && cmd != CMD_LIST)
00765 {
00766 do
00767 {
00768 qaddch(' ');
00769 col++;
00770 } while (col % *o_tabstop != 0);
00771 }
00772 else if (*scan > 0 && *scan < ' ' || *scan == '\177')
00773 {
00774 qaddch('^');
00775 qaddch(*scan ^ 0x40);
00776 col += 2;
00777 }
00778 else if ((*scan & 0x80) && cmd == CMD_LIST)
00779 {
00780 sprintf(tmpblk.c, "\\%03o", UCHAR(*scan));
00781 qaddstr(tmpblk.c);
00782 col += 4;
00783 }
00784 else
00785 {
00786 qaddch(*scan);
00787 col++;
00788 }
00789
00790
00791 if (!has_AM && col >= COLS)
00792 {
00793 addch('\n');
00794 col -= COLS;
00795 }
00796 }
00797 if (cmd == CMD_LIST)
00798 {
00799 qaddch('$');
00800 }
00801 addch('\n');
00802 exrefresh();
00803 }
00804 }
00805
00806
00807
00808
00809 void cmd_move(frommark, tomark, cmd, bang, extra)
00810 MARK frommark;
00811 MARK tomark;
00812 CMD cmd;
00813 int bang;
00814 char *extra;
00815 {
00816 MARK destmark;
00817
00818
00819 destmark = cursor;
00820 if (!strcmp(extra, "0"))
00821 {
00822 destmark = 0L;
00823 }
00824 else if (linespec(extra, &destmark) == extra || !destmark)
00825 {
00826 msg("invalid destination address");
00827 return;
00828 }
00829
00830
00831 frommark &= ~(BLKSIZE - 1);
00832 tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
00833 destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE;
00834
00835
00836 if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark)
00837 {
00838 msg("invalid destination address");
00839 }
00840
00841
00842 ChangeText
00843 {
00844
00845 cutname('\0');
00846 cut(frommark, tomark);
00847
00848
00849 if (cmd != CMD_COPY)
00850 {
00851 delete(frommark, tomark);
00852 if (destmark >= frommark)
00853 {
00854 destmark -= (tomark - frommark);
00855 }
00856 }
00857
00858
00859 paste(destmark, FALSE, FALSE);
00860 }
00861
00862
00863 cursor = destmark + (tomark - frommark) - BLKSIZE;
00864 if (cursor < MARK_FIRST || cursor >= MARK_LAST + BLKSIZE)
00865 {
00866 cursor = MARK_LAST;
00867 }
00868
00869
00870 rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" );
00871 }
00872
00873
00874
00875
00876
00877 void cmd_source(frommark, tomark, cmd, bang, extra)
00878 MARK frommark;
00879 MARK tomark;
00880 CMD cmd;
00881 int bang;
00882 char *extra;
00883 {
00884
00885 if (!*extra)
00886 {
00887 msg("\"source\" requires a filename");
00888 return;
00889 }
00890
00891 doexrc(extra);
00892 }
00893
00894
00895 #ifndef NO_AT
00896
00897 void cmd_at(frommark, tomark, cmd, bang, extra)
00898 MARK frommark;
00899 MARK tomark;
00900 CMD cmd;
00901 int bang;
00902 char *extra;
00903 {
00904 static nest = FALSE;
00905 int result;
00906 char buf[MAXRCLEN];
00907
00908
00909 if (nest)
00910 {
00911 msg("@ macros can't be nested");
00912 return;
00913 }
00914 nest = TRUE;
00915
00916
00917 if (*extra == '"')
00918 extra++;
00919 if (!*extra || !isascii(*extra) ||!islower(*extra))
00920 {
00921 msg("@ requires a cut buffer name (a-z)");
00922 }
00923
00924
00925 result = cb2str(*extra, buf, (unsigned)(sizeof buf));
00926 if (result <= 0)
00927 {
00928 msg("buffer \"%c is empty", *extra);
00929 }
00930 else if (result >= sizeof buf)
00931 {
00932 msg("buffer \"%c is too large to execute", *extra);
00933 }
00934 else
00935 {
00936
00937 exstring(buf, result, '\\');
00938 }
00939
00940 nest = FALSE;
00941 }
00942 #endif