heirloom-ed

annotate ed.c @ 4:4165f1b57d18

Become SUSv3 compatible and thus remove own regexp code The Heirloom tools can be compiled to comply to several standards. This version does not need this flexibility. We can omit the regexp code and use the system's, by using the SU3 variant of ed. This is the latest of the supported standards.
author markus schnalke <meillo@marmaro.de>
date Mon, 13 Apr 2015 17:26:51 +0200
parents ac52712b2b5e
children
rev   line source
meillo@0 1 /*
meillo@0 2 * Editor
meillo@0 3 */
meillo@0 4
meillo@0 5 /*
meillo@0 6 * Changes by Gunnar Ritter, Freiburg i. Br., Germany, July 2003.
meillo@0 7 */
meillo@0 8 /* from Unix 32V /usr/src/cmd/ed.c */
meillo@0 9 /*
meillo@0 10 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
meillo@0 11 *
meillo@0 12 * Redistribution and use in source and binary forms, with or without
meillo@0 13 * modification, are permitted provided that the following conditions
meillo@0 14 * are met:
meillo@0 15 * Redistributions of source code and documentation must retain the
meillo@0 16 * above copyright notice, this list of conditions and the following
meillo@0 17 * disclaimer.
meillo@0 18 * Redistributions in binary form must reproduce the above copyright
meillo@0 19 * notice, this list of conditions and the following disclaimer in the
meillo@0 20 * documentation and/or other materials provided with the distribution.
meillo@0 21 * All advertising materials mentioning features or use of this software
meillo@0 22 * must display the following acknowledgement:
meillo@0 23 * This product includes software developed or owned by Caldera
meillo@0 24 * International, Inc.
meillo@0 25 * Neither the name of Caldera International, Inc. nor the names of
meillo@0 26 * other contributors may be used to endorse or promote products
meillo@0 27 * derived from this software without specific prior written permission.
meillo@0 28 *
meillo@0 29 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
meillo@0 30 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
meillo@0 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
meillo@0 32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
meillo@0 33 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
meillo@0 34 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
meillo@0 35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
meillo@0 36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
meillo@0 37 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
meillo@0 38 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
meillo@0 39 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
meillo@0 40 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
meillo@0 41 */
meillo@0 42
meillo@0 43 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
meillo@0 44 #define USED __attribute__ ((used))
meillo@0 45 #elif defined __GNUC__
meillo@0 46 #define USED __attribute__ ((unused))
meillo@0 47 #else
meillo@0 48 #define USED
meillo@0 49 #endif
meillo@0 50 static const char sccsid[] USED = "@(#)ed_su3.sl 1.99 (gritter) 7/27/06";
meillo@0 51
meillo@0 52 #include <sys/types.h>
meillo@0 53 #include <sys/stat.h>
meillo@0 54 #include <sys/wait.h>
meillo@0 55 #include <sys/stat.h>
meillo@0 56 #include <fcntl.h>
meillo@0 57 #include <unistd.h>
meillo@0 58 #include <time.h>
meillo@0 59 #include <string.h>
meillo@0 60 #include <stdlib.h>
meillo@0 61 #include <signal.h>
meillo@0 62 #include "sigset.h"
meillo@0 63 #include <setjmp.h>
meillo@0 64 #include <libgen.h>
meillo@0 65 #include <inttypes.h>
meillo@0 66 #include <locale.h>
meillo@0 67 #include <wchar.h>
meillo@0 68 #include <ctype.h>
meillo@0 69 #include <wctype.h>
meillo@0 70 #include <limits.h>
meillo@0 71 static int FNSIZE;
meillo@0 72 static int LBSIZE;
meillo@0 73 static int RHSIZE;
meillo@0 74 #define ESIZE 2048
meillo@0 75 static int GBSIZE;
meillo@0 76 #undef EOF
meillo@0 77 #define EOF -1
meillo@0 78 #define puts(s) xxputs(s)
meillo@0 79 #define getline(t, n) xxgetline(t, n)
meillo@0 80
meillo@0 81 #if (LONG_MAX > 017777777777L)
meillo@0 82 #define MAXCNT 0777777777777777777777L /* 2^63-1 */
meillo@0 83 #else
meillo@0 84 #define MAXCNT 017777777777L /* 2^31-1 */
meillo@0 85 #endif
meillo@0 86 #define BLKMSK (MAXCNT>>8) /* was 0377 */
meillo@0 87
meillo@0 88 #define READ 0
meillo@0 89 #define WRITE 1
meillo@0 90 #define EXIST 2
meillo@0 91
meillo@0 92 static int peekc;
meillo@0 93 static int lastc;
meillo@0 94 static char *savedfile;
meillo@0 95 static char *file;
meillo@0 96 static struct stat fstbuf;
meillo@0 97 static char *linebuf;
meillo@0 98 static char *rhsbuf;
meillo@0 99 static char expbuf[ESIZE + 4];
meillo@0 100 static long *zero;
meillo@0 101 static long *undzero;
meillo@0 102 static long *dot;
meillo@0 103 static long *unddot;
meillo@0 104 static long *dol;
meillo@0 105 static long *unddol;
meillo@0 106 static long *addr1;
meillo@0 107 static long *addr2;
meillo@0 108 static char *genbuf;
meillo@0 109 static long count;
meillo@0 110 static char *linebp;
meillo@0 111 static int ninbuf;
meillo@0 112 static int io;
meillo@0 113 static int ioeof;
meillo@0 114 static int pflag;
meillo@0 115 static char *wrtemp;
meillo@0 116 static uid_t myuid;
meillo@0 117 static void (*oldhup)(int);
meillo@0 118 static void (*oldquit)(int);
meillo@0 119 static void (*oldpipe)(int);
meillo@0 120 static int vflag = 1;
meillo@0 121 static int listf;
meillo@0 122 static int numbf;
meillo@0 123 static char *globp;
meillo@0 124 static int tfile = -1;
meillo@0 125 static long tline;
meillo@0 126 static char tfname[64];
meillo@0 127 static char ibuff[512];
meillo@0 128 static int iblock = -1;
meillo@0 129 static char obuff[512];
meillo@0 130 static int oblock = -1;
meillo@0 131 static int ichanged;
meillo@0 132 static int nleft;
meillo@0 133 static long *names;
meillo@0 134 static long *undnames;
meillo@0 135 static int anymarks;
meillo@0 136 static int subnewa;
meillo@0 137 static int fchange;
meillo@0 138 static int wrapp;
meillo@0 139 static unsigned nlall = 128;
meillo@0 140 static const char *progname;
meillo@0 141 static const char *prompt = "*";
meillo@0 142 static int Pflag;
meillo@0 143 static int prhelp;
meillo@0 144 static const char *prvmsg;
meillo@0 145 static int lastsig;
meillo@0 146 static int pipid = -1;
meillo@0 147 static int readop;
meillo@0 148 static int status;
meillo@0 149 static int mb_cur_max;
meillo@0 150 static int needsub;
meillo@0 151 static int insub;
meillo@0 152 static int maxlength;
meillo@0 153 static int rspec;
meillo@0 154 static int Nflag;
meillo@0 155 static int bcount = 22;
meillo@0 156 static int ocount = 11;
meillo@0 157
meillo@0 158 static jmp_buf savej;
meillo@0 159
meillo@2 160 static void usage(char);
meillo@0 161 static void commands(void);
meillo@0 162 static long *address(void);
meillo@0 163 static void setdot(void);
meillo@0 164 static void setall(void);
meillo@0 165 static void setnoaddr(void);
meillo@0 166 static void nonzero(void);
meillo@0 167 static void newline(void);
meillo@0 168 static void filename(int);
meillo@0 169 static void exfile(void);
meillo@0 170 static void onintr(int);
meillo@0 171 static void onhup(int);
meillo@0 172 static void onpipe(int);
meillo@0 173 static void error(const char *);
meillo@0 174 static void error2(const char *, const char *);
meillo@0 175 static void errput(const char *, const char *);
meillo@0 176 static int getchr(void);
meillo@0 177 static int gettty(void);
meillo@0 178 static long getnum(void);
meillo@0 179 static int getfile(void);
meillo@0 180 static void putfile(void);
meillo@0 181 static int append(int (*)(void), long *);
meillo@0 182 static void callunix(void);
meillo@0 183 static char *readcmd(void);
meillo@0 184 static void quit(int);
meillo@0 185 static void delete(void);
meillo@0 186 static void rdelete(long *, long *);
meillo@0 187 static void gdelete(void);
meillo@0 188 static char *getline(long, int);
meillo@0 189 static int putline(void);
meillo@0 190 static char *getblock(long, long);
meillo@0 191 static void blkio(long, char *, int);
meillo@0 192 static void init(void);
meillo@0 193 static void global(int, int);
meillo@0 194 static void globrd(char **, int);
meillo@0 195 static void join(void);
meillo@0 196 static void substitute(int);
meillo@0 197 static int compsub(void);
meillo@0 198 static int getsub(void);
meillo@0 199 static int dosub(int);
meillo@0 200 static int place(int, const char *, const char *);
meillo@0 201 static void move(int);
meillo@0 202 static void reverse(long *, long *);
meillo@0 203 static int getcopy(void);
meillo@0 204 static int execute(int, long *, int);
meillo@0 205 static void cmplerr(int);
meillo@0 206 static void doprnt(long *, long *);
meillo@0 207 static void putd(long);
meillo@0 208 static void puts(const char *);
meillo@0 209 static void nlputs(const char *);
meillo@0 210 static void list(const char *);
meillo@0 211 static int lstchr(int);
meillo@0 212 static void putstr(const char *);
meillo@0 213 static void putchr(int);
meillo@0 214 static void checkpoint(void);
meillo@0 215 static void undo(void);
meillo@0 216 static int maketf(int);
meillo@0 217 static int creatf(const char *);
meillo@0 218 static int sopen(const char *, int);
meillo@0 219 static void sclose(int);
meillo@0 220 static void growlb(const char *);
meillo@0 221 static void growrhs(const char *);
meillo@0 222 static void growfn(const char *);
meillo@0 223 static void help(void);
meillo@0 224
meillo@0 225 #define INIT
meillo@0 226 #define GETC() getchr()
meillo@0 227 #define UNGETC(c) (peekc = c)
meillo@0 228 #define PEEKC() (peekc = getchr())
meillo@0 229 #define RETURN(c) return c
meillo@0 230 #define ERROR(c) cmplerr(c)
meillo@0 231 static wint_t GETWC(char *);
meillo@0 232
meillo@0 233 #include <regex.h>
meillo@0 234
meillo@0 235 #define NBRA 9
meillo@0 236
meillo@0 237 static char *braslist[NBRA];
meillo@0 238 static char *braelist[NBRA];
meillo@0 239 static char *loc1, *loc2, *locs;
meillo@0 240 static int nbra;
meillo@0 241 static int circf;
meillo@0 242 static int nodelim;
meillo@0 243
meillo@0 244 static char *compile(char *, char *, const char *, int);
meillo@0 245 static int step(const char *, const char *);
meillo@0 246
meillo@0 247 int
meillo@0 248 main(int argc, char **argv)
meillo@0 249 {
meillo@0 250 register int i;
meillo@0 251 void (*oldintr)(int);
meillo@0 252
meillo@0 253 progname = basename(argv[0]);
meillo@0 254 setlocale(LC_COLLATE, "");
meillo@0 255 setlocale(LC_CTYPE, "");
meillo@0 256 mb_cur_max = MB_CUR_MAX;
meillo@0 257 myuid = getuid();
meillo@0 258 oldquit = sigset(SIGQUIT, SIG_IGN);
meillo@0 259 oldhup = sigset(SIGHUP, SIG_IGN);
meillo@0 260 oldintr = sigset(SIGINT, SIG_IGN);
meillo@0 261 if (sigset(SIGTERM, SIG_IGN) != SIG_IGN)
meillo@0 262 sigset(SIGTERM, quit);
meillo@0 263 oldpipe = sigset(SIGPIPE, onpipe);
meillo@0 264 argv++;
meillo@2 265 if (argc > 1 && **argv=='-') {
meillo@2 266 if ((*argv)[1]=='\0') {
meillo@0 267 vflag = 0;
meillo@2 268 } else {
meillo@2 269 usage((*argv)[1]);
meillo@0 270 }
meillo@2 271 argv++;
meillo@0 272 argc--;
meillo@0 273 }
meillo@0 274
meillo@0 275 growfn("no space");
meillo@0 276 if (argc>1) {
meillo@0 277 i = -1;
meillo@0 278 do
meillo@0 279 if (++i >= FNSIZE)
meillo@0 280 growfn("maximum of characters in "
meillo@0 281 "file names reached");
meillo@0 282 while (savedfile[i] = (*argv)[i]);
meillo@0 283 globp = "e";
meillo@0 284 }
meillo@0 285 names = malloc(26*sizeof *names);
meillo@0 286 undnames = malloc(26*sizeof *undnames);
meillo@0 287 zero = malloc(nlall*sizeof *zero);
meillo@0 288 if ((undzero = malloc(nlall*sizeof *undzero)) == NULL)
meillo@0 289 puts("no memory for undo");
meillo@0 290 growlb("no space");
meillo@0 291 growrhs("no space");
meillo@0 292 init();
meillo@0 293 if (oldintr != SIG_IGN)
meillo@0 294 sigset(SIGINT, onintr);
meillo@0 295 if (oldhup != SIG_IGN)
meillo@0 296 sigset(SIGHUP, onhup);
meillo@0 297 setjmp(savej);
meillo@0 298 if (lastsig) {
meillo@0 299 sigrelse(lastsig);
meillo@0 300 lastsig = 0;
meillo@0 301 }
meillo@0 302 commands();
meillo@0 303 quit(0);
meillo@0 304 /*NOTREACHED*/
meillo@0 305 return 0;
meillo@0 306 }
meillo@0 307
meillo@0 308 static void
meillo@2 309 usage(char c)
meillo@0 310 {
meillo@0 311 if (c) {
meillo@0 312 write(2, progname, strlen(progname));
meillo@2 313 write(2, ": illegal option -- ", 20);
meillo@0 314 write(2, &c, 1);
meillo@0 315 write(2, "\n", 1);
meillo@0 316 }
meillo@0 317 write(2, "usage: ", 7);
meillo@0 318 write(2, progname, strlen(progname));
meillo@2 319 write(2, " [-] [file]\n", 12);
meillo@0 320 exit(2);
meillo@0 321 }
meillo@0 322
meillo@0 323 static void
meillo@0 324 commands(void)
meillo@0 325 {
meillo@0 326 register long *a1;
meillo@0 327 register int c;
meillo@0 328 int n;
meillo@0 329
meillo@0 330 for (;;) {
meillo@0 331 if (pflag) {
meillo@0 332 pflag = 0;
meillo@0 333 addr1 = addr2 = dot;
meillo@0 334 goto print;
meillo@0 335 }
meillo@0 336 if (Pflag && globp == NULL)
meillo@0 337 write(1, prompt, strlen(prompt));
meillo@0 338 addr1 = 0;
meillo@0 339 addr2 = 0;
meillo@0 340 switch (c = getchr()) {
meillo@0 341 case ',':
meillo@0 342 case ';':
meillo@0 343 addr2 = c == ',' ? zero+1 : dot;
meillo@0 344 if (((peekc = getchr()) < '0' || peekc > '9') &&
meillo@0 345 peekc != ' ' && peekc != '\t' &&
meillo@0 346 peekc != '+' && peekc != '-' &&
meillo@0 347 peekc != '^' && peekc != '?' &&
meillo@0 348 peekc != '/' && peekc != '$' &&
meillo@0 349 peekc != '.' && peekc != '\'') {
meillo@0 350 addr1 = addr2;
meillo@0 351 a1 = dol;
meillo@0 352 goto loop;
meillo@0 353 }
meillo@0 354 break;
meillo@0 355 default:
meillo@0 356 peekc = c;
meillo@0 357 }
meillo@0 358 do {
meillo@0 359 addr1 = addr2;
meillo@0 360 if ((a1 = address())==0) {
meillo@0 361 c = getchr();
meillo@0 362 break;
meillo@0 363 }
meillo@0 364 loop: addr2 = a1;
meillo@0 365 if ((c=getchr()) == ';') {
meillo@0 366 c = ',';
meillo@0 367 dot = a1;
meillo@0 368 }
meillo@0 369 } while (c==',');
meillo@0 370 if (addr1==0)
meillo@0 371 addr1 = addr2;
meillo@0 372 switch(c) {
meillo@0 373
meillo@0 374 case 'a':
meillo@0 375 setdot();
meillo@0 376 newline();
meillo@0 377 checkpoint();
meillo@0 378 append(gettty, addr2);
meillo@0 379 continue;
meillo@0 380
meillo@0 381 case 'c':
meillo@0 382 if (addr1 == zero && addr1+1 <= dol) {
meillo@0 383 if (addr1 == addr2)
meillo@0 384 addr2++;
meillo@0 385 addr1++;
meillo@0 386 }
meillo@0 387 delete();
meillo@0 388 append(gettty, addr1-1);
meillo@0 389 if (dot == addr1-1 && addr1 <= dol)
meillo@0 390 dot = addr1;
meillo@0 391 continue;
meillo@0 392
meillo@0 393 case 'd':
meillo@0 394 delete();
meillo@0 395 continue;
meillo@0 396
meillo@0 397 case 'E':
meillo@0 398 fchange = 0;
meillo@0 399 c = 'e';
meillo@0 400 case 'e':
meillo@0 401 setnoaddr();
meillo@0 402 if (vflag && fchange) {
meillo@0 403 fchange = 0;
meillo@0 404 error("warning: expecting `w'");
meillo@0 405 }
meillo@0 406 filename(c);
meillo@0 407 init();
meillo@0 408 addr2 = zero;
meillo@0 409 goto caseread;
meillo@0 410
meillo@0 411 case 'f':
meillo@0 412 setnoaddr();
meillo@0 413 filename(c);
meillo@0 414 puts(savedfile);
meillo@0 415 continue;
meillo@0 416
meillo@0 417 case 'g':
meillo@0 418 global(1, 0);
meillo@0 419 continue;
meillo@0 420
meillo@0 421 case 'G':
meillo@0 422 global(1, 1);
meillo@0 423 continue;
meillo@0 424
meillo@0 425 case 'H':
meillo@0 426 prhelp = !prhelp;
meillo@0 427 /*FALLTHRU*/
meillo@0 428
meillo@0 429 case 'h':
meillo@0 430 if ((peekc = getchr()) == 'e') {
meillo@0 431 peekc = 0;
meillo@0 432 if (getchr() != 'l' || getchr() != 'p' ||
meillo@0 433 getchr() != '\n')
meillo@0 434 error("illegal suffix");
meillo@0 435 setnoaddr();
meillo@0 436 help();
meillo@0 437 continue;
meillo@0 438 }
meillo@0 439 newline();
meillo@0 440 setnoaddr();
meillo@0 441 if (prvmsg)
meillo@0 442 puts(prvmsg);
meillo@0 443 continue;
meillo@0 444
meillo@0 445 case 'i':
meillo@0 446 setdot();
meillo@0 447 if (addr1 == zero) {
meillo@0 448 if (addr1 == addr2)
meillo@0 449 addr2++;
meillo@0 450 addr1++;
meillo@0 451 if (dol != zero)
meillo@0 452 nonzero();
meillo@0 453 } else
meillo@0 454 nonzero();
meillo@0 455 newline();
meillo@0 456 checkpoint();
meillo@0 457 append(gettty, addr2-1);
meillo@0 458 if (dot == addr2-1)
meillo@0 459 dot++;
meillo@0 460 continue;
meillo@0 461
meillo@0 462
meillo@0 463 case 'j':
meillo@0 464 if (addr2==0) {
meillo@0 465 addr1 = dot;
meillo@0 466 addr2 = dot+1;
meillo@0 467 }
meillo@0 468 setdot();
meillo@0 469 newline();
meillo@0 470 nonzero();
meillo@0 471 checkpoint();
meillo@0 472 if (addr1 != addr2)
meillo@0 473 join();
meillo@0 474 continue;
meillo@0 475
meillo@0 476 case 'k':
meillo@0 477 if ((c = getchr()) < 'a' || c > 'z')
meillo@0 478 error("mark not lower case");
meillo@0 479 newline();
meillo@0 480 setdot();
meillo@0 481 nonzero();
meillo@0 482 names[c-'a'] = *addr2 & ~01;
meillo@0 483 anymarks |= 01;
meillo@0 484 continue;
meillo@0 485
meillo@0 486 case 'm':
meillo@0 487 move(0);
meillo@0 488 continue;
meillo@0 489
meillo@0 490 case '\n':
meillo@0 491 if (addr2==0)
meillo@0 492 addr2 = dot+1;
meillo@0 493 addr1 = addr2;
meillo@0 494 goto print;
meillo@0 495
meillo@0 496 case 'n':
meillo@0 497 numbf = 1;
meillo@0 498 newline();
meillo@0 499 goto print;
meillo@0 500
meillo@0 501 case 'N':
meillo@0 502 newline();
meillo@0 503 setnoaddr();
meillo@0 504 Nflag = !Nflag;
meillo@0 505 continue;
meillo@0 506
meillo@0 507 case 'b':
meillo@0 508 case 'o':
meillo@0 509 n = getnum();
meillo@0 510 newline();
meillo@0 511 setdot();
meillo@0 512 nonzero();
meillo@0 513 if (n >= 0) {
meillo@0 514 if (c == 'b')
meillo@0 515 bcount = n;
meillo@0 516 else
meillo@0 517 ocount = n;
meillo@0 518 }
meillo@0 519 if (c == 'b') {
meillo@0 520 a1 = addr2+bcount > dol ? dol : addr2 + bcount;
meillo@0 521 doprnt(addr1, a1);
meillo@0 522 dot = a1;
meillo@0 523 } else {
meillo@0 524 a1 = addr2+ocount > dol ? dol : addr2 + ocount;
meillo@0 525 doprnt(addr2-ocount<zero+1?zero+1:addr2-ocount, a1);
meillo@0 526 dot = addr2;
meillo@0 527 }
meillo@0 528 continue;
meillo@0 529
meillo@0 530 case 'l':
meillo@0 531 listf++;
meillo@0 532 case 'p':
meillo@0 533 newline();
meillo@0 534 print:
meillo@0 535 setdot();
meillo@0 536 nonzero();
meillo@0 537 doprnt(addr1, addr2);
meillo@0 538 dot = addr2;
meillo@0 539 continue;
meillo@0 540
meillo@0 541 case 'P':
meillo@0 542 setnoaddr();
meillo@0 543 newline();
meillo@0 544 Pflag = !Pflag;
meillo@0 545 continue;
meillo@0 546
meillo@0 547 case 'Q':
meillo@0 548 fchange = 0;
meillo@0 549 case 'q':
meillo@0 550 setnoaddr();
meillo@0 551 newline();
meillo@0 552 quit(0);
meillo@0 553
meillo@0 554 case 'r':
meillo@0 555 filename(c);
meillo@0 556 caseread:
meillo@0 557 if ((io = sopen(file, READ)) < 0) {
meillo@0 558 lastc = '\n';
meillo@0 559 error2("cannot open input file", file);
meillo@0 560 }
meillo@0 561 ioeof = 0;
meillo@0 562 setall();
meillo@0 563 ninbuf = 0;
meillo@0 564 if (c == 'r')
meillo@0 565 checkpoint();
meillo@0 566 n = zero != dol;
meillo@0 567 rspec = (c == 'e' || !n) && file[0] != '!';
meillo@0 568 append(getfile, addr2);
meillo@0 569 rspec = 0;
meillo@0 570 exfile();
meillo@0 571 fchange = n;
meillo@0 572 continue;
meillo@0 573
meillo@0 574 case 's':
meillo@0 575 setdot();
meillo@0 576 nonzero();
meillo@0 577 substitute(globp!=0);
meillo@0 578 continue;
meillo@0 579
meillo@0 580 case 't':
meillo@0 581 move(1);
meillo@0 582 continue;
meillo@0 583
meillo@0 584 case 'u':
meillo@0 585 setdot();
meillo@0 586 newline();
meillo@0 587 if (unddot == NULL)
meillo@0 588 error("nothing to undo");
meillo@0 589 undo();
meillo@0 590 continue;
meillo@0 591
meillo@0 592 case 'v':
meillo@0 593 global(0, 0);
meillo@0 594 continue;
meillo@0 595
meillo@0 596 case 'V':
meillo@0 597 global(0, 1);
meillo@0 598 continue;
meillo@0 599
meillo@0 600 case 'W':
meillo@0 601 wrapp++;
meillo@0 602 case 'w':
meillo@0 603 write:
meillo@0 604 setall();
meillo@0 605 if (zero != dol)
meillo@0 606 nonzero();
meillo@0 607 filename(c);
meillo@0 608 if(!wrapp ||
meillo@0 609 ((io = open(file,O_WRONLY|O_APPEND)) == -1) ||
meillo@0 610 ((lseek(io, 0, SEEK_END)) == -1)) {
meillo@0 611 struct stat st;
meillo@0 612 if (lstat(file, &st) == 0 &&
meillo@0 613 (st.st_mode&S_IFMT) == S_IFREG &&
meillo@0 614 st.st_nlink == 1 &&
meillo@0 615 (myuid==0 || myuid==st.st_uid)) {
meillo@0 616 char *cp, *tp;
meillo@0 617 int nio;
meillo@0 618 if ((io = sopen(file, EXIST)) < 0)
meillo@0 619 error("cannot create output file");
meillo@0 620 if ((wrtemp = malloc(strlen(file)+8)) == NULL)
meillo@0 621 error("out of memory");
meillo@0 622 for (cp = file, tp = wrtemp; *cp; cp++)
meillo@0 623 *tp++ = *cp;
meillo@0 624 while (tp > wrtemp && tp[-1] != '/')
meillo@0 625 tp--;
meillo@0 626 for (cp = "\7XXXXXX"; *cp; cp++)
meillo@0 627 *tp++ = *cp;
meillo@0 628 *tp = '\0';
meillo@0 629 if ((nio = mkstemp(wrtemp)) < 0) {
meillo@0 630 free(wrtemp);
meillo@0 631 wrtemp = NULL;
meillo@0 632 ftruncate(io, 0);
meillo@0 633 } else {
meillo@0 634 close(io);
meillo@0 635 io = nio;
meillo@0 636 }
meillo@0 637 } else {
meillo@0 638 if ((io = sopen(file, WRITE)) < 0)
meillo@0 639 error("cannot create output file");
meillo@0 640 }
meillo@0 641 }
meillo@0 642 if (zero != dol) {
meillo@0 643 ioeof = 0;
meillo@0 644 wrapp = 0;
meillo@0 645 putfile();
meillo@0 646 }
meillo@0 647 exfile();
meillo@0 648 if (addr1==zero+1 && addr2==dol || addr1==addr2 && dol==zero)
meillo@0 649 fchange = 0;
meillo@0 650 if (c == 'z')
meillo@0 651 quit(0);
meillo@0 652 continue;
meillo@0 653
meillo@0 654 case 'z':
meillo@0 655 if ((peekc=getchr()) != '\n')
meillo@0 656 error("illegal suffix");
meillo@0 657 setnoaddr();
meillo@0 658 goto write;
meillo@0 659
meillo@0 660 case '=':
meillo@0 661 setall();
meillo@0 662 newline();
meillo@0 663 putd((addr2-zero)&MAXCNT);
meillo@0 664 putchr('\n');
meillo@0 665 continue;
meillo@0 666
meillo@0 667 case '!':
meillo@0 668 callunix();
meillo@0 669 continue;
meillo@0 670
meillo@0 671 case EOF:
meillo@0 672 return;
meillo@0 673
meillo@0 674 }
meillo@0 675 error("unknown command");
meillo@0 676 }
meillo@0 677 }
meillo@0 678
meillo@0 679 static long *
meillo@0 680 address(void)
meillo@0 681 {
meillo@0 682 register long *a1;
meillo@0 683 register int minus, c;
meillo@0 684 int n, relerr;
meillo@0 685
meillo@0 686 minus = 0;
meillo@0 687 a1 = 0;
meillo@0 688 for (;;) {
meillo@0 689 c = getchr();
meillo@0 690 if ('0'<=c && c<='9') {
meillo@0 691 n = 0;
meillo@0 692 do {
meillo@0 693 n *= 10;
meillo@0 694 n += c - '0';
meillo@0 695 } while ((c = getchr())>='0' && c<='9');
meillo@0 696 peekc = c;
meillo@0 697 if (a1==0)
meillo@0 698 a1 = zero;
meillo@0 699 if (minus<0)
meillo@0 700 n = -n;
meillo@0 701 a1 += n;
meillo@0 702 minus = 0;
meillo@0 703 continue;
meillo@0 704 }
meillo@0 705 relerr = 0;
meillo@0 706 if (a1 || minus)
meillo@0 707 relerr++;
meillo@0 708 switch(c) {
meillo@0 709 case ' ':
meillo@0 710 case '\t':
meillo@0 711 continue;
meillo@0 712
meillo@0 713 case '+':
meillo@0 714 minus++;
meillo@0 715 if (a1==0)
meillo@0 716 a1 = dot;
meillo@0 717 continue;
meillo@0 718
meillo@0 719 case '-':
meillo@0 720 case '^':
meillo@0 721 minus--;
meillo@0 722 if (a1==0)
meillo@0 723 a1 = dot;
meillo@0 724 continue;
meillo@0 725
meillo@0 726 case '?':
meillo@0 727 case '/':
meillo@0 728 compile(NULL, expbuf, &expbuf[ESIZE], c);
meillo@0 729 a1 = dot;
meillo@0 730 for (;;) {
meillo@0 731 if (c=='/') {
meillo@0 732 a1++;
meillo@0 733 if (a1 > dol)
meillo@0 734 a1 = zero;
meillo@0 735 } else {
meillo@0 736 a1--;
meillo@0 737 if (a1 < zero)
meillo@0 738 a1 = dol;
meillo@0 739 }
meillo@0 740 if (execute(0, a1, 0))
meillo@0 741 break;
meillo@0 742 if (a1==dot)
meillo@0 743 error("search string not found");
meillo@0 744 }
meillo@0 745 break;
meillo@0 746
meillo@0 747 case '$':
meillo@0 748 a1 = dol;
meillo@0 749 break;
meillo@0 750
meillo@0 751 case '.':
meillo@0 752 a1 = dot;
meillo@0 753 break;
meillo@0 754
meillo@0 755 case '\'':
meillo@0 756 if ((c = getchr()) < 'a' || c > 'z')
meillo@0 757 error("mark not lower case");
meillo@0 758 for (a1=zero; a1<=dol; a1++)
meillo@0 759 if (names[c-'a'] == (*a1 & ~01))
meillo@0 760 break;
meillo@0 761 break;
meillo@0 762
meillo@0 763 default:
meillo@0 764 peekc = c;
meillo@0 765 if (a1==0)
meillo@0 766 return(0);
meillo@0 767 a1 += minus;
meillo@0 768 if (a1<zero || a1>dol)
meillo@0 769 error("line out of range");
meillo@0 770 return(a1);
meillo@0 771 }
meillo@0 772 if (relerr)
meillo@0 773 error("bad number");
meillo@0 774 }
meillo@0 775 }
meillo@0 776
meillo@0 777 static void
meillo@0 778 setdot(void)
meillo@0 779 {
meillo@0 780 if (addr2 == 0)
meillo@0 781 addr1 = addr2 = dot;
meillo@0 782 if (addr1 > addr2)
meillo@0 783 error("bad range");
meillo@0 784 }
meillo@0 785
meillo@0 786 static void
meillo@0 787 setall(void)
meillo@0 788 {
meillo@0 789 if (addr2==0) {
meillo@0 790 addr1 = zero+1;
meillo@0 791 addr2 = dol;
meillo@0 792 if (dol==zero)
meillo@0 793 addr1 = zero;
meillo@0 794 }
meillo@0 795 setdot();
meillo@0 796 }
meillo@0 797
meillo@0 798 static void
meillo@0 799 setnoaddr(void)
meillo@0 800 {
meillo@0 801 if (addr2)
meillo@0 802 error("Illegal address count");
meillo@0 803 }
meillo@0 804
meillo@0 805 static void
meillo@0 806 nonzero(void)
meillo@0 807 {
meillo@0 808 if (addr1<=zero || addr2>dol)
meillo@0 809 error("line out of range");
meillo@0 810 }
meillo@0 811
meillo@0 812 static void
meillo@0 813 newline(void)
meillo@0 814 {
meillo@0 815 register int c;
meillo@0 816
meillo@0 817 if ((c = getchr()) == '\n')
meillo@0 818 return;
meillo@0 819 if (c=='p' || c=='l' || c=='n') {
meillo@0 820 pflag++;
meillo@0 821 if (c=='l')
meillo@0 822 listf++;
meillo@0 823 else if (c=='n')
meillo@0 824 numbf = 1;
meillo@0 825 if (getchr() == '\n')
meillo@0 826 return;
meillo@0 827 }
meillo@0 828 error("illegal suffix");
meillo@0 829 }
meillo@0 830
meillo@0 831 static void
meillo@0 832 filename(int comm)
meillo@0 833 {
meillo@0 834 register char *p1, *p2;
meillo@0 835 register int c, i;
meillo@0 836
meillo@0 837 count = 0;
meillo@0 838 c = getchr();
meillo@0 839 if (c=='\n' || c==EOF) {
meillo@0 840 p1 = savedfile;
meillo@0 841 if (*p1==0 && comm!='f')
meillo@0 842 error("illegal or missing filename");
meillo@0 843 p2 = file;
meillo@0 844 while (*p2++ = *p1++)
meillo@0 845 ;
meillo@0 846 return;
meillo@0 847 }
meillo@0 848 if (c!=' ')
meillo@0 849 error("no space after command");
meillo@0 850 while ((c = getchr()) == ' ')
meillo@0 851 ;
meillo@0 852 if (c=='\n')
meillo@0 853 error("illegal or missing filename");
meillo@0 854 i = 0;
meillo@0 855 do {
meillo@0 856 if (i >= FNSIZE)
meillo@0 857 growfn("maximum of characters in file names reached");
meillo@0 858 file[i++] = c;
meillo@0 859 if (c==' ' && file[0] != '!' || c==EOF)
meillo@0 860 error("illegal or missing filename");
meillo@0 861 } while ((c = getchr()) != '\n');
meillo@0 862 file[i++] = 0;
meillo@0 863 if ((savedfile[0]==0 || comm=='e' || comm=='f') && file[0] != '!') {
meillo@0 864 p1 = savedfile;
meillo@0 865 p2 = file;
meillo@0 866 while (*p1++ = *p2++)
meillo@0 867 ;
meillo@0 868 }
meillo@0 869 }
meillo@0 870
meillo@0 871 static void
meillo@0 872 exfile(void)
meillo@0 873 {
meillo@0 874 sclose(io);
meillo@0 875 io = -1;
meillo@0 876 if (wrtemp) {
meillo@0 877 extern int rename(const char *, const char *);
meillo@0 878 if (rename(wrtemp, file) < 0)
meillo@0 879 error("cannot create output file");
meillo@0 880 if (myuid == 0)
meillo@0 881 chown(file, fstbuf.st_uid, fstbuf.st_gid);
meillo@0 882 chmod(file, fstbuf.st_mode & 07777);
meillo@0 883 free(wrtemp);
meillo@0 884 wrtemp = NULL;
meillo@0 885 }
meillo@0 886 if (vflag) {
meillo@0 887 putd(count);
meillo@0 888 putchr('\n');
meillo@0 889 }
meillo@0 890 }
meillo@0 891
meillo@0 892 static void
meillo@0 893 onintr(int signo)
meillo@0 894 {
meillo@0 895 lastsig = signo;
meillo@0 896 putchr('\n');
meillo@0 897 lastc = '\n';
meillo@0 898 if (readop) {
meillo@0 899 puts("\007read may be incomplete - beware!\007");
meillo@0 900 fchange = 0;
meillo@0 901 }
meillo@0 902 error("interrupt");
meillo@0 903 }
meillo@0 904
meillo@0 905 static void
meillo@0 906 onhup(int signo)
meillo@0 907 {
meillo@0 908 if (dol > zero && fchange) {
meillo@0 909 addr1 = zero+1;
meillo@0 910 addr2 = dol;
meillo@0 911 io = creat("ed.hup", 0666);
meillo@0 912 if (io < 0) {
meillo@0 913 char *home = getenv("HOME");
meillo@0 914 if (home) {
meillo@0 915 char *fn = malloc(strlen(home) + 10);
meillo@0 916 if (fn) {
meillo@0 917 strcpy(fn, home);
meillo@0 918 strcat(fn, "/ed.hup");
meillo@0 919 io = creat(fn, 0666);
meillo@0 920 }
meillo@0 921 }
meillo@0 922 }
meillo@0 923 if (io >= 0)
meillo@0 924 putfile();
meillo@0 925 }
meillo@0 926 fchange = 0;
meillo@0 927 status = 0200 | signo;
meillo@0 928 quit(0);
meillo@0 929 }
meillo@0 930
meillo@0 931 static void
meillo@0 932 onpipe(int signo)
meillo@0 933 {
meillo@0 934 lastsig = signo;
meillo@0 935 error("write or open on pipe failed");
meillo@0 936 }
meillo@0 937
meillo@0 938 static void
meillo@0 939 error(const char *s)
meillo@0 940 {
meillo@0 941 error2(s, NULL);
meillo@0 942 }
meillo@0 943
meillo@0 944 static void
meillo@0 945 error2(const char *s, const char *fn)
meillo@0 946 {
meillo@0 947 register int c;
meillo@0 948
meillo@0 949 wrapp = 0;
meillo@0 950 listf = 0;
meillo@0 951 numbf = 0;
meillo@0 952 errput(s, fn);
meillo@0 953 count = 0;
meillo@0 954 if (lseek(0, 0, SEEK_END) > 0)
meillo@0 955 status = 2;
meillo@0 956 pflag = 0;
meillo@0 957 if (globp)
meillo@0 958 lastc = '\n';
meillo@0 959 globp = 0;
meillo@0 960 peekc = lastc;
meillo@0 961 if(lastc)
meillo@0 962 while ((c = getchr()) != '\n' && c != EOF)
meillo@0 963 ;
meillo@0 964 if (io > 0) {
meillo@0 965 sclose(io);
meillo@0 966 io = -1;
meillo@0 967 }
meillo@0 968 if (wrtemp) {
meillo@0 969 unlink(wrtemp);
meillo@0 970 free(wrtemp);
meillo@0 971 wrtemp = NULL;
meillo@0 972 }
meillo@0 973 longjmp(savej, 1);
meillo@0 974 }
meillo@0 975
meillo@0 976 static void
meillo@0 977 errput(const char *s, const char *fn)
meillo@0 978 {
meillo@0 979 prvmsg = s;
meillo@0 980 if (fn) {
meillo@0 981 putchr('?');
meillo@0 982 puts(fn);
meillo@0 983 } else
meillo@0 984 puts("?");
meillo@0 985 if (prhelp)
meillo@0 986 puts(s);
meillo@0 987 }
meillo@0 988
meillo@0 989 static int
meillo@0 990 getchr(void)
meillo@0 991 {
meillo@0 992 char c;
meillo@0 993 if (lastc=peekc) {
meillo@0 994 peekc = 0;
meillo@0 995 return(lastc);
meillo@0 996 }
meillo@0 997 if (globp) {
meillo@0 998 if ((lastc = *globp++) != 0)
meillo@0 999 return(lastc);
meillo@0 1000 globp = 0;
meillo@0 1001 return(EOF);
meillo@0 1002 }
meillo@0 1003 if (read(0, &c, 1) <= 0)
meillo@0 1004 return(lastc = EOF);
meillo@0 1005 lastc = c;
meillo@0 1006 return(lastc);
meillo@0 1007 }
meillo@0 1008
meillo@0 1009 static int
meillo@0 1010 gettty(void)
meillo@0 1011 {
meillo@0 1012 register int c, i;
meillo@0 1013 register char *gf;
meillo@0 1014
meillo@0 1015 i = 0;
meillo@0 1016 gf = globp;
meillo@0 1017 while ((c = getchr()) != '\n') {
meillo@0 1018 if (c==EOF) {
meillo@0 1019 if (gf)
meillo@0 1020 peekc = c;
meillo@0 1021 return(c);
meillo@0 1022 }
meillo@0 1023 if (c == 0)
meillo@0 1024 continue;
meillo@0 1025 if (i >= LBSIZE)
meillo@0 1026 growlb("line too long");
meillo@0 1027 linebuf[i++] = c;
meillo@0 1028 }
meillo@0 1029 if (i >= LBSIZE-2)
meillo@0 1030 growlb("line too long");
meillo@0 1031 linebuf[i++] = 0;
meillo@0 1032 if (linebuf[0]=='.' && linebuf[1]==0)
meillo@0 1033 return(EOF);
meillo@0 1034 return(0);
meillo@0 1035 }
meillo@0 1036
meillo@0 1037 static long
meillo@0 1038 getnum(void)
meillo@0 1039 {
meillo@0 1040 char scount[20];
meillo@0 1041 int i;
meillo@0 1042
meillo@0 1043 i = 0;
meillo@0 1044 while ((peekc=getchr()) >= '0' && peekc <= '9' && i < sizeof scount) {
meillo@0 1045 scount[i++] = peekc;
meillo@0 1046 peekc = 0;
meillo@0 1047 }
meillo@0 1048 scount[i] = '\0';
meillo@0 1049 return i ? atol(scount) : -1;
meillo@0 1050 }
meillo@0 1051
meillo@0 1052 static int
meillo@0 1053 getfile(void)
meillo@0 1054 {
meillo@0 1055 register int c, i, j;
meillo@0 1056 static int nextj;
meillo@0 1057
meillo@0 1058 i = 0;
meillo@0 1059 j = nextj;
meillo@0 1060 do {
meillo@0 1061 if (--ninbuf < 0) {
meillo@0 1062 if (ioeof || (ninbuf=read(io, genbuf, LBSIZE)-1) < 0) {
meillo@0 1063 if (ioeof == 0 && ninbuf < -1) {
meillo@0 1064 puts("input error");
meillo@0 1065 status = 1;
meillo@0 1066 }
meillo@0 1067 if (i > 0) {
meillo@0 1068 puts("'\\n' appended");
meillo@0 1069 c = '\n';
meillo@0 1070 ioeof = 1;
meillo@0 1071 goto wrc;
meillo@0 1072 }
meillo@0 1073 return(EOF);
meillo@0 1074 }
meillo@0 1075 j = 0;
meillo@0 1076 }
meillo@0 1077 c = genbuf[j++]&0377;
meillo@0 1078 wrc: if (i >= LBSIZE) {
meillo@0 1079 lastc = '\n';
meillo@0 1080 growlb("line too long");
meillo@0 1081 }
meillo@0 1082 linebuf[i++] = c ? c : '\n';
meillo@0 1083 count++;
meillo@0 1084 } while (c != '\n');
meillo@0 1085 linebuf[--i] = 0;
meillo@0 1086 nextj = j;
meillo@0 1087 if (maxlength && i > maxlength) {
meillo@0 1088 putstr("line too long: lno = ");
meillo@0 1089 putd((dot - zero+1)&MAXCNT);
meillo@0 1090 putchr('\n');
meillo@0 1091 }
meillo@0 1092 return(0);
meillo@0 1093 }
meillo@0 1094
meillo@0 1095 static void
meillo@0 1096 putfile(void)
meillo@0 1097 {
meillo@0 1098 long *a1;
meillo@0 1099 int n;
meillo@0 1100 register char *fp, *lp;
meillo@0 1101 register int nib;
meillo@0 1102
meillo@0 1103 nib = 512;
meillo@0 1104 fp = genbuf;
meillo@0 1105 a1 = addr1;
meillo@0 1106 do {
meillo@0 1107 lp = getline(*a1++, 0);
meillo@0 1108 if (maxlength) {
meillo@0 1109 for (n = 0; lp[n]; n++);
meillo@0 1110 if (n > maxlength) {
meillo@0 1111 putstr("line too long: lno = ");
meillo@0 1112 putd((a1-1 - zero)&MAXCNT);
meillo@0 1113 putchr('\n');
meillo@0 1114 }
meillo@0 1115 }
meillo@0 1116 for (;;) {
meillo@0 1117 if (--nib < 0) {
meillo@0 1118 n = fp-genbuf;
meillo@0 1119 if(write(io, genbuf, n) != n)
meillo@0 1120 error("write error");
meillo@0 1121 nib = 511;
meillo@0 1122 fp = genbuf;
meillo@0 1123 }
meillo@0 1124 count++;
meillo@0 1125 if ((*fp++ = *lp++) == 0) {
meillo@0 1126 fp[-1] = '\n';
meillo@0 1127 break;
meillo@0 1128 } else if (fp[-1] == '\n')
meillo@0 1129 fp[-1] = '\0';
meillo@0 1130 }
meillo@0 1131 } while (a1 <= addr2);
meillo@0 1132 n = fp-genbuf;
meillo@0 1133 if(write(io, genbuf, n) != n)
meillo@0 1134 error("write error");
meillo@0 1135 }
meillo@0 1136
meillo@0 1137 static int
meillo@0 1138 append(int (*f)(void), long *a)
meillo@0 1139 {
meillo@0 1140 register long *a1, *a2, *rdot;
meillo@0 1141 int nline, tl;
meillo@0 1142
meillo@0 1143 nline = 0;
meillo@0 1144 dot = a;
meillo@0 1145 while ((*f)() == 0) {
meillo@0 1146 if ((dol-zero)+1 >= nlall) {
meillo@0 1147 long *ozero = zero;
meillo@0 1148 nlall += 512;
meillo@0 1149 if ((zero = realloc(zero, nlall*sizeof *zero))==NULL) {
meillo@0 1150 lastc = '\n';
meillo@0 1151 zero = ozero;
meillo@0 1152 error("out of memory for append");
meillo@0 1153 }
meillo@0 1154 dot += zero - ozero;
meillo@0 1155 dol += zero - ozero;
meillo@0 1156 addr1 += zero - ozero;
meillo@0 1157 addr2 += zero - ozero;
meillo@0 1158 if (unddot) {
meillo@0 1159 unddot += zero - ozero;
meillo@0 1160 unddol += zero - ozero;
meillo@0 1161 }
meillo@0 1162 if (undzero) {
meillo@0 1163 ozero = undzero;
meillo@0 1164 if ((undzero = realloc(undzero,
meillo@0 1165 nlall*sizeof *undzero)) == 0) {
meillo@0 1166 puts("no memory for undo");
meillo@0 1167 free(ozero);
meillo@0 1168 }
meillo@0 1169 }
meillo@0 1170 }
meillo@0 1171 tl = putline();
meillo@0 1172 nline++;
meillo@0 1173 a1 = ++dol;
meillo@0 1174 a2 = a1+1;
meillo@0 1175 rdot = ++dot;
meillo@0 1176 while (a1 > rdot)
meillo@0 1177 *--a2 = *--a1;
meillo@0 1178 *rdot = tl;
meillo@0 1179 }
meillo@0 1180 return(nline);
meillo@0 1181 }
meillo@0 1182
meillo@0 1183 static void
meillo@0 1184 callunix(void)
meillo@0 1185 {
meillo@0 1186 char *line;
meillo@0 1187 void (*savint)(int);
meillo@0 1188 pid_t pid, rpid;
meillo@0 1189 int retcode;
meillo@0 1190
meillo@0 1191 setnoaddr();
meillo@0 1192 line = readcmd();
meillo@0 1193 if ((pid = fork()) == 0) {
meillo@0 1194 sigset(SIGHUP, oldhup);
meillo@0 1195 sigset(SIGQUIT, oldquit);
meillo@0 1196 sigset(SIGPIPE, oldpipe);
meillo@0 1197 execl(SHELL, "sh", "-c", line, NULL);
meillo@0 1198 _exit(0100);
meillo@0 1199 } else if (pid < 0)
meillo@0 1200 error("fork failed - try again");
meillo@0 1201 savint = sigset(SIGINT, SIG_IGN);
meillo@0 1202 while ((rpid = wait(&retcode)) != pid && rpid != -1)
meillo@0 1203 ;
meillo@0 1204 sigset(SIGINT, savint);
meillo@0 1205 if (vflag)
meillo@0 1206 puts("!");
meillo@0 1207 }
meillo@0 1208
meillo@0 1209 #define cmadd(c) ((i>=cmsize ? \
meillo@0 1210 ((line=realloc(line,cmsize+=128)) == 0 ? \
meillo@0 1211 (error("line too long"),0) : 0, 0) \
meillo@0 1212 : 0), line[i++]=(c))
meillo@0 1213
meillo@0 1214 static char *
meillo@0 1215 readcmd(void)
meillo@0 1216 {
meillo@0 1217 static char *line, *prev;
meillo@0 1218 static int cmsize, pvsize;
meillo@0 1219 char *pp;
meillo@0 1220 int c, mod = 0, i;
meillo@0 1221
meillo@0 1222 i = 0;
meillo@0 1223 if ((c = getchr()) == '!') {
meillo@0 1224 for (pp = prev; *pp; pp++)
meillo@0 1225 line[i++] = *pp;
meillo@0 1226 mod = 1;
meillo@0 1227 c = getchr();
meillo@0 1228 }
meillo@0 1229 while (c != '\n' && c != EOF) {
meillo@0 1230 if (c == '\\') {
meillo@0 1231 c = getchr();
meillo@0 1232 if (c != '%')
meillo@0 1233 cmadd('\\');
meillo@0 1234 cmadd(c);
meillo@0 1235 } else if (c == '%') {
meillo@0 1236 for (pp = savedfile; *pp; pp++)
meillo@0 1237 cmadd(*pp);
meillo@0 1238 mod = 1;
meillo@0 1239 } else
meillo@0 1240 cmadd(c);
meillo@0 1241 c = getchr();
meillo@0 1242 }
meillo@0 1243 cmadd('\0');
meillo@0 1244 if (pvsize < cmsize && (prev = realloc(prev, pvsize=cmsize)) == 0)
meillo@0 1245 error("line too long");
meillo@0 1246 strcpy(prev, line);
meillo@0 1247 if (mod)
meillo@0 1248 nlputs(line);
meillo@0 1249 return line;
meillo@0 1250 }
meillo@0 1251
meillo@0 1252 static void
meillo@0 1253 quit(int signo)
meillo@0 1254 {
meillo@0 1255 lastsig = signo;
meillo@0 1256 if (vflag && fchange) {
meillo@0 1257 fchange = 0;
meillo@0 1258 error("warning: expecting `w'");
meillo@0 1259 }
meillo@0 1260 if (wrtemp)
meillo@0 1261 unlink(wrtemp);
meillo@0 1262 unlink(tfname);
meillo@0 1263 exit(status);
meillo@0 1264 }
meillo@0 1265
meillo@0 1266 static void
meillo@0 1267 delete(void)
meillo@0 1268 {
meillo@0 1269 setdot();
meillo@0 1270 newline();
meillo@0 1271 nonzero();
meillo@0 1272 checkpoint();
meillo@0 1273 rdelete(addr1, addr2);
meillo@0 1274 }
meillo@0 1275
meillo@0 1276 static void
meillo@0 1277 rdelete(long *ad1, long *ad2)
meillo@0 1278 {
meillo@0 1279 register long *a1, *a2, *a3;
meillo@0 1280
meillo@0 1281 a1 = ad1;
meillo@0 1282 a2 = ad2+1;
meillo@0 1283 a3 = dol;
meillo@0 1284 dol -= a2 - a1;
meillo@0 1285 do {
meillo@0 1286 *a1++ = *a2++;
meillo@0 1287 } while (a2 <= a3);
meillo@0 1288 a1 = ad1;
meillo@0 1289 if (a1 > dol)
meillo@0 1290 a1 = dol;
meillo@0 1291 dot = a1;
meillo@0 1292 fchange = 1;
meillo@0 1293 }
meillo@0 1294
meillo@0 1295 static void
meillo@0 1296 gdelete(void)
meillo@0 1297 {
meillo@0 1298 register long *a1, *a2, *a3;
meillo@0 1299
meillo@0 1300 a3 = dol;
meillo@0 1301 for (a1=zero+1; (*a1&01)==0; a1++)
meillo@0 1302 if (a1>=a3)
meillo@0 1303 return;
meillo@0 1304 for (a2=a1+1; a2<=a3;) {
meillo@0 1305 if (*a2&01) {
meillo@0 1306 a2++;
meillo@0 1307 dot = a1;
meillo@0 1308 } else
meillo@0 1309 *a1++ = *a2++;
meillo@0 1310 }
meillo@0 1311 dol = a1-1;
meillo@0 1312 if (dot>dol)
meillo@0 1313 dot = dol;
meillo@0 1314 fchange = 1;
meillo@0 1315 }
meillo@0 1316
meillo@0 1317 static char *
meillo@0 1318 getline(long tl, int nulterm)
meillo@0 1319 {
meillo@0 1320 register char *bp, *lp;
meillo@0 1321 register long nl;
meillo@0 1322
meillo@0 1323 lp = linebuf;
meillo@0 1324 bp = getblock(tl, READ);
meillo@0 1325 nl = nleft;
meillo@0 1326 tl &= ~0377;
meillo@0 1327 while (*lp++ = *bp++) {
meillo@0 1328 if (lp[-1] == '\n' && nulterm) {
meillo@0 1329 lp[-1] = '\0';
meillo@0 1330 break;
meillo@0 1331 }
meillo@0 1332 if (--nl == 0) {
meillo@0 1333 bp = getblock(tl+=0400, READ);
meillo@0 1334 nl = nleft;
meillo@0 1335 }
meillo@0 1336 }
meillo@0 1337 return(linebuf);
meillo@0 1338 }
meillo@0 1339
meillo@0 1340 static int
meillo@0 1341 putline(void)
meillo@0 1342 {
meillo@0 1343 register char *bp, *lp;
meillo@0 1344 register long nl;
meillo@0 1345 long tl;
meillo@0 1346
meillo@0 1347 fchange = 1;
meillo@0 1348 lp = linebuf;
meillo@0 1349 tl = tline;
meillo@0 1350 bp = getblock(tl, WRITE);
meillo@0 1351 nl = nleft;
meillo@0 1352 tl &= ~0377;
meillo@0 1353 while (*bp = *lp++) {
meillo@0 1354 if (*bp++ == '\n' && insub) {
meillo@0 1355 *--bp = 0;
meillo@0 1356 linebp = lp;
meillo@0 1357 break;
meillo@0 1358 }
meillo@0 1359 if (--nl == 0) {
meillo@0 1360 bp = getblock(tl+=0400, WRITE);
meillo@0 1361 nl = nleft;
meillo@0 1362 }
meillo@0 1363 }
meillo@0 1364 nl = tline;
meillo@0 1365 tline += (((lp-linebuf)+03)>>1)&(MAXCNT-1);
meillo@0 1366 return(nl);
meillo@0 1367 }
meillo@0 1368
meillo@0 1369 static char *
meillo@0 1370 getblock(long atl, long iof)
meillo@0 1371 {
meillo@0 1372 register long bno, off;
meillo@0 1373
meillo@0 1374 bno = (atl>>8)&BLKMSK;
meillo@0 1375 off = (atl<<1)&0774;
meillo@0 1376 if (bno >= BLKMSK) {
meillo@0 1377 lastc = '\n';
meillo@0 1378 error("temp file too big");
meillo@0 1379 }
meillo@0 1380 nleft = 512 - off;
meillo@0 1381 if (bno==iblock) {
meillo@0 1382 ichanged |= iof;
meillo@0 1383 return(ibuff+off);
meillo@0 1384 }
meillo@0 1385 if (bno==oblock)
meillo@0 1386 return(obuff+off);
meillo@0 1387 if (iof==READ) {
meillo@0 1388 if (ichanged)
meillo@0 1389 blkio(iblock, ibuff, 1);
meillo@0 1390 ichanged = 0;
meillo@0 1391 iblock = bno;
meillo@0 1392 blkio(bno, ibuff, 0);
meillo@0 1393 return(ibuff+off);
meillo@0 1394 }
meillo@0 1395 if (oblock>=0)
meillo@0 1396 blkio(oblock, obuff, 1);
meillo@0 1397 oblock = bno;
meillo@0 1398 return(obuff+off);
meillo@0 1399 }
meillo@0 1400
meillo@0 1401 static void
meillo@0 1402 blkio(long b, char *buf, int wr)
meillo@0 1403 {
meillo@0 1404 lseek(tfile, b<<9, SEEK_SET);
meillo@0 1405 if ((wr ? write(tfile, buf, 512) : read (tfile, buf, 512)) != 512) {
meillo@0 1406 status = 1;
meillo@0 1407 error("I/O error on temp file");
meillo@0 1408 }
meillo@0 1409 }
meillo@0 1410
meillo@0 1411 static void
meillo@0 1412 init(void)
meillo@0 1413 {
meillo@0 1414 register long *markp;
meillo@0 1415
meillo@0 1416 tline = 2;
meillo@0 1417 for (markp = names; markp < &names[26]; markp++)
meillo@0 1418 *markp = 0;
meillo@0 1419 for (markp = undnames; markp < &undnames[26]; markp++)
meillo@0 1420 *markp = 0;
meillo@0 1421 subnewa = 0;
meillo@0 1422 anymarks = 0;
meillo@0 1423 iblock = -1;
meillo@0 1424 oblock = -1;
meillo@0 1425 ichanged = 0;
meillo@0 1426 tfile = maketf(tfile);
meillo@0 1427 dot = dol = zero;
meillo@0 1428 unddot = NULL;
meillo@0 1429 }
meillo@0 1430
meillo@0 1431 static void
meillo@0 1432 global(int k, int ia)
meillo@0 1433 {
meillo@0 1434 register int c;
meillo@0 1435 register long *a1;
meillo@0 1436 static char *globuf;
meillo@0 1437 char mb[MB_LEN_MAX+1];
meillo@0 1438 int spflag = 0;
meillo@0 1439
meillo@0 1440 if (globp)
meillo@0 1441 error("multiple globals not allowed");
meillo@0 1442 setall();
meillo@0 1443 nonzero();
meillo@0 1444 if ((c=GETWC(mb))=='\n')
meillo@0 1445 error("incomplete global expression");
meillo@0 1446 compile(NULL, expbuf, &expbuf[ESIZE], c);
meillo@0 1447 if (!ia) {
meillo@0 1448 globrd(&globuf, EOF);
meillo@0 1449 if (globuf[0] == '\n')
meillo@0 1450 globuf[0] = 'p', globuf[1] = '\n', globuf[2] = '\0';
meillo@0 1451 } else {
meillo@0 1452 newline();
meillo@0 1453 spflag = pflag;
meillo@0 1454 pflag = 0;
meillo@0 1455 }
meillo@0 1456 checkpoint();
meillo@0 1457 for (a1=zero; a1<=dol; a1++) {
meillo@0 1458 *a1 &= ~01;
meillo@0 1459 if (a1>=addr1 && a1<=addr2 && execute(0, a1, 0)==k)
meillo@0 1460 *a1 |= 01;
meillo@0 1461 }
meillo@0 1462 /*
meillo@0 1463 * Special case: g/.../d (avoid n^2 algorithm)
meillo@0 1464 */
meillo@0 1465 if (!ia && globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
meillo@0 1466 gdelete();
meillo@0 1467 return;
meillo@0 1468 }
meillo@0 1469 for (a1=zero; a1<=dol; a1++) {
meillo@0 1470 if (*a1 & 01) {
meillo@0 1471 *a1 &= ~01;
meillo@0 1472 dot = a1;
meillo@0 1473 if (ia) {
meillo@0 1474 puts(getline(*a1, 0));
meillo@0 1475 if ((c = getchr()) == EOF)
meillo@0 1476 error("command expected");
meillo@0 1477 if (c == 'a' || c == 'c' || c == 'i')
meillo@0 1478 error("a, i, or c not allowed in G");
meillo@0 1479 else if (c == '&') {
meillo@0 1480 if ((c = getchr()) != '\n')
meillo@0 1481 error("end of line expected");
meillo@0 1482 if (globuf == 0 || *globuf == 0)
meillo@0 1483 error("no remembered command");
meillo@0 1484 } else if (c == '\n') {
meillo@0 1485 a1 = zero;
meillo@0 1486 continue;
meillo@0 1487 } else
meillo@0 1488 globrd(&globuf, c);
meillo@0 1489 }
meillo@0 1490 globp = globuf;
meillo@0 1491 commands();
meillo@0 1492 globp = NULL;
meillo@0 1493 a1 = zero;
meillo@0 1494 }
meillo@0 1495 }
meillo@0 1496 if (ia)
meillo@0 1497 pflag = spflag;
meillo@0 1498 }
meillo@0 1499
meillo@0 1500 static void
meillo@0 1501 globrd(char **globuf, register int c)
meillo@0 1502 {
meillo@0 1503 register int i;
meillo@0 1504
meillo@0 1505 if (*globuf == 0 && (*globuf = malloc(GBSIZE=256)) == 0)
meillo@0 1506 error("global too long");
meillo@0 1507 i = 0;
meillo@0 1508 if (c != EOF)
meillo@0 1509 (*globuf)[i++] = c;
meillo@0 1510 while ((c = getchr()) != '\n') {
meillo@0 1511 if (c==EOF)
meillo@0 1512 error("incomplete global expression");
meillo@0 1513 if (c=='\\') {
meillo@0 1514 c = getchr();
meillo@0 1515 if (c!='\n')
meillo@0 1516 (*globuf)[i++] = '\\';
meillo@0 1517 }
meillo@0 1518 (*globuf)[i++] = c;
meillo@0 1519 if (i>=GBSIZE-4 && (*globuf=realloc(*globuf,GBSIZE+=256)) == 0)
meillo@0 1520 error("global too long");
meillo@0 1521 }
meillo@0 1522 (*globuf)[i++] = '\n';
meillo@0 1523 (*globuf)[i++] = 0;
meillo@0 1524 }
meillo@0 1525
meillo@0 1526 static void
meillo@0 1527 join(void)
meillo@0 1528 {
meillo@0 1529 register int i, j;
meillo@0 1530 register long *a1;
meillo@0 1531
meillo@0 1532 j = 0;
meillo@0 1533 for (a1=addr1; a1<=addr2; a1++) {
meillo@0 1534 i = getline(*a1, 0) - linebuf;
meillo@0 1535 while (genbuf[j] = linebuf[i++])
meillo@0 1536 if (j++ >= LBSIZE-2)
meillo@0 1537 growlb("line too long");
meillo@0 1538 }
meillo@0 1539 i = 0;
meillo@0 1540 j = 0;
meillo@0 1541 while (linebuf[i++] = genbuf[j++])
meillo@0 1542 ;
meillo@0 1543 *addr1 = putline();
meillo@0 1544 if (addr1<addr2)
meillo@0 1545 rdelete(addr1+1, addr2);
meillo@0 1546 dot = addr1;
meillo@0 1547 }
meillo@0 1548
meillo@0 1549 static void
meillo@0 1550 substitute(int inglob)
meillo@0 1551 {
meillo@0 1552 register long *markp;
meillo@0 1553 register long *a1;
meillo@0 1554 intptr_t nl;
meillo@0 1555 int gsubf;
meillo@0 1556
meillo@0 1557 checkpoint();
meillo@0 1558 gsubf = compsub();
meillo@0 1559 insub = 1;
meillo@0 1560 for (a1 = addr1; a1 <= addr2; a1++) {
meillo@0 1561 long *ozero;
meillo@0 1562 if (execute(0, a1, 1)==0)
meillo@0 1563 continue;
meillo@0 1564 inglob |= dosub(gsubf < 2);
meillo@0 1565 if (gsubf) {
meillo@0 1566 int i = 1;
meillo@0 1567
meillo@0 1568 while (*loc2) {
meillo@0 1569 if (execute(1, NULL, 1)==0)
meillo@0 1570 break;
meillo@0 1571 inglob |= dosub(gsubf == -1 || ++i == gsubf);
meillo@0 1572 }
meillo@0 1573 }
meillo@0 1574 subnewa = putline();
meillo@0 1575 *a1 &= ~01;
meillo@0 1576 if (anymarks) {
meillo@0 1577 for (markp = names; markp < &names[26]; markp++)
meillo@0 1578 if (*markp == *a1)
meillo@0 1579 *markp = subnewa;
meillo@0 1580 }
meillo@0 1581 *a1 = subnewa;
meillo@0 1582 ozero = zero;
meillo@0 1583 nl = append(getsub, a1);
meillo@0 1584 nl += zero-ozero;
meillo@0 1585 a1 += nl;
meillo@0 1586 addr2 += nl;
meillo@0 1587 }
meillo@0 1588 insub = 0;
meillo@0 1589 if (inglob==0)
meillo@0 1590 error("no match");
meillo@0 1591 }
meillo@0 1592
meillo@0 1593 static int
meillo@0 1594 compsub(void)
meillo@0 1595 {
meillo@0 1596 register int seof, c, i;
meillo@0 1597 static char *oldrhs;
meillo@0 1598 static int orhssz;
meillo@0 1599 char mb[MB_LEN_MAX+1];
meillo@0 1600
meillo@0 1601 if ((seof = GETWC(mb)) == '\n' || seof == ' ')
meillo@0 1602 error("illegal or missing delimiter");
meillo@0 1603 nodelim = 0;
meillo@0 1604 compile(NULL, expbuf, &expbuf[ESIZE], seof);
meillo@0 1605 i = 0;
meillo@0 1606 for (;;) {
meillo@0 1607 c = GETWC(mb);
meillo@0 1608 if (c=='\\') {
meillo@0 1609 if (i >= RHSIZE-2)
meillo@0 1610 growrhs("replacement string too long");
meillo@0 1611 rhsbuf[i++] = c;
meillo@0 1612 c = GETWC(mb);
meillo@0 1613 } else if (c=='\n') {
meillo@0 1614 if (globp && *globp) {
meillo@0 1615 if (i >= RHSIZE-2)
meillo@0 1616 growrhs("replacement string too long");
meillo@0 1617 rhsbuf[i++] = '\\';
meillo@0 1618 }
meillo@0 1619 else if (nodelim)
meillo@0 1620 error("illegal or missing delimiter");
meillo@0 1621 else {
meillo@0 1622 peekc = c;
meillo@0 1623 pflag++;
meillo@0 1624 break;
meillo@0 1625 }
meillo@0 1626 } else if (c==seof)
meillo@0 1627 break;
meillo@0 1628 for (c = 0; c==0 || mb[c]; c++) {
meillo@0 1629 if (i >= RHSIZE-2)
meillo@0 1630 growrhs("replacement string too long");
meillo@0 1631 rhsbuf[i++] = mb[c];
meillo@0 1632 }
meillo@0 1633 }
meillo@0 1634 rhsbuf[i++] = 0;
meillo@0 1635 if (rhsbuf[0] == '%' && rhsbuf[1] == 0) {
meillo@0 1636 if (orhssz == 0)
meillo@0 1637 error("no remembered replacement string");
meillo@0 1638 strcpy(rhsbuf, oldrhs);
meillo@0 1639 } else {
meillo@0 1640 if (orhssz < RHSIZE &&
meillo@0 1641 (oldrhs = realloc(oldrhs, orhssz=RHSIZE)) == 0)
meillo@0 1642 error("replacement string too long");
meillo@0 1643 strcpy(oldrhs, rhsbuf);
meillo@0 1644 }
meillo@0 1645 if ((peekc = getchr()) == 'g') {
meillo@0 1646 peekc = 0;
meillo@0 1647 newline();
meillo@0 1648 return(-1);
meillo@0 1649 } else if (peekc >= '0' && peekc <= '9') {
meillo@0 1650 c = getnum();
meillo@0 1651 if (c < 1 || c > LBSIZE)
meillo@0 1652 error("invalid count");
meillo@0 1653 newline();
meillo@0 1654 return c;
meillo@0 1655 }
meillo@0 1656 newline();
meillo@0 1657 return(0);
meillo@0 1658 }
meillo@0 1659
meillo@0 1660 static int
meillo@0 1661 getsub(void)
meillo@0 1662 {
meillo@0 1663 register char *p1, *p2;
meillo@0 1664
meillo@0 1665 p1 = linebuf;
meillo@0 1666 if ((p2 = linebp) == 0)
meillo@0 1667 return(EOF);
meillo@0 1668 while (*p1++ = *p2++)
meillo@0 1669 ;
meillo@0 1670 linebp = 0;
meillo@0 1671 return(0);
meillo@0 1672 }
meillo@0 1673
meillo@0 1674 static int
meillo@0 1675 dosub(int really)
meillo@0 1676 {
meillo@0 1677 register char *lp, *sp;
meillo@0 1678 register int i, j, k;
meillo@0 1679 int c;
meillo@0 1680
meillo@0 1681 if (!really)
meillo@0 1682 goto copy;
meillo@0 1683 i = 0;
meillo@0 1684 j = 0;
meillo@0 1685 k = 0;
meillo@0 1686 while (&linebuf[i] < loc1)
meillo@0 1687 genbuf[j++] = linebuf[i++];
meillo@0 1688 while (c = rhsbuf[k++]&0377) {
meillo@0 1689 if (c=='&') {
meillo@0 1690 j = place(j, loc1, loc2);
meillo@0 1691 continue;
meillo@0 1692 } else if (c == '\\') {
meillo@0 1693 c = rhsbuf[k++]&0377;
meillo@0 1694 if (c >='1' && c < nbra+'1') {
meillo@0 1695 j = place(j, braslist[c-'1'], braelist[c-'1']);
meillo@0 1696 continue;
meillo@0 1697 }
meillo@0 1698 }
meillo@0 1699 if (j >= LBSIZE)
meillo@0 1700 growlb("line too long");
meillo@0 1701 genbuf[j++] = c;
meillo@0 1702 }
meillo@0 1703 i = loc2 - linebuf;
meillo@0 1704 loc2 = j + linebuf;
meillo@0 1705 if (loc1 == &linebuf[i]) {
meillo@0 1706 int n;
meillo@0 1707 wchar_t wc;
meillo@0 1708 if (mb_cur_max > 1 && (n = mbtowc(&wc, loc2, mb_cur_max)) > 0)
meillo@0 1709 loc2 += n;
meillo@0 1710 else
meillo@0 1711 loc2++;
meillo@0 1712 }
meillo@0 1713 while (genbuf[j++] = linebuf[i++])
meillo@0 1714 if (j >= LBSIZE)
meillo@0 1715 growlb("line too long");
meillo@0 1716 if (really) {
meillo@0 1717 lp = linebuf;
meillo@0 1718 sp = genbuf;
meillo@0 1719 } else {
meillo@0 1720 copy: sp = linebuf;
meillo@0 1721 lp = genbuf;
meillo@0 1722 }
meillo@0 1723 while (*lp++ = *sp++)
meillo@0 1724 ;
meillo@0 1725 return really;
meillo@0 1726 }
meillo@0 1727
meillo@0 1728 static int
meillo@0 1729 place(register int j, register const char *l1, register const char *l2)
meillo@0 1730 {
meillo@0 1731
meillo@0 1732 while (l1 < l2) {
meillo@0 1733 genbuf[j++] = *l1++;
meillo@0 1734 if (j >= LBSIZE)
meillo@0 1735 growlb("line too long");
meillo@0 1736 }
meillo@0 1737 return(j);
meillo@0 1738 }
meillo@0 1739
meillo@0 1740 static void
meillo@0 1741 move(int cflag)
meillo@0 1742 {
meillo@0 1743 register long *adt, *ad1, *ad2;
meillo@0 1744
meillo@0 1745 setdot();
meillo@0 1746 nonzero();
meillo@0 1747 if ((adt = address())==0)
meillo@0 1748 error("illegal move destination");
meillo@0 1749 newline();
meillo@0 1750 checkpoint();
meillo@0 1751 if (cflag) {
meillo@0 1752 long *ozero;
meillo@0 1753 intptr_t delta;
meillo@0 1754 ad1 = dol;
meillo@0 1755 ozero = zero;
meillo@0 1756 append(getcopy, ad1++);
meillo@0 1757 ad2 = dol;
meillo@0 1758 delta = zero - ozero;
meillo@0 1759 ad1 += delta;
meillo@0 1760 adt += delta;
meillo@0 1761 } else {
meillo@0 1762 ad2 = addr2;
meillo@0 1763 for (ad1 = addr1; ad1 <= ad2;)
meillo@0 1764 *ad1++ &= ~01;
meillo@0 1765 ad1 = addr1;
meillo@0 1766 }
meillo@0 1767 ad2++;
meillo@0 1768 if (adt<ad1) {
meillo@0 1769 dot = adt + (ad2-ad1);
meillo@0 1770 if ((++adt)==ad1)
meillo@0 1771 return;
meillo@0 1772 reverse(adt, ad1);
meillo@0 1773 reverse(ad1, ad2);
meillo@0 1774 reverse(adt, ad2);
meillo@0 1775 } else if (adt >= ad2) {
meillo@0 1776 dot = adt++;
meillo@0 1777 reverse(ad1, ad2);
meillo@0 1778 reverse(ad2, adt);
meillo@0 1779 reverse(ad1, adt);
meillo@0 1780 } else
meillo@0 1781 error("illegal move destination");
meillo@0 1782 fchange = 1;
meillo@0 1783 }
meillo@0 1784
meillo@0 1785 static void
meillo@0 1786 reverse(register long *a1, register long *a2)
meillo@0 1787 {
meillo@0 1788 register int t;
meillo@0 1789
meillo@0 1790 for (;;) {
meillo@0 1791 t = *--a2;
meillo@0 1792 if (a2 <= a1)
meillo@0 1793 return;
meillo@0 1794 *a2 = *a1;
meillo@0 1795 *a1++ = t;
meillo@0 1796 }
meillo@0 1797 }
meillo@0 1798
meillo@0 1799 static int
meillo@0 1800 getcopy(void)
meillo@0 1801 {
meillo@0 1802 if (addr1 > addr2)
meillo@0 1803 return(EOF);
meillo@0 1804 getline(*addr1++, 0);
meillo@0 1805 return(0);
meillo@0 1806 }
meillo@0 1807
meillo@0 1808 static int
meillo@0 1809 execute(int gf, long *addr, int subst)
meillo@0 1810 {
meillo@0 1811 register char *p1, *p2, c;
meillo@0 1812
meillo@0 1813 for (c=0; c<NBRA; c++) {
meillo@0 1814 braslist[c&0377] = 0;
meillo@0 1815 braelist[c&0377] = 0;
meillo@0 1816 }
meillo@0 1817 if (gf) {
meillo@0 1818 if (circf)
meillo@0 1819 return(0);
meillo@0 1820 p1 = linebuf;
meillo@0 1821 p2 = genbuf;
meillo@0 1822 while (*p1++ = *p2++)
meillo@0 1823 ;
meillo@0 1824 locs = p1 = loc2;
meillo@0 1825 } else {
meillo@0 1826 if (addr==zero)
meillo@0 1827 return(0);
meillo@0 1828 p1 = getline(*addr, 1);
meillo@0 1829 locs = 0;
meillo@0 1830 }
meillo@0 1831 needsub = subst;
meillo@0 1832 return step(p1, expbuf);
meillo@0 1833 }
meillo@0 1834
meillo@0 1835 static void
meillo@0 1836 cmplerr(int c)
meillo@0 1837 {
meillo@0 1838 const char *msg;
meillo@0 1839
meillo@0 1840 switch (c) {
meillo@0 1841 case 11:
meillo@0 1842 msg = "Range endpoint too large";
meillo@0 1843 break;
meillo@0 1844 case 16:
meillo@0 1845 msg = "bad number";
meillo@0 1846 break;
meillo@0 1847 case 25:
meillo@0 1848 msg = "`\\digit' out of range";
meillo@0 1849 break;
meillo@0 1850 case 36:
meillo@0 1851 msg = "illegal or missing delimiter";
meillo@0 1852 break;
meillo@0 1853 case 41:
meillo@0 1854 msg = "no remembered search string";
meillo@0 1855 break;
meillo@0 1856 case 42:
meillo@0 1857 msg = "'\\( \\)' imbalance";
meillo@0 1858 break;
meillo@0 1859 case 43:
meillo@0 1860 msg = "Too many `\\(' s";
meillo@0 1861 break;
meillo@0 1862 case 44:
meillo@0 1863 msg = "more than 2 numbers given";
meillo@0 1864 break;
meillo@0 1865 case 45:
meillo@0 1866 msg = "'\\}' expected";
meillo@0 1867 break;
meillo@0 1868 case 46:
meillo@0 1869 msg = "first number exceeds second";
meillo@0 1870 break;
meillo@0 1871 case 49:
meillo@0 1872 msg = "'[ ]' imbalance";
meillo@0 1873 break;
meillo@0 1874 case 50:
meillo@0 1875 msg = "regular expression overflow";
meillo@0 1876 break;
meillo@0 1877 case 67:
meillo@0 1878 msg = "illegal byte sequence";
meillo@0 1879 break;
meillo@0 1880 default:
meillo@0 1881 msg = "regular expression error";
meillo@0 1882 break;
meillo@0 1883 }
meillo@0 1884 error(msg);
meillo@0 1885 }
meillo@0 1886
meillo@0 1887 static void
meillo@0 1888 doprnt(long *bot, long *top)
meillo@0 1889 {
meillo@0 1890 long *a1;
meillo@0 1891
meillo@0 1892 a1 = bot;
meillo@0 1893 do {
meillo@0 1894 if (numbf ^ Nflag) {
meillo@0 1895 putd(a1-zero);
meillo@0 1896 putchr('\t');
meillo@0 1897 }
meillo@0 1898 nlputs(getline(*a1++, 0));
meillo@0 1899 } while (a1 <= top);
meillo@0 1900 pflag = 0;
meillo@0 1901 listf = 0;
meillo@0 1902 numbf = 0;
meillo@0 1903 }
meillo@0 1904
meillo@0 1905 static void
meillo@0 1906 putd(long c)
meillo@0 1907 {
meillo@0 1908 register int r;
meillo@0 1909
meillo@0 1910 r = c%10;
meillo@0 1911 c /= 10;
meillo@0 1912 if (c)
meillo@0 1913 putd(c);
meillo@0 1914 putchr(r + '0');
meillo@0 1915 }
meillo@0 1916
meillo@0 1917 static void
meillo@0 1918 nlputs(register const char *sp)
meillo@0 1919 {
meillo@0 1920 if (listf)
meillo@0 1921 list(sp);
meillo@0 1922 else
meillo@0 1923 puts(sp);
meillo@0 1924 }
meillo@0 1925
meillo@0 1926 static void
meillo@0 1927 puts(register const char *sp)
meillo@0 1928 {
meillo@0 1929 while (*sp) {
meillo@0 1930 if (*sp != '\n')
meillo@0 1931 putchr(*sp++ & 0377);
meillo@0 1932 else
meillo@0 1933 sp++, putchr('\0');
meillo@0 1934 }
meillo@0 1935 putchr('\n');
meillo@0 1936 }
meillo@0 1937
meillo@0 1938 static void
meillo@0 1939 list(const char *lp)
meillo@0 1940 {
meillo@0 1941 int col, n;
meillo@0 1942 wchar_t c;
meillo@0 1943
meillo@0 1944 col = numbf ^ Nflag ? 8 : 0;
meillo@0 1945 while (*lp) {
meillo@0 1946 if (mb_cur_max > 1 && *lp&0200)
meillo@0 1947 n = mbtowc(&c, lp, mb_cur_max);
meillo@0 1948 else {
meillo@0 1949 n = 1;
meillo@0 1950 c = *lp&0377;
meillo@0 1951 }
meillo@0 1952 if (col+1 >= 72) {
meillo@0 1953 col = 0;
meillo@0 1954 putchr('\\');
meillo@0 1955 putchr('\n');
meillo@0 1956 }
meillo@4 1957 if (n<0 || c == '\\' ||
meillo@0 1958 !(mb_cur_max>1 ? iswprint(c) : isprint(c))) {
meillo@0 1959 if (n<0)
meillo@0 1960 n = 1;
meillo@0 1961 while (n--)
meillo@0 1962 col += lstchr(*lp++&0377);
meillo@0 1963 } else if (mb_cur_max>1) {
meillo@0 1964 col += wcwidth(c);
meillo@0 1965 while (n--)
meillo@0 1966 putchr(*lp++&0377);
meillo@0 1967 } else {
meillo@0 1968 putchr(*lp++&0377);
meillo@0 1969 col++;
meillo@0 1970 }
meillo@0 1971 }
meillo@0 1972 putchr('$');
meillo@0 1973 putchr('\n');
meillo@0 1974 }
meillo@0 1975
meillo@0 1976 static int
meillo@0 1977 lstchr(int c)
meillo@0 1978 {
meillo@0 1979 int cad = 1, d;
meillo@0 1980
meillo@0 1981 if (c == '\n')
meillo@0 1982 c = '\0';
meillo@0 1983 if (c == '\\') {
meillo@0 1984 putchr('\\');
meillo@0 1985 putchr('\\');
meillo@0 1986 cad = 2;
meillo@0 1987 } else if (c == '\a') {
meillo@0 1988 putchr('\\');
meillo@0 1989 putchr('a');
meillo@0 1990 cad = 2;
meillo@0 1991 } else if (c == '\b') {
meillo@0 1992 putchr('\\');
meillo@0 1993 putchr('b');
meillo@0 1994 cad = 2;
meillo@0 1995 } else if (c == '\f') {
meillo@0 1996 putchr('\\');
meillo@0 1997 putchr('f');
meillo@0 1998 cad = 2;
meillo@0 1999 } else if (c == '\r') {
meillo@0 2000 putchr('\\');
meillo@0 2001 putchr('r');
meillo@0 2002 cad = 2;
meillo@0 2003 } else if (c == '\t') {
meillo@0 2004 putchr('\\');
meillo@0 2005 putchr('t');
meillo@0 2006 cad = 2;
meillo@0 2007 } else if (c == '\v') {
meillo@0 2008 putchr('\\');
meillo@0 2009 putchr('v');
meillo@0 2010 cad = 2;
meillo@0 2011 } else {
meillo@0 2012 putchr('\\');
meillo@0 2013 putchr(((c&~077)>>6)+'0');
meillo@0 2014 c &= 077;
meillo@0 2015 d = c & 07;
meillo@0 2016 putchr(c > d ? ((c-d)>>3)+'0' : '0');
meillo@0 2017 putchr(d+'0');
meillo@0 2018 cad = 4;
meillo@0 2019 }
meillo@0 2020 return cad;
meillo@0 2021 }
meillo@0 2022
meillo@0 2023 static void
meillo@0 2024 putstr(const char *s)
meillo@0 2025 {
meillo@0 2026 while (*s)
meillo@0 2027 putchr(*s++);
meillo@0 2028 }
meillo@0 2029
meillo@0 2030 static char line[70];
meillo@0 2031 static char *linp = line;
meillo@0 2032
meillo@0 2033 static void
meillo@0 2034 putchr(int ac)
meillo@0 2035 {
meillo@0 2036 register char *lp;
meillo@0 2037 register int c;
meillo@0 2038
meillo@0 2039 lp = linp;
meillo@0 2040 c = ac;
meillo@0 2041 *lp++ = c;
meillo@0 2042 if(c == '\n' || lp >= &line[64]) {
meillo@0 2043 linp = line;
meillo@0 2044 write(1, line, lp-line);
meillo@0 2045 return;
meillo@0 2046 }
meillo@0 2047 linp = lp;
meillo@0 2048 }
meillo@0 2049
meillo@0 2050 static void
meillo@0 2051 checkpoint(void)
meillo@0 2052 {
meillo@0 2053 long *a1, *a2;
meillo@0 2054
meillo@0 2055 if (undzero && globp == NULL) {
meillo@0 2056 for (a1 = zero+1, a2 = undzero+1; a1 <= dol; a1++, a2++)
meillo@0 2057 *a2 = *a1;
meillo@0 2058 unddot = &undzero[dot-zero];
meillo@0 2059 unddol = &undzero[dol-zero];
meillo@0 2060 for (a1 = names, a2 = undnames; a1 < &names[26]; a1++, a2++)
meillo@0 2061 *a2 = *a1;
meillo@0 2062 }
meillo@0 2063 }
meillo@0 2064
meillo@0 2065 #define swap(a, b) (t = a, a = b, b = t)
meillo@0 2066
meillo@0 2067 static void
meillo@0 2068 undo(void)
meillo@0 2069 {
meillo@0 2070 long *t;
meillo@0 2071
meillo@0 2072 if (undzero == NULL)
meillo@0 2073 error("no undo information saved");
meillo@0 2074 swap(zero, undzero);
meillo@0 2075 swap(dot, unddot);
meillo@0 2076 swap(dol, unddol);
meillo@0 2077 swap(names, undnames);
meillo@0 2078 }
meillo@0 2079
meillo@0 2080 static int
meillo@0 2081 maketf(int fd)
meillo@0 2082 {
meillo@0 2083 char *tmpdir;
meillo@0 2084
meillo@0 2085 if (fd == -1) {
meillo@0 2086 if ((tmpdir = getenv("TMPDIR")) == NULL ||
meillo@0 2087 (fd = creatf(tmpdir)) < 0)
meillo@0 2088 if ((fd = creatf("/var/tmp")) < 0 &&
meillo@0 2089 (fd = creatf("/tmp")) < 0)
meillo@0 2090 error("cannot create temporary file");
meillo@0 2091 } else
meillo@0 2092 ftruncate(fd, 0); /* blkio() will seek to 0 anyway */
meillo@0 2093 return fd;
meillo@0 2094 }
meillo@0 2095
meillo@0 2096 static int
meillo@0 2097 creatf(const char *tmpdir)
meillo@0 2098 {
meillo@0 2099 if (strlen(tmpdir) >= sizeof tfname - 9)
meillo@0 2100 return -1;
meillo@0 2101 strcpy(tfname, tmpdir);
meillo@0 2102 strcat(tfname, "/eXXXXXX");
meillo@0 2103 return mkstemp(tfname);
meillo@0 2104 }
meillo@0 2105
meillo@0 2106 static int
meillo@0 2107 sopen(const char *fn, int rdwr)
meillo@0 2108 {
meillo@0 2109 int pf[2], fd = -1;
meillo@0 2110
meillo@0 2111 if (fn[0] == '!') {
meillo@0 2112 fn++;
meillo@0 2113 if (pipe(pf) < 0)
meillo@0 2114 error("write or open on pipe failed");
meillo@0 2115 switch (pipid = fork()) {
meillo@0 2116 case 0:
meillo@0 2117 if (rdwr == READ)
meillo@0 2118 dup2(pf[1], 1);
meillo@0 2119 else
meillo@0 2120 dup2(pf[0], 0);
meillo@0 2121 close(pf[0]);
meillo@0 2122 close(pf[1]);
meillo@0 2123 sigset(SIGHUP, oldhup);
meillo@0 2124 sigset(SIGQUIT, oldquit);
meillo@0 2125 sigset(SIGPIPE, oldpipe);
meillo@0 2126 execl(SHELL, "sh", "-c", fn, NULL);
meillo@0 2127 _exit(0100);
meillo@0 2128 default:
meillo@0 2129 close(pf[rdwr == READ ? 1 : 0]);
meillo@0 2130 fd = pf[rdwr == READ ? 0 : 1];
meillo@0 2131 break;
meillo@0 2132 case -1:
meillo@0 2133 error("fork failed - try again");
meillo@0 2134 }
meillo@0 2135 } else if (rdwr == READ)
meillo@0 2136 fd = open(fn, O_RDONLY);
meillo@0 2137 else if (rdwr == EXIST)
meillo@0 2138 fd = open(fn, O_WRONLY);
meillo@0 2139 else /*if (rdwr == WRITE)*/
meillo@0 2140 fd = creat(fn, 0666);
meillo@0 2141 if (fd >= 0 && rdwr == READ)
meillo@0 2142 readop = 1;
meillo@0 2143 if (fd >= 0)
meillo@0 2144 fstat(fd, &fstbuf);
meillo@0 2145 return fd;
meillo@0 2146 }
meillo@0 2147
meillo@0 2148 static void
meillo@0 2149 sclose(int fd)
meillo@0 2150 {
meillo@0 2151 int status;
meillo@0 2152
meillo@0 2153 close(fd);
meillo@0 2154 if (pipid >= 0) {
meillo@0 2155 while (wait(&status) != pipid);
meillo@0 2156 pipid = -1;
meillo@0 2157 }
meillo@0 2158 readop = 0;
meillo@0 2159 }
meillo@0 2160
meillo@0 2161 static wint_t
meillo@0 2162 GETWC(char *mb)
meillo@0 2163 {
meillo@0 2164 int c, n;
meillo@0 2165
meillo@0 2166 n = 1;
meillo@0 2167 mb[0] = c = GETC();
meillo@0 2168 mb[1] = '\0';
meillo@0 2169 if (mb_cur_max > 1 && c&0200 && c != EOF) {
meillo@0 2170 int m;
meillo@0 2171 wchar_t wc;
meillo@0 2172
meillo@0 2173 while ((m = mbtowc(&wc, mb, mb_cur_max)) < 0 && n<mb_cur_max) {
meillo@0 2174 mb[n++] = c = GETC();
meillo@0 2175 mb[n] = '\0';
meillo@0 2176 if (c == '\n' || c == EOF)
meillo@0 2177 break;
meillo@0 2178 }
meillo@0 2179 if (m != n)
meillo@0 2180 ERROR(67);
meillo@0 2181 return wc;
meillo@0 2182 } else
meillo@0 2183 return c;
meillo@0 2184 }
meillo@0 2185
meillo@0 2186 static void
meillo@0 2187 growlb(const char *msg)
meillo@0 2188 {
meillo@0 2189 char *olb = linebuf;
meillo@0 2190 int i;
meillo@0 2191
meillo@0 2192 LBSIZE += 512;
meillo@0 2193 if ((linebuf = realloc(linebuf, LBSIZE)) == NULL ||
meillo@0 2194 (genbuf = realloc(genbuf, LBSIZE)) == NULL)
meillo@0 2195 error(msg);
meillo@0 2196 if (linebuf != olb) {
meillo@0 2197 loc1 += linebuf - olb;
meillo@0 2198 loc2 += linebuf - olb;
meillo@0 2199 for (i = 0; i < NBRA; i++) {
meillo@0 2200 if (braslist[i])
meillo@0 2201 braslist[i] += linebuf - olb;
meillo@0 2202 if (braelist[i])
meillo@0 2203 braelist[i] += linebuf - olb;
meillo@0 2204 }
meillo@0 2205 }
meillo@0 2206 }
meillo@0 2207
meillo@0 2208 static void
meillo@0 2209 growrhs(const char *msg)
meillo@0 2210 {
meillo@0 2211 RHSIZE += 256;
meillo@0 2212 if ((rhsbuf = realloc(rhsbuf, RHSIZE)) == NULL)
meillo@0 2213 error(msg);
meillo@0 2214 }
meillo@0 2215
meillo@0 2216 static void
meillo@0 2217 growfn(const char *msg)
meillo@0 2218 {
meillo@0 2219 FNSIZE += 64;
meillo@0 2220 if ((savedfile = realloc(savedfile, FNSIZE)) == NULL ||
meillo@0 2221 (file = realloc(file, FNSIZE)) == NULL)
meillo@0 2222 error(msg);
meillo@0 2223 if (FNSIZE == 64)
meillo@0 2224 file[0] = savedfile[0] = 0;
meillo@0 2225 }
meillo@0 2226
meillo@0 2227 union ptrstore {
meillo@0 2228 void *vp;
meillo@0 2229 char bp[sizeof (void *)];
meillo@0 2230 };
meillo@0 2231
meillo@0 2232 static void *
meillo@0 2233 fetchptr(const char *bp)
meillo@0 2234 {
meillo@0 2235 union ptrstore u;
meillo@0 2236 int i;
meillo@0 2237
meillo@0 2238 for (i = 0; i < sizeof (void *); i++)
meillo@0 2239 u.bp[i] = bp[i];
meillo@0 2240 return u.vp;
meillo@0 2241 }
meillo@0 2242
meillo@0 2243 static void
meillo@0 2244 storeptr(void *vp, char *bp)
meillo@0 2245 {
meillo@0 2246 union ptrstore u;
meillo@0 2247 int i;
meillo@0 2248
meillo@0 2249 u.vp = vp;
meillo@0 2250 for (i = 0; i < sizeof (void *); i++)
meillo@0 2251 bp[i] = u.bp[i];
meillo@0 2252 }
meillo@0 2253
meillo@0 2254 #define add(c) ((i>=LBSIZE ? (growlb("regular expression overflow"),0) : 0), \
meillo@0 2255 genbuf[i++] = (c))
meillo@0 2256
meillo@0 2257 #define copy(s) { \
meillo@0 2258 int m; \
meillo@0 2259 for (m = 0; m==0 || s[m]; m++) \
meillo@0 2260 add(s[m]); \
meillo@0 2261 }
meillo@0 2262
meillo@0 2263 static char *
meillo@0 2264 compile(char *unused, char *ep, const char *endbuf, int seof)
meillo@0 2265 {
meillo@0 2266 INIT
meillo@0 2267 int c, d, i;
meillo@0 2268 regex_t *rp;
meillo@0 2269 char *op;
meillo@0 2270 char mb[MB_LEN_MAX+1];
meillo@0 2271
meillo@0 2272 op = ep;
meillo@0 2273 ep += 2;
meillo@0 2274 if ((rp = fetchptr(ep)) == NULL) {
meillo@0 2275 if ((rp = calloc(1, sizeof *rp)) == NULL)
meillo@0 2276 ERROR(50);
meillo@0 2277 storeptr(rp, ep);
meillo@0 2278 }
meillo@0 2279 ep += sizeof (void *);
meillo@0 2280 i = 0;
meillo@0 2281 nbra = 0;
meillo@0 2282 do {
meillo@0 2283 if ((c = GETWC(mb)) == seof)
meillo@0 2284 add('\0');
meillo@0 2285 else if (c == '\\') {
meillo@0 2286 copy(mb);
meillo@0 2287 c = GETWC(mb);
meillo@0 2288 if (c == '(')
meillo@0 2289 nbra++;
meillo@0 2290 goto normchar;
meillo@0 2291 } else if (c == '[') {
meillo@0 2292 add(c);
meillo@0 2293 d = EOF;
meillo@0 2294 do {
meillo@0 2295 c = GETWC(mb);
meillo@0 2296 if (c == EOF || c == '\n')
meillo@0 2297 ERROR(49);
meillo@0 2298 copy(mb);
meillo@0 2299 if (d=='[' && (c==':' || c=='.' || c=='=')) {
meillo@0 2300 d = c;
meillo@0 2301 do {
meillo@0 2302 c = GETWC(mb);
meillo@0 2303 if (c == EOF || c == '\n')
meillo@0 2304 ERROR(49);
meillo@0 2305 copy(mb);
meillo@0 2306 } while (c != d || PEEKC() != ']');
meillo@0 2307 c = GETWC(mb);
meillo@0 2308 copy(mb);
meillo@0 2309 c = EOF;
meillo@0 2310 }
meillo@0 2311 d = c;
meillo@0 2312 } while (c != ']');
meillo@0 2313 } else {
meillo@0 2314 if (c == EOF || c == '\n') {
meillo@0 2315 if (c == '\n')
meillo@0 2316 UNGETC(c);
meillo@0 2317 mb[0] = c = '\0';
meillo@0 2318 }
meillo@0 2319 if (c == '\0')
meillo@0 2320 nodelim = 1;
meillo@0 2321 normchar: copy(mb);
meillo@0 2322 }
meillo@0 2323 } while (genbuf[i-1] != '\0');
meillo@0 2324 if (genbuf[0]) {
meillo@0 2325 int reflags = 0;
meillo@0 2326
meillo@0 2327 #ifdef REG_ANGLES
meillo@0 2328 reflags |= REG_ANGLES;
meillo@0 2329 #endif
meillo@4 2330 #ifdef REG_AVOIDNULL
meillo@0 2331 reflags |= REG_AVOIDNULL;
meillo@0 2332 #endif
meillo@0 2333 if (op[0])
meillo@0 2334 regfree(rp);
meillo@0 2335 op[0] = 0;
meillo@0 2336 switch (regcomp(rp, genbuf, reflags)) {
meillo@0 2337 case 0:
meillo@0 2338 break;
meillo@0 2339 case REG_ESUBREG:
meillo@0 2340 ERROR(25);
meillo@0 2341 /*NOTREACHED*/
meillo@0 2342 case REG_EBRACK:
meillo@0 2343 ERROR(49);
meillo@0 2344 /*NOTREACHED*/
meillo@0 2345 case REG_EPAREN:
meillo@0 2346 ERROR(42);
meillo@0 2347 /*NOTREACHED*/
meillo@0 2348 case REG_BADBR:
meillo@0 2349 case REG_EBRACE:
meillo@0 2350 ERROR(45);
meillo@0 2351 /*NOTREACHED*/
meillo@0 2352 case REG_ERANGE:
meillo@0 2353 ERROR(11);
meillo@0 2354 /*NOTREACHED*/
meillo@0 2355 case REG_ESPACE:
meillo@0 2356 ERROR(50);
meillo@0 2357 /*NOTREACHED*/
meillo@0 2358 default:
meillo@0 2359 ERROR(-1);
meillo@0 2360 }
meillo@0 2361 op[0] = 1;
meillo@0 2362 circf = op[1] = genbuf[0] == '^';
meillo@0 2363 } else if (op[0]) {
meillo@0 2364 circf = op[1];
meillo@0 2365 } else
meillo@0 2366 ERROR(41);
meillo@0 2367 return ep + sizeof (void *);
meillo@0 2368 }
meillo@0 2369
meillo@0 2370 static int
meillo@0 2371 step(const char *lp, const char *ep)
meillo@0 2372 {
meillo@0 2373 regex_t *rp;
meillo@0 2374 regmatch_t bralist[NBRA+1];
meillo@0 2375 int eflag = 0;
meillo@0 2376 int res;
meillo@0 2377 int i;
meillo@0 2378
meillo@0 2379 rp = fetchptr(&ep[2]);
meillo@0 2380 if (ep[0] == 0)
meillo@0 2381 return 0;
meillo@0 2382 if (locs)
meillo@0 2383 eflag |= REG_NOTBOL;
meillo@0 2384 if ((res = regexec(rp, lp, needsub? NBRA+1 : 0, bralist, eflag)) == 0 &&
meillo@0 2385 needsub) {
meillo@0 2386 loc1 = (char *)lp + bralist[0].rm_so;
meillo@0 2387 loc2 = (char *)lp + bralist[0].rm_eo;
meillo@0 2388 for (i = 1; i <= NBRA; i++) {
meillo@0 2389 if (bralist[i].rm_so != -1) {
meillo@0 2390 braslist[i-1] = (char *)lp + bralist[i].rm_so;
meillo@0 2391 braelist[i-1] = (char *)lp + bralist[i].rm_eo;
meillo@0 2392 } else
meillo@0 2393 braslist[i-1] = braelist[i-1] = NULL;
meillo@0 2394 }
meillo@0 2395 }
meillo@0 2396 return res == 0;
meillo@0 2397 }
meillo@0 2398
meillo@0 2399 static void
meillo@0 2400 help(void)
meillo@0 2401 {
meillo@0 2402 const char *desc[] = {
meillo@0 2403 "(.)a append up to .",
meillo@0 2404 "(.)b[n] browse n lines",
meillo@0 2405 "(.,.)c change up to .",
meillo@0 2406 "(.,.)d delete lines",
meillo@0 2407 "e [file] edit file",
meillo@0 2408 "E [file] force edit",
meillo@0 2409 "f [file] print or set file",
meillo@0 2410 "(1,$)g/RE/cmd global cmd",
meillo@0 2411 "(1,$)G/RE/ interactive global",
meillo@0 2412 "h print last error",
meillo@0 2413 "H toggle error messages",
meillo@0 2414 "help print this screen",
meillo@0 2415 "(.)i insert up to .",
meillo@0 2416 "(.,.+1)j join lines",
meillo@0 2417 "(.)kx mark line with x",
meillo@0 2418 "(.,.)l list lines",
meillo@0 2419 "(.,.)ma move lines to a",
meillo@0 2420 "(.,.)n number lines",
meillo@0 2421 "N revert n and p",
meillo@0 2422 "(.)o[n] show n lines of context",
meillo@0 2423 "(.,.)p print lines",
meillo@0 2424 "P toggle prompt",
meillo@0 2425 "q quit",
meillo@0 2426 "Q force quit",
meillo@0 2427 "($)r read file",
meillo@0 2428 "(.,.)s/RE/repl/ search and replace",
meillo@0 2429 "(.,.)s/RE/rp/g replace all occurrences",
meillo@0 2430 "(.,.)s/RE/rp/n replace n-th occurrence",
meillo@0 2431 "(.,.)ta transfer lines to a",
meillo@0 2432 "u undo last change",
meillo@0 2433 "(1,$)v/RE/cmd reverse global",
meillo@0 2434 "(1,$)V/RE/ reverse i/a global",
meillo@0 2435 "(1,$)w [file] write file",
meillo@0 2436 "(1,$)W [file] append to file",
meillo@0 2437 "z write buffer and quit",
meillo@0 2438 "($)= print line number",
meillo@0 2439 "!command execute shell command",
meillo@0 2440 "(.+1)<newline> print one line",
meillo@0 2441 "/RE find RE forwards",
meillo@0 2442 "?RE find RE backwards",
meillo@0 2443 "1 first line",
meillo@0 2444 ". current line",
meillo@0 2445 "$ last line",
meillo@0 2446 ", 1,$",
meillo@0 2447 "; .,$",
meillo@0 2448 NULL
meillo@0 2449 };
meillo@0 2450 char line[100];
meillo@0 2451 int c, half, i, k;
meillo@0 2452
meillo@0 2453 half = (sizeof desc / sizeof *desc) / 2;
meillo@0 2454 for (i = 0; i < half && desc[i]; i++) {
meillo@0 2455 c = 0;
meillo@0 2456 for (k = 0; desc[i][k]; k++)
meillo@0 2457 line[c++] = desc[i][k];
meillo@0 2458 if (desc[i+half]) {
meillo@0 2459 while (c < 40)
meillo@0 2460 line[c++] = ' ';
meillo@0 2461 for (k = 0; desc[i+half][k]; k++)
meillo@0 2462 line[c++] = desc[i+half][k];
meillo@0 2463 }
meillo@0 2464 line[c] = 0;
meillo@0 2465 puts(line);
meillo@0 2466 }
meillo@0 2467 }