heirloom-ed
diff ed.c @ 0:1493bea5ac22
Initial version of the standalone heirloom-ed
author | markus schnalke <meillo@marmaro.de> |
---|---|
date | Mon, 05 Sep 2011 16:31:35 +0200 |
parents | |
children | a09d0630f05b |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ed.c Mon Sep 05 16:31:35 2011 +0200 1.3 @@ -0,0 +1,2822 @@ 1.4 +/* 1.5 + * Editor 1.6 + */ 1.7 + 1.8 +/* 1.9 + * Changes by Gunnar Ritter, Freiburg i. Br., Germany, July 2003. 1.10 + */ 1.11 +/* from Unix 32V /usr/src/cmd/ed.c */ 1.12 +/* 1.13 + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 1.14 + * 1.15 + * Redistribution and use in source and binary forms, with or without 1.16 + * modification, are permitted provided that the following conditions 1.17 + * are met: 1.18 + * Redistributions of source code and documentation must retain the 1.19 + * above copyright notice, this list of conditions and the following 1.20 + * disclaimer. 1.21 + * Redistributions in binary form must reproduce the above copyright 1.22 + * notice, this list of conditions and the following disclaimer in the 1.23 + * documentation and/or other materials provided with the distribution. 1.24 + * All advertising materials mentioning features or use of this software 1.25 + * must display the following acknowledgement: 1.26 + * This product includes software developed or owned by Caldera 1.27 + * International, Inc. 1.28 + * Neither the name of Caldera International, Inc. nor the names of 1.29 + * other contributors may be used to endorse or promote products 1.30 + * derived from this software without specific prior written permission. 1.31 + * 1.32 + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 1.33 + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 1.34 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1.35 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.36 + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE 1.37 + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.38 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.39 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 1.40 + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 1.41 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 1.42 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 1.43 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.44 + */ 1.45 + 1.46 +#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 1.47 +#define USED __attribute__ ((used)) 1.48 +#elif defined __GNUC__ 1.49 +#define USED __attribute__ ((unused)) 1.50 +#else 1.51 +#define USED 1.52 +#endif 1.53 +#if defined (SU3) 1.54 +static const char sccsid[] USED = "@(#)ed_su3.sl 1.99 (gritter) 7/27/06"; 1.55 +#elif defined (SUS) 1.56 +static const char sccsid[] USED = "@(#)ed_sus.sl 1.99 (gritter) 7/27/06"; 1.57 +#elif defined (S42) 1.58 +static const char sccsid[] USED = "@(#)ed_s42.sl 1.99 (gritter) 7/27/06"; 1.59 +#else /* !SU3, !SUS, !S42 */ 1.60 +static const char sccsid[] USED = "@(#)ed.sl 1.99 (gritter) 7/27/06"; 1.61 +#endif /* !SU3, !SUS, !S42 */ 1.62 + 1.63 +#include <sys/types.h> 1.64 +#include <sys/stat.h> 1.65 +#include <sys/wait.h> 1.66 +#include <sys/stat.h> 1.67 +#include <fcntl.h> 1.68 +#include <unistd.h> 1.69 +#include <time.h> 1.70 +#include <string.h> 1.71 +#include <stdlib.h> 1.72 +#include <signal.h> 1.73 +#include "sigset.h" 1.74 +#include <termios.h> 1.75 +#include <setjmp.h> 1.76 +#include <libgen.h> 1.77 +#include <inttypes.h> 1.78 +#include <locale.h> 1.79 +#include <wchar.h> 1.80 +#include <ctype.h> 1.81 +#include <wctype.h> 1.82 +#include <limits.h> 1.83 +#include <termios.h> 1.84 +static int FNSIZE; 1.85 +static int LBSIZE; 1.86 +static int RHSIZE; 1.87 +#define ESIZE 2048 1.88 +static int GBSIZE; 1.89 +#undef EOF 1.90 +#define EOF -1 1.91 +#define puts(s) xxputs(s) 1.92 +#define getline(t, n) xxgetline(t, n) 1.93 + 1.94 +#if (LONG_MAX > 017777777777L) 1.95 +#define MAXCNT 0777777777777777777777L /* 2^63-1 */ 1.96 +#else 1.97 +#define MAXCNT 017777777777L /* 2^31-1 */ 1.98 +#endif 1.99 +#define BLKMSK (MAXCNT>>8) /* was 0377 */ 1.100 + 1.101 +#define READ 0 1.102 +#define WRITE 1 1.103 +#define EXIST 2 1.104 + 1.105 +struct tabulator { 1.106 + struct tabulator *t_nxt; /* next list element */ 1.107 + const char *t_str; /* tabulator string */ 1.108 + int t_tab; /* tab stop position */ 1.109 + int t_rep; /* repetitive tab count */ 1.110 +}; 1.111 + 1.112 +static int peekc; 1.113 +static int lastc; 1.114 +static char *savedfile; 1.115 +static char *file; 1.116 +static struct stat fstbuf; 1.117 +static char *linebuf; 1.118 +static char *rhsbuf; 1.119 +static char expbuf[ESIZE + 4]; 1.120 +static long *zero; 1.121 +static long *undzero; 1.122 +static long *dot; 1.123 +static long *unddot; 1.124 +static long *dol; 1.125 +static long *unddol; 1.126 +static long *addr1; 1.127 +static long *addr2; 1.128 +static char *genbuf; 1.129 +static long count; 1.130 +static char *linebp; 1.131 +static int ninbuf; 1.132 +static int io; 1.133 +static int ioeof; 1.134 +static int pflag; 1.135 +static char *wrtemp; 1.136 +static uid_t myuid; 1.137 +static void (*oldhup)(int); 1.138 +static void (*oldquit)(int); 1.139 +static void (*oldpipe)(int); 1.140 +static int vflag = 1; 1.141 +static int listf; 1.142 +static int numbf; 1.143 +static char *globp; 1.144 +static int tfile = -1; 1.145 +static long tline; 1.146 +static char tfname[64]; 1.147 +static char ibuff[512]; 1.148 +static int iblock = -1; 1.149 +static char obuff[512]; 1.150 +static int oblock = -1; 1.151 +static int ichanged; 1.152 +static int nleft; 1.153 +static long *names; 1.154 +static long *undnames; 1.155 +static int anymarks; 1.156 +static int subnewa; 1.157 +static int fchange; 1.158 +static int wrapp; 1.159 +static unsigned nlall = 128; 1.160 +static const char *progname; 1.161 +static const char *prompt = "*"; 1.162 +static int Pflag; 1.163 +static int prhelp; 1.164 +static const char *prvmsg; 1.165 +static int lastsig; 1.166 +static int pipid = -1; 1.167 +static int readop; 1.168 +static int status; 1.169 +static int mb_cur_max; 1.170 +static int needsub; 1.171 +static int insub; 1.172 +static struct tabulator *tabstops; 1.173 +static int maxlength; 1.174 +static int rspec; 1.175 +static int Nflag; 1.176 +static int bcount = 22; 1.177 +static int ocount = 11; 1.178 + 1.179 +static jmp_buf savej; 1.180 + 1.181 +static void usage(char, int); 1.182 +static void commands(void); 1.183 +static long *address(void); 1.184 +static void setdot(void); 1.185 +static void setall(void); 1.186 +static void setnoaddr(void); 1.187 +static void nonzero(void); 1.188 +static void newline(void); 1.189 +static void filename(int); 1.190 +static void exfile(void); 1.191 +static void onintr(int); 1.192 +static void onhup(int); 1.193 +static void onpipe(int); 1.194 +static void error(const char *); 1.195 +static void error2(const char *, const char *); 1.196 +static void errput(const char *, const char *); 1.197 +static int getchr(void); 1.198 +static int gettty(void); 1.199 +static long getnum(void); 1.200 +static int getfile(void); 1.201 +static void putfile(void); 1.202 +static int append(int (*)(void), long *); 1.203 +static void callunix(void); 1.204 +static char *readcmd(void); 1.205 +static void quit(int); 1.206 +static void delete(void); 1.207 +static void rdelete(long *, long *); 1.208 +static void gdelete(void); 1.209 +static char *getline(long, int); 1.210 +static int putline(void); 1.211 +static char *getblock(long, long); 1.212 +static void blkio(long, char *, int); 1.213 +static void init(void); 1.214 +static void global(int, int); 1.215 +static void globrd(char **, int); 1.216 +static void join(void); 1.217 +static void substitute(int); 1.218 +static int compsub(void); 1.219 +static int getsub(void); 1.220 +static int dosub(int); 1.221 +static int place(int, const char *, const char *); 1.222 +static void move(int); 1.223 +static void reverse(long *, long *); 1.224 +static int getcopy(void); 1.225 +static int execute(int, long *, int); 1.226 +static void cmplerr(int); 1.227 +static void doprnt(long *, long *); 1.228 +static void putd(long); 1.229 +static void puts(const char *); 1.230 +static void nlputs(const char *); 1.231 +static void list(const char *); 1.232 +static int lstchr(int); 1.233 +static void putstr(const char *); 1.234 +static void putchr(int); 1.235 +static void checkpoint(void); 1.236 +static void undo(void); 1.237 +static int maketf(int); 1.238 +static int creatf(const char *); 1.239 +static int sopen(const char *, int); 1.240 +static void sclose(int); 1.241 +static void fspec(const char *); 1.242 +static const char *ftok(const char **); 1.243 +static struct tabulator *tabstring(const char *); 1.244 +static void freetabs(void); 1.245 +static void expand(const char *); 1.246 +static void growlb(const char *); 1.247 +static void growrhs(const char *); 1.248 +static void growfn(const char *); 1.249 +static void help(void); 1.250 + 1.251 +#define INIT 1.252 +#define GETC() getchr() 1.253 +#define UNGETC(c) (peekc = c) 1.254 +#define PEEKC() (peekc = getchr()) 1.255 +#define RETURN(c) return c 1.256 +#define ERROR(c) cmplerr(c) 1.257 +static wint_t GETWC(char *); 1.258 + 1.259 +#if defined (SUS) || defined (S42) || defined (SU3) 1.260 + 1.261 +#include <regex.h> 1.262 + 1.263 +#define NBRA 9 1.264 + 1.265 +static char *braslist[NBRA]; 1.266 +static char *braelist[NBRA]; 1.267 +static char *loc1, *loc2, *locs; 1.268 +static int nbra; 1.269 +static int circf; 1.270 +static int nodelim; 1.271 + 1.272 +static char *compile(char *, char *, const char *, int); 1.273 +static int step(const char *, const char *); 1.274 + 1.275 +#else /* !SUS, !S42, !SU3 */ 1.276 + 1.277 +#include <regexp.h> 1.278 + 1.279 +#endif /* !SUS, !S42, !SU3 */ 1.280 + 1.281 +int 1.282 +main(int argc, char **argv) 1.283 +{ 1.284 + register int i; 1.285 + void (*oldintr)(int); 1.286 + 1.287 + progname = basename(argv[0]); 1.288 +#if defined (SUS) || defined (S42) || defined (SU3) 1.289 + setlocale(LC_COLLATE, ""); 1.290 +#endif 1.291 + setlocale(LC_CTYPE, ""); 1.292 + mb_cur_max = MB_CUR_MAX; 1.293 + myuid = getuid(); 1.294 + oldquit = sigset(SIGQUIT, SIG_IGN); 1.295 + oldhup = sigset(SIGHUP, SIG_IGN); 1.296 + oldintr = sigset(SIGINT, SIG_IGN); 1.297 + if (sigset(SIGTERM, SIG_IGN) != SIG_IGN) 1.298 + sigset(SIGTERM, quit); 1.299 + oldpipe = sigset(SIGPIPE, onpipe); 1.300 + argv++; 1.301 + while (argc > 1 && **argv=='-') { 1.302 + if ((*argv)[1] == '\0') { 1.303 + vflag = 0; 1.304 + goto next; 1.305 + } else if ((*argv)[1] == '-' && (*argv)[2] == '\0') { 1.306 + argv++; 1.307 + argc--; 1.308 + break; 1.309 + } 1.310 + letter: switch((*argv)[1]) { 1.311 + 1.312 + case 's': 1.313 + vflag = 0; 1.314 + break; 1.315 + 1.316 + case 'q': 1.317 + sigset(SIGQUIT, SIG_DFL); 1.318 + vflag = 1; 1.319 + break; 1.320 + 1.321 + case 'p': 1.322 + if ((*argv)[2]) 1.323 + prompt = &(*argv)[2]; 1.324 + else if (argv[1]) { 1.325 + prompt = argv[1]; 1.326 + argv++; 1.327 + argc--; 1.328 + } else 1.329 + usage((*argv)[1], 1); 1.330 + Pflag = 1; 1.331 + goto next; 1.332 + 1.333 + default: 1.334 + usage((*argv)[1], 0); 1.335 + } 1.336 + if ((*argv)[2]) { 1.337 + (*argv)++; 1.338 + goto letter; 1.339 + } 1.340 + next: argv++; 1.341 + argc--; 1.342 + } 1.343 + 1.344 + growfn("no space"); 1.345 + if (argc>1) { 1.346 + i = -1; 1.347 + do 1.348 + if (++i >= FNSIZE) 1.349 + growfn("maximum of characters in " 1.350 + "file names reached"); 1.351 + while (savedfile[i] = (*argv)[i]); 1.352 + globp = "e"; 1.353 + } 1.354 + names = malloc(26*sizeof *names); 1.355 + undnames = malloc(26*sizeof *undnames); 1.356 + zero = malloc(nlall*sizeof *zero); 1.357 + if ((undzero = malloc(nlall*sizeof *undzero)) == NULL) 1.358 + puts("no memory for undo"); 1.359 + growlb("no space"); 1.360 + growrhs("no space"); 1.361 + init(); 1.362 + if (oldintr != SIG_IGN) 1.363 + sigset(SIGINT, onintr); 1.364 + if (oldhup != SIG_IGN) 1.365 + sigset(SIGHUP, onhup); 1.366 + setjmp(savej); 1.367 + if (lastsig) { 1.368 + sigrelse(lastsig); 1.369 + lastsig = 0; 1.370 + } 1.371 + commands(); 1.372 + quit(0); 1.373 + /*NOTREACHED*/ 1.374 + return 0; 1.375 +} 1.376 + 1.377 +static void 1.378 +usage(char c, int misarg) 1.379 +{ 1.380 + if (c) { 1.381 + write(2, progname, strlen(progname)); 1.382 + if (misarg) 1.383 + write(2, ": option requires an argument -- ", 33); 1.384 + else 1.385 + write(2, ": illegal option -- ", 20); 1.386 + write(2, &c, 1); 1.387 + write(2, "\n", 1); 1.388 + } 1.389 + write(2, "usage: ", 7); 1.390 + write(2, progname, strlen(progname)); 1.391 + write(2, " [- | -s] [-p string] [file]\n", 29); 1.392 + exit(2); 1.393 +} 1.394 + 1.395 +static void 1.396 +commands(void) 1.397 +{ 1.398 + register long *a1; 1.399 + register int c; 1.400 + int n; 1.401 + 1.402 + for (;;) { 1.403 + if (pflag) { 1.404 + pflag = 0; 1.405 + addr1 = addr2 = dot; 1.406 + goto print; 1.407 + } 1.408 + if (Pflag && globp == NULL) 1.409 + write(1, prompt, strlen(prompt)); 1.410 + addr1 = 0; 1.411 + addr2 = 0; 1.412 + switch (c = getchr()) { 1.413 + case ',': 1.414 + case ';': 1.415 + addr2 = c == ',' ? zero+1 : dot; 1.416 + if (((peekc = getchr()) < '0' || peekc > '9') && 1.417 + peekc != ' ' && peekc != '\t' && 1.418 + peekc != '+' && peekc != '-' && 1.419 + peekc != '^' && peekc != '?' && 1.420 + peekc != '/' && peekc != '$' && 1.421 + peekc != '.' && peekc != '\'') { 1.422 + addr1 = addr2; 1.423 + a1 = dol; 1.424 + goto loop; 1.425 + } 1.426 + break; 1.427 + default: 1.428 + peekc = c; 1.429 + } 1.430 + do { 1.431 + addr1 = addr2; 1.432 + if ((a1 = address())==0) { 1.433 + c = getchr(); 1.434 + break; 1.435 + } 1.436 + loop: addr2 = a1; 1.437 + if ((c=getchr()) == ';') { 1.438 + c = ','; 1.439 + dot = a1; 1.440 + } 1.441 + } while (c==','); 1.442 + if (addr1==0) 1.443 + addr1 = addr2; 1.444 + switch(c) { 1.445 + 1.446 + case 'a': 1.447 + setdot(); 1.448 + newline(); 1.449 + checkpoint(); 1.450 + append(gettty, addr2); 1.451 + continue; 1.452 + 1.453 + case 'c': 1.454 +#if defined (SU3) 1.455 + if (addr1 == zero && addr1+1 <= dol) { 1.456 + if (addr1 == addr2) 1.457 + addr2++; 1.458 + addr1++; 1.459 + } 1.460 +#endif /* SU3 */ 1.461 + delete(); 1.462 + append(gettty, addr1-1); 1.463 +#if defined (SUS) || defined (SU3) 1.464 + if (dot == addr1-1 && addr1 <= dol) 1.465 + dot = addr1; 1.466 +#endif /* SUS || SU3 */ 1.467 + continue; 1.468 + 1.469 + case 'd': 1.470 + delete(); 1.471 + continue; 1.472 + 1.473 + case 'E': 1.474 + fchange = 0; 1.475 + c = 'e'; 1.476 + case 'e': 1.477 + setnoaddr(); 1.478 + if (vflag && fchange) { 1.479 + fchange = 0; 1.480 + error("warning: expecting `w'"); 1.481 + } 1.482 + filename(c); 1.483 + init(); 1.484 + addr2 = zero; 1.485 + goto caseread; 1.486 + 1.487 + case 'f': 1.488 + setnoaddr(); 1.489 + filename(c); 1.490 + puts(savedfile); 1.491 + continue; 1.492 + 1.493 + case 'g': 1.494 + global(1, 0); 1.495 + continue; 1.496 + 1.497 + case 'G': 1.498 + global(1, 1); 1.499 + continue; 1.500 + 1.501 + case 'H': 1.502 + prhelp = !prhelp; 1.503 + /*FALLTHRU*/ 1.504 + 1.505 + case 'h': 1.506 + if ((peekc = getchr()) == 'e') { 1.507 + peekc = 0; 1.508 + if (getchr() != 'l' || getchr() != 'p' || 1.509 + getchr() != '\n') 1.510 + error("illegal suffix"); 1.511 + setnoaddr(); 1.512 + help(); 1.513 + continue; 1.514 + } 1.515 + newline(); 1.516 + setnoaddr(); 1.517 + if (prvmsg) 1.518 + puts(prvmsg); 1.519 + continue; 1.520 + 1.521 + case 'i': 1.522 + setdot(); 1.523 +#if defined (SU3) 1.524 + if (addr1 == zero) { 1.525 + if (addr1 == addr2) 1.526 + addr2++; 1.527 + addr1++; 1.528 + if (dol != zero) 1.529 + nonzero(); 1.530 + } else 1.531 +#endif /* SU3 */ 1.532 + nonzero(); 1.533 + newline(); 1.534 + checkpoint(); 1.535 + append(gettty, addr2-1); 1.536 + if (dot == addr2-1) 1.537 + dot++; 1.538 + continue; 1.539 + 1.540 + 1.541 + case 'j': 1.542 + if (addr2==0) { 1.543 + addr1 = dot; 1.544 + addr2 = dot+1; 1.545 + } 1.546 + setdot(); 1.547 + newline(); 1.548 + nonzero(); 1.549 + checkpoint(); 1.550 + if (addr1 != addr2) 1.551 + join(); 1.552 + continue; 1.553 + 1.554 + case 'k': 1.555 + if ((c = getchr()) < 'a' || c > 'z') 1.556 + error("mark not lower case"); 1.557 + newline(); 1.558 + setdot(); 1.559 + nonzero(); 1.560 + names[c-'a'] = *addr2 & ~01; 1.561 + anymarks |= 01; 1.562 + continue; 1.563 + 1.564 + case 'm': 1.565 + move(0); 1.566 + continue; 1.567 + 1.568 + case '\n': 1.569 + if (addr2==0) 1.570 + addr2 = dot+1; 1.571 + addr1 = addr2; 1.572 + goto print; 1.573 + 1.574 + case 'n': 1.575 + numbf = 1; 1.576 + newline(); 1.577 + goto print; 1.578 + 1.579 + case 'N': 1.580 + newline(); 1.581 + setnoaddr(); 1.582 + Nflag = !Nflag; 1.583 + continue; 1.584 + 1.585 + case 'b': 1.586 + case 'o': 1.587 + n = getnum(); 1.588 + newline(); 1.589 + setdot(); 1.590 + nonzero(); 1.591 + if (n >= 0) { 1.592 + if (c == 'b') 1.593 + bcount = n; 1.594 + else 1.595 + ocount = n; 1.596 + } 1.597 + if (c == 'b') { 1.598 + a1 = addr2+bcount > dol ? dol : addr2 + bcount; 1.599 + doprnt(addr1, a1); 1.600 + dot = a1; 1.601 + } else { 1.602 + a1 = addr2+ocount > dol ? dol : addr2 + ocount; 1.603 + doprnt(addr2-ocount<zero+1?zero+1:addr2-ocount, a1); 1.604 + dot = addr2; 1.605 + } 1.606 + continue; 1.607 + 1.608 + case 'l': 1.609 + listf++; 1.610 + case 'p': 1.611 + newline(); 1.612 + print: 1.613 + setdot(); 1.614 + nonzero(); 1.615 + doprnt(addr1, addr2); 1.616 + dot = addr2; 1.617 + continue; 1.618 + 1.619 + case 'P': 1.620 + setnoaddr(); 1.621 + newline(); 1.622 + Pflag = !Pflag; 1.623 + continue; 1.624 + 1.625 + case 'Q': 1.626 + fchange = 0; 1.627 + case 'q': 1.628 + setnoaddr(); 1.629 + newline(); 1.630 + quit(0); 1.631 + 1.632 + case 'r': 1.633 + filename(c); 1.634 + caseread: 1.635 + if ((io = sopen(file, READ)) < 0) { 1.636 + lastc = '\n'; 1.637 + error2("cannot open input file", file); 1.638 + } 1.639 + ioeof = 0; 1.640 + setall(); 1.641 + ninbuf = 0; 1.642 + if (c == 'r') 1.643 + checkpoint(); 1.644 + n = zero != dol; 1.645 + rspec = (c == 'e' || !n) && file[0] != '!'; 1.646 + append(getfile, addr2); 1.647 + rspec = 0; 1.648 + exfile(); 1.649 + fchange = n; 1.650 + continue; 1.651 + 1.652 + case 's': 1.653 + setdot(); 1.654 + nonzero(); 1.655 + substitute(globp!=0); 1.656 + continue; 1.657 + 1.658 + case 't': 1.659 + move(1); 1.660 + continue; 1.661 + 1.662 + case 'u': 1.663 + setdot(); 1.664 + newline(); 1.665 + if (unddot == NULL) 1.666 + error("nothing to undo"); 1.667 + undo(); 1.668 + continue; 1.669 + 1.670 + case 'v': 1.671 + global(0, 0); 1.672 + continue; 1.673 + 1.674 + case 'V': 1.675 + global(0, 1); 1.676 + continue; 1.677 + 1.678 + case 'W': 1.679 + wrapp++; 1.680 + case 'w': 1.681 + write: 1.682 + setall(); 1.683 + if (zero != dol) 1.684 + nonzero(); 1.685 + filename(c); 1.686 + if(!wrapp || 1.687 + ((io = open(file,O_WRONLY|O_APPEND)) == -1) || 1.688 + ((lseek(io, 0, SEEK_END)) == -1)) { 1.689 + struct stat st; 1.690 + if (lstat(file, &st) == 0 && 1.691 + (st.st_mode&S_IFMT) == S_IFREG && 1.692 + st.st_nlink == 1 && 1.693 + (myuid==0 || myuid==st.st_uid)) { 1.694 + char *cp, *tp; 1.695 + int nio; 1.696 + if ((io = sopen(file, EXIST)) < 0) 1.697 + error("cannot create output file"); 1.698 + if ((wrtemp = malloc(strlen(file)+8)) == NULL) 1.699 + error("out of memory"); 1.700 + for (cp = file, tp = wrtemp; *cp; cp++) 1.701 + *tp++ = *cp; 1.702 + while (tp > wrtemp && tp[-1] != '/') 1.703 + tp--; 1.704 + for (cp = "\7XXXXXX"; *cp; cp++) 1.705 + *tp++ = *cp; 1.706 + *tp = '\0'; 1.707 + if ((nio = mkstemp(wrtemp)) < 0) { 1.708 + free(wrtemp); 1.709 + wrtemp = NULL; 1.710 + ftruncate(io, 0); 1.711 + } else { 1.712 + close(io); 1.713 + io = nio; 1.714 + } 1.715 + } else { 1.716 + if ((io = sopen(file, WRITE)) < 0) 1.717 + error("cannot create output file"); 1.718 + } 1.719 + } 1.720 + if (zero != dol) { 1.721 + ioeof = 0; 1.722 + wrapp = 0; 1.723 + putfile(); 1.724 + } 1.725 + exfile(); 1.726 + if (addr1==zero+1 && addr2==dol || addr1==addr2 && dol==zero) 1.727 + fchange = 0; 1.728 + if (c == 'z') 1.729 + quit(0); 1.730 + continue; 1.731 + 1.732 + case 'z': 1.733 + if ((peekc=getchr()) != '\n') 1.734 + error("illegal suffix"); 1.735 + setnoaddr(); 1.736 + goto write; 1.737 + 1.738 + case '=': 1.739 + setall(); 1.740 + newline(); 1.741 + putd((addr2-zero)&MAXCNT); 1.742 + putchr('\n'); 1.743 + continue; 1.744 + 1.745 + case '!': 1.746 + callunix(); 1.747 + continue; 1.748 + 1.749 + case EOF: 1.750 + return; 1.751 + 1.752 + } 1.753 + error("unknown command"); 1.754 + } 1.755 +} 1.756 + 1.757 +static long * 1.758 +address(void) 1.759 +{ 1.760 + register long *a1; 1.761 + register int minus, c; 1.762 + int n, relerr; 1.763 + 1.764 + minus = 0; 1.765 + a1 = 0; 1.766 + for (;;) { 1.767 + c = getchr(); 1.768 + if ('0'<=c && c<='9') { 1.769 + n = 0; 1.770 + do { 1.771 + n *= 10; 1.772 + n += c - '0'; 1.773 + } while ((c = getchr())>='0' && c<='9'); 1.774 + peekc = c; 1.775 + if (a1==0) 1.776 + a1 = zero; 1.777 + if (minus<0) 1.778 + n = -n; 1.779 + a1 += n; 1.780 + minus = 0; 1.781 + continue; 1.782 + } 1.783 + relerr = 0; 1.784 + if (a1 || minus) 1.785 + relerr++; 1.786 + switch(c) { 1.787 + case ' ': 1.788 + case '\t': 1.789 + continue; 1.790 + 1.791 + case '+': 1.792 + minus++; 1.793 + if (a1==0) 1.794 + a1 = dot; 1.795 + continue; 1.796 + 1.797 + case '-': 1.798 + case '^': 1.799 + minus--; 1.800 + if (a1==0) 1.801 + a1 = dot; 1.802 + continue; 1.803 + 1.804 + case '?': 1.805 + case '/': 1.806 + compile(NULL, expbuf, &expbuf[ESIZE], c); 1.807 + a1 = dot; 1.808 + for (;;) { 1.809 + if (c=='/') { 1.810 + a1++; 1.811 + if (a1 > dol) 1.812 + a1 = zero; 1.813 + } else { 1.814 + a1--; 1.815 + if (a1 < zero) 1.816 + a1 = dol; 1.817 + } 1.818 + if (execute(0, a1, 0)) 1.819 + break; 1.820 + if (a1==dot) 1.821 + error("search string not found"); 1.822 + } 1.823 + break; 1.824 + 1.825 + case '$': 1.826 + a1 = dol; 1.827 + break; 1.828 + 1.829 + case '.': 1.830 + a1 = dot; 1.831 + break; 1.832 + 1.833 + case '\'': 1.834 + if ((c = getchr()) < 'a' || c > 'z') 1.835 + error("mark not lower case"); 1.836 + for (a1=zero; a1<=dol; a1++) 1.837 + if (names[c-'a'] == (*a1 & ~01)) 1.838 + break; 1.839 + break; 1.840 + 1.841 + default: 1.842 + peekc = c; 1.843 + if (a1==0) 1.844 + return(0); 1.845 + a1 += minus; 1.846 + if (a1<zero || a1>dol) 1.847 + error("line out of range"); 1.848 + return(a1); 1.849 + } 1.850 + if (relerr) 1.851 + error("bad number"); 1.852 + } 1.853 +} 1.854 + 1.855 +static void 1.856 +setdot(void) 1.857 +{ 1.858 + if (addr2 == 0) 1.859 + addr1 = addr2 = dot; 1.860 + if (addr1 > addr2) 1.861 + error("bad range"); 1.862 +} 1.863 + 1.864 +static void 1.865 +setall(void) 1.866 +{ 1.867 + if (addr2==0) { 1.868 + addr1 = zero+1; 1.869 + addr2 = dol; 1.870 + if (dol==zero) 1.871 + addr1 = zero; 1.872 + } 1.873 + setdot(); 1.874 +} 1.875 + 1.876 +static void 1.877 +setnoaddr(void) 1.878 +{ 1.879 + if (addr2) 1.880 + error("Illegal address count"); 1.881 +} 1.882 + 1.883 +static void 1.884 +nonzero(void) 1.885 +{ 1.886 + if (addr1<=zero || addr2>dol) 1.887 + error("line out of range"); 1.888 +} 1.889 + 1.890 +static void 1.891 +newline(void) 1.892 +{ 1.893 + register int c; 1.894 + 1.895 + if ((c = getchr()) == '\n') 1.896 + return; 1.897 + if (c=='p' || c=='l' || c=='n') { 1.898 + pflag++; 1.899 + if (c=='l') 1.900 + listf++; 1.901 + else if (c=='n') 1.902 + numbf = 1; 1.903 + if (getchr() == '\n') 1.904 + return; 1.905 + } 1.906 + error("illegal suffix"); 1.907 +} 1.908 + 1.909 +static void 1.910 +filename(int comm) 1.911 +{ 1.912 + register char *p1, *p2; 1.913 + register int c, i; 1.914 + 1.915 + count = 0; 1.916 + c = getchr(); 1.917 + if (c=='\n' || c==EOF) { 1.918 + p1 = savedfile; 1.919 + if (*p1==0 && comm!='f') 1.920 + error("illegal or missing filename"); 1.921 + p2 = file; 1.922 + while (*p2++ = *p1++) 1.923 + ; 1.924 + return; 1.925 + } 1.926 + if (c!=' ') 1.927 + error("no space after command"); 1.928 + while ((c = getchr()) == ' ') 1.929 + ; 1.930 + if (c=='\n') 1.931 + error("illegal or missing filename"); 1.932 + i = 0; 1.933 + do { 1.934 + if (i >= FNSIZE) 1.935 + growfn("maximum of characters in file names reached"); 1.936 + file[i++] = c; 1.937 + if (c==' ' && file[0] != '!' || c==EOF) 1.938 + error("illegal or missing filename"); 1.939 + } while ((c = getchr()) != '\n'); 1.940 + file[i++] = 0; 1.941 + if ((savedfile[0]==0 || comm=='e' || comm=='f') && file[0] != '!') { 1.942 + p1 = savedfile; 1.943 + p2 = file; 1.944 + while (*p1++ = *p2++) 1.945 + ; 1.946 + } 1.947 +} 1.948 + 1.949 +static void 1.950 +exfile(void) 1.951 +{ 1.952 + sclose(io); 1.953 + io = -1; 1.954 + if (wrtemp) { 1.955 + extern int rename(const char *, const char *); 1.956 + if (rename(wrtemp, file) < 0) 1.957 + error("cannot create output file"); 1.958 + if (myuid == 0) 1.959 + chown(file, fstbuf.st_uid, fstbuf.st_gid); 1.960 + chmod(file, fstbuf.st_mode & 07777); 1.961 + free(wrtemp); 1.962 + wrtemp = NULL; 1.963 + } 1.964 + if (vflag) { 1.965 + putd(count); 1.966 + putchr('\n'); 1.967 + } 1.968 +} 1.969 + 1.970 +static void 1.971 +onintr(int signo) 1.972 +{ 1.973 + lastsig = signo; 1.974 + putchr('\n'); 1.975 + lastc = '\n'; 1.976 + if (readop) { 1.977 + puts("\007read may be incomplete - beware!\007"); 1.978 + fchange = 0; 1.979 + } 1.980 + error("interrupt"); 1.981 +} 1.982 + 1.983 +static void 1.984 +onhup(int signo) 1.985 +{ 1.986 + if (dol > zero && fchange) { 1.987 + addr1 = zero+1; 1.988 + addr2 = dol; 1.989 + io = creat("ed.hup", 0666); 1.990 + if (io < 0) { 1.991 + char *home = getenv("HOME"); 1.992 + if (home) { 1.993 + char *fn = malloc(strlen(home) + 10); 1.994 + if (fn) { 1.995 + strcpy(fn, home); 1.996 + strcat(fn, "/ed.hup"); 1.997 + io = creat(fn, 0666); 1.998 + } 1.999 + } 1.1000 + } 1.1001 + if (io >= 0) 1.1002 + putfile(); 1.1003 + } 1.1004 + fchange = 0; 1.1005 + status = 0200 | signo; 1.1006 + quit(0); 1.1007 +} 1.1008 + 1.1009 +static void 1.1010 +onpipe(int signo) 1.1011 +{ 1.1012 + lastsig = signo; 1.1013 + error("write or open on pipe failed"); 1.1014 +} 1.1015 + 1.1016 +static void 1.1017 +error(const char *s) 1.1018 +{ 1.1019 + error2(s, NULL); 1.1020 +} 1.1021 + 1.1022 +static void 1.1023 +error2(const char *s, const char *fn) 1.1024 +{ 1.1025 + register int c; 1.1026 + 1.1027 + wrapp = 0; 1.1028 + listf = 0; 1.1029 + numbf = 0; 1.1030 + errput(s, fn); 1.1031 + count = 0; 1.1032 + if (lseek(0, 0, SEEK_END) > 0) 1.1033 + status = 2; 1.1034 + pflag = 0; 1.1035 + if (globp) 1.1036 + lastc = '\n'; 1.1037 + globp = 0; 1.1038 + peekc = lastc; 1.1039 + if(lastc) 1.1040 + while ((c = getchr()) != '\n' && c != EOF) 1.1041 + ; 1.1042 + if (io > 0) { 1.1043 + sclose(io); 1.1044 + io = -1; 1.1045 + } 1.1046 + if (wrtemp) { 1.1047 + unlink(wrtemp); 1.1048 + free(wrtemp); 1.1049 + wrtemp = NULL; 1.1050 + } 1.1051 + longjmp(savej, 1); 1.1052 +} 1.1053 + 1.1054 +static void 1.1055 +errput(const char *s, const char *fn) 1.1056 +{ 1.1057 + prvmsg = s; 1.1058 + if (fn) { 1.1059 + putchr('?'); 1.1060 + puts(fn); 1.1061 + } else 1.1062 + puts("?"); 1.1063 + if (prhelp) 1.1064 + puts(s); 1.1065 +} 1.1066 + 1.1067 +static int 1.1068 +getchr(void) 1.1069 +{ 1.1070 + char c; 1.1071 + if (lastc=peekc) { 1.1072 + peekc = 0; 1.1073 + return(lastc); 1.1074 + } 1.1075 + if (globp) { 1.1076 + if ((lastc = *globp++) != 0) 1.1077 + return(lastc); 1.1078 + globp = 0; 1.1079 + return(EOF); 1.1080 + } 1.1081 + if (read(0, &c, 1) <= 0) 1.1082 + return(lastc = EOF); 1.1083 + lastc = c; 1.1084 + return(lastc); 1.1085 +} 1.1086 + 1.1087 +static int 1.1088 +gettty(void) 1.1089 +{ 1.1090 + register int c, i; 1.1091 + register char *gf; 1.1092 + 1.1093 + i = 0; 1.1094 + gf = globp; 1.1095 + while ((c = getchr()) != '\n') { 1.1096 + if (c==EOF) { 1.1097 + if (gf) 1.1098 + peekc = c; 1.1099 + return(c); 1.1100 + } 1.1101 + if (c == 0) 1.1102 + continue; 1.1103 + if (i >= LBSIZE) 1.1104 + growlb("line too long"); 1.1105 + linebuf[i++] = c; 1.1106 + } 1.1107 + if (i >= LBSIZE-2) 1.1108 + growlb("line too long"); 1.1109 + linebuf[i++] = 0; 1.1110 + if (linebuf[0]=='.' && linebuf[1]==0) 1.1111 + return(EOF); 1.1112 +#if !defined (SUS) && !defined (SU3) 1.1113 + if (linebuf[0]=='\\' && linebuf[1]=='.' && linebuf[2]==0) 1.1114 + linebuf[0]='.', linebuf[1]=0; 1.1115 +#endif 1.1116 + return(0); 1.1117 +} 1.1118 + 1.1119 +static long 1.1120 +getnum(void) 1.1121 +{ 1.1122 + char scount[20]; 1.1123 + int i; 1.1124 + 1.1125 + i = 0; 1.1126 + while ((peekc=getchr()) >= '0' && peekc <= '9' && i < sizeof scount) { 1.1127 + scount[i++] = peekc; 1.1128 + peekc = 0; 1.1129 + } 1.1130 + scount[i] = '\0'; 1.1131 + return i ? atol(scount) : -1; 1.1132 +} 1.1133 + 1.1134 +static int 1.1135 +getfile(void) 1.1136 +{ 1.1137 + register int c, i, j; 1.1138 + static int nextj; 1.1139 + 1.1140 + i = 0; 1.1141 + j = nextj; 1.1142 + do { 1.1143 + if (--ninbuf < 0) { 1.1144 + if (ioeof || (ninbuf=read(io, genbuf, LBSIZE)-1) < 0) { 1.1145 + if (ioeof == 0 && ninbuf < -1) { 1.1146 + puts("input error"); 1.1147 + status = 1; 1.1148 + } 1.1149 + if (i > 0) { 1.1150 + puts("'\\n' appended"); 1.1151 + c = '\n'; 1.1152 + ioeof = 1; 1.1153 + goto wrc; 1.1154 + } 1.1155 + return(EOF); 1.1156 + } 1.1157 + j = 0; 1.1158 + } 1.1159 + c = genbuf[j++]&0377; 1.1160 + wrc: if (i >= LBSIZE) { 1.1161 + lastc = '\n'; 1.1162 + growlb("line too long"); 1.1163 + } 1.1164 + linebuf[i++] = c ? c : '\n'; 1.1165 + count++; 1.1166 + } while (c != '\n'); 1.1167 + linebuf[--i] = 0; 1.1168 + nextj = j; 1.1169 + if (rspec && dot == zero) 1.1170 + fspec(linebuf); 1.1171 + if (maxlength && i > maxlength) { 1.1172 + putstr("line too long: lno = "); 1.1173 + putd((dot - zero+1)&MAXCNT); 1.1174 + putchr('\n'); 1.1175 + } 1.1176 + return(0); 1.1177 +} 1.1178 + 1.1179 +static void 1.1180 +putfile(void) 1.1181 +{ 1.1182 + long *a1; 1.1183 + int n; 1.1184 + register char *fp, *lp; 1.1185 + register int nib; 1.1186 + 1.1187 + nib = 512; 1.1188 + fp = genbuf; 1.1189 + a1 = addr1; 1.1190 + do { 1.1191 + lp = getline(*a1++, 0); 1.1192 + if (maxlength) { 1.1193 + for (n = 0; lp[n]; n++); 1.1194 + if (n > maxlength) { 1.1195 + putstr("line too long: lno = "); 1.1196 + putd((a1-1 - zero)&MAXCNT); 1.1197 + putchr('\n'); 1.1198 + } 1.1199 + } 1.1200 + for (;;) { 1.1201 + if (--nib < 0) { 1.1202 + n = fp-genbuf; 1.1203 + if(write(io, genbuf, n) != n) 1.1204 + error("write error"); 1.1205 + nib = 511; 1.1206 + fp = genbuf; 1.1207 + } 1.1208 + count++; 1.1209 + if ((*fp++ = *lp++) == 0) { 1.1210 + fp[-1] = '\n'; 1.1211 + break; 1.1212 + } else if (fp[-1] == '\n') 1.1213 + fp[-1] = '\0'; 1.1214 + } 1.1215 + } while (a1 <= addr2); 1.1216 + n = fp-genbuf; 1.1217 + if(write(io, genbuf, n) != n) 1.1218 + error("write error"); 1.1219 +} 1.1220 + 1.1221 +static int 1.1222 +append(int (*f)(void), long *a) 1.1223 +{ 1.1224 + register long *a1, *a2, *rdot; 1.1225 + int nline, tl; 1.1226 + 1.1227 + nline = 0; 1.1228 + dot = a; 1.1229 + while ((*f)() == 0) { 1.1230 + if ((dol-zero)+1 >= nlall) { 1.1231 + long *ozero = zero; 1.1232 + nlall += 512; 1.1233 + if ((zero = realloc(zero, nlall*sizeof *zero))==NULL) { 1.1234 + lastc = '\n'; 1.1235 + zero = ozero; 1.1236 + error("out of memory for append"); 1.1237 + } 1.1238 + dot += zero - ozero; 1.1239 + dol += zero - ozero; 1.1240 + addr1 += zero - ozero; 1.1241 + addr2 += zero - ozero; 1.1242 + if (unddot) { 1.1243 + unddot += zero - ozero; 1.1244 + unddol += zero - ozero; 1.1245 + } 1.1246 + if (undzero) { 1.1247 + ozero = undzero; 1.1248 + if ((undzero = realloc(undzero, 1.1249 + nlall*sizeof *undzero)) == 0) { 1.1250 + puts("no memory for undo"); 1.1251 + free(ozero); 1.1252 + } 1.1253 + } 1.1254 + } 1.1255 + tl = putline(); 1.1256 + nline++; 1.1257 + a1 = ++dol; 1.1258 + a2 = a1+1; 1.1259 + rdot = ++dot; 1.1260 + while (a1 > rdot) 1.1261 + *--a2 = *--a1; 1.1262 + *rdot = tl; 1.1263 + } 1.1264 + return(nline); 1.1265 +} 1.1266 + 1.1267 +static void 1.1268 +callunix(void) 1.1269 +{ 1.1270 + char *line; 1.1271 + void (*savint)(int); 1.1272 + pid_t pid, rpid; 1.1273 + int retcode; 1.1274 + 1.1275 + setnoaddr(); 1.1276 + line = readcmd(); 1.1277 + if ((pid = fork()) == 0) { 1.1278 + sigset(SIGHUP, oldhup); 1.1279 + sigset(SIGQUIT, oldquit); 1.1280 + sigset(SIGPIPE, oldpipe); 1.1281 + execl(SHELL, "sh", "-c", line, NULL); 1.1282 + _exit(0100); 1.1283 + } else if (pid < 0) 1.1284 + error("fork failed - try again"); 1.1285 + savint = sigset(SIGINT, SIG_IGN); 1.1286 + while ((rpid = wait(&retcode)) != pid && rpid != -1) 1.1287 + ; 1.1288 + sigset(SIGINT, savint); 1.1289 + if (vflag) 1.1290 + puts("!"); 1.1291 +} 1.1292 + 1.1293 +#define cmadd(c) ((i>=cmsize ? \ 1.1294 + ((line=realloc(line,cmsize+=128)) == 0 ? \ 1.1295 + (error("line too long"),0) : 0, 0) \ 1.1296 + : 0), line[i++]=(c)) 1.1297 + 1.1298 +static char * 1.1299 +readcmd(void) 1.1300 +{ 1.1301 + static char *line, *prev; 1.1302 + static int cmsize, pvsize; 1.1303 + char *pp; 1.1304 + int c, mod = 0, i; 1.1305 + 1.1306 + i = 0; 1.1307 + if ((c = getchr()) == '!') { 1.1308 + for (pp = prev; *pp; pp++) 1.1309 + line[i++] = *pp; 1.1310 + mod = 1; 1.1311 + c = getchr(); 1.1312 + } 1.1313 + while (c != '\n' && c != EOF) { 1.1314 + if (c == '\\') { 1.1315 + c = getchr(); 1.1316 + if (c != '%') 1.1317 + cmadd('\\'); 1.1318 + cmadd(c); 1.1319 + } else if (c == '%') { 1.1320 + for (pp = savedfile; *pp; pp++) 1.1321 + cmadd(*pp); 1.1322 + mod = 1; 1.1323 + } else 1.1324 + cmadd(c); 1.1325 + c = getchr(); 1.1326 + } 1.1327 + cmadd('\0'); 1.1328 + if (pvsize < cmsize && (prev = realloc(prev, pvsize=cmsize)) == 0) 1.1329 + error("line too long"); 1.1330 + strcpy(prev, line); 1.1331 + if (mod) 1.1332 + nlputs(line); 1.1333 + return line; 1.1334 +} 1.1335 + 1.1336 +static void 1.1337 +quit(int signo) 1.1338 +{ 1.1339 + lastsig = signo; 1.1340 + if (vflag && fchange) { 1.1341 + fchange = 0; 1.1342 + error("warning: expecting `w'"); 1.1343 + } 1.1344 + if (wrtemp) 1.1345 + unlink(wrtemp); 1.1346 + unlink(tfname); 1.1347 + exit(status); 1.1348 +} 1.1349 + 1.1350 +static void 1.1351 +delete(void) 1.1352 +{ 1.1353 + setdot(); 1.1354 + newline(); 1.1355 + nonzero(); 1.1356 + checkpoint(); 1.1357 + rdelete(addr1, addr2); 1.1358 +} 1.1359 + 1.1360 +static void 1.1361 +rdelete(long *ad1, long *ad2) 1.1362 +{ 1.1363 + register long *a1, *a2, *a3; 1.1364 + 1.1365 + a1 = ad1; 1.1366 + a2 = ad2+1; 1.1367 + a3 = dol; 1.1368 + dol -= a2 - a1; 1.1369 + do { 1.1370 + *a1++ = *a2++; 1.1371 + } while (a2 <= a3); 1.1372 + a1 = ad1; 1.1373 + if (a1 > dol) 1.1374 + a1 = dol; 1.1375 + dot = a1; 1.1376 + fchange = 1; 1.1377 +} 1.1378 + 1.1379 +static void 1.1380 +gdelete(void) 1.1381 +{ 1.1382 + register long *a1, *a2, *a3; 1.1383 + 1.1384 + a3 = dol; 1.1385 + for (a1=zero+1; (*a1&01)==0; a1++) 1.1386 + if (a1>=a3) 1.1387 + return; 1.1388 + for (a2=a1+1; a2<=a3;) { 1.1389 + if (*a2&01) { 1.1390 + a2++; 1.1391 + dot = a1; 1.1392 + } else 1.1393 + *a1++ = *a2++; 1.1394 + } 1.1395 + dol = a1-1; 1.1396 + if (dot>dol) 1.1397 + dot = dol; 1.1398 + fchange = 1; 1.1399 +} 1.1400 + 1.1401 +static char * 1.1402 +getline(long tl, int nulterm) 1.1403 +{ 1.1404 + register char *bp, *lp; 1.1405 + register long nl; 1.1406 + 1.1407 + lp = linebuf; 1.1408 + bp = getblock(tl, READ); 1.1409 + nl = nleft; 1.1410 + tl &= ~0377; 1.1411 + while (*lp++ = *bp++) { 1.1412 + if (lp[-1] == '\n' && nulterm) { 1.1413 + lp[-1] = '\0'; 1.1414 + break; 1.1415 + } 1.1416 + if (--nl == 0) { 1.1417 + bp = getblock(tl+=0400, READ); 1.1418 + nl = nleft; 1.1419 + } 1.1420 + } 1.1421 + return(linebuf); 1.1422 +} 1.1423 + 1.1424 +static int 1.1425 +putline(void) 1.1426 +{ 1.1427 + register char *bp, *lp; 1.1428 + register long nl; 1.1429 + long tl; 1.1430 + 1.1431 + fchange = 1; 1.1432 + lp = linebuf; 1.1433 + tl = tline; 1.1434 + bp = getblock(tl, WRITE); 1.1435 + nl = nleft; 1.1436 + tl &= ~0377; 1.1437 + while (*bp = *lp++) { 1.1438 + if (*bp++ == '\n' && insub) { 1.1439 + *--bp = 0; 1.1440 + linebp = lp; 1.1441 + break; 1.1442 + } 1.1443 + if (--nl == 0) { 1.1444 + bp = getblock(tl+=0400, WRITE); 1.1445 + nl = nleft; 1.1446 + } 1.1447 + } 1.1448 + nl = tline; 1.1449 + tline += (((lp-linebuf)+03)>>1)&(MAXCNT-1); 1.1450 + return(nl); 1.1451 +} 1.1452 + 1.1453 +static char * 1.1454 +getblock(long atl, long iof) 1.1455 +{ 1.1456 + register long bno, off; 1.1457 + 1.1458 + bno = (atl>>8)&BLKMSK; 1.1459 + off = (atl<<1)&0774; 1.1460 + if (bno >= BLKMSK) { 1.1461 + lastc = '\n'; 1.1462 + error("temp file too big"); 1.1463 + } 1.1464 + nleft = 512 - off; 1.1465 + if (bno==iblock) { 1.1466 + ichanged |= iof; 1.1467 + return(ibuff+off); 1.1468 + } 1.1469 + if (bno==oblock) 1.1470 + return(obuff+off); 1.1471 + if (iof==READ) { 1.1472 + if (ichanged) 1.1473 + blkio(iblock, ibuff, 1); 1.1474 + ichanged = 0; 1.1475 + iblock = bno; 1.1476 + blkio(bno, ibuff, 0); 1.1477 + return(ibuff+off); 1.1478 + } 1.1479 + if (oblock>=0) 1.1480 + blkio(oblock, obuff, 1); 1.1481 + oblock = bno; 1.1482 + return(obuff+off); 1.1483 +} 1.1484 + 1.1485 +static void 1.1486 +blkio(long b, char *buf, int wr) 1.1487 +{ 1.1488 + lseek(tfile, b<<9, SEEK_SET); 1.1489 + if ((wr ? write(tfile, buf, 512) : read (tfile, buf, 512)) != 512) { 1.1490 + status = 1; 1.1491 + error("I/O error on temp file"); 1.1492 + } 1.1493 +} 1.1494 + 1.1495 +static void 1.1496 +init(void) 1.1497 +{ 1.1498 + register long *markp; 1.1499 + 1.1500 + tline = 2; 1.1501 + for (markp = names; markp < &names[26]; markp++) 1.1502 + *markp = 0; 1.1503 + for (markp = undnames; markp < &undnames[26]; markp++) 1.1504 + *markp = 0; 1.1505 + subnewa = 0; 1.1506 + anymarks = 0; 1.1507 + iblock = -1; 1.1508 + oblock = -1; 1.1509 + ichanged = 0; 1.1510 + tfile = maketf(tfile); 1.1511 + dot = dol = zero; 1.1512 + unddot = NULL; 1.1513 +} 1.1514 + 1.1515 +static void 1.1516 +global(int k, int ia) 1.1517 +{ 1.1518 + register int c; 1.1519 + register long *a1; 1.1520 + static char *globuf; 1.1521 + char mb[MB_LEN_MAX+1]; 1.1522 + int spflag = 0; 1.1523 + 1.1524 + if (globp) 1.1525 + error("multiple globals not allowed"); 1.1526 + setall(); 1.1527 + nonzero(); 1.1528 + if ((c=GETWC(mb))=='\n') 1.1529 + error("incomplete global expression"); 1.1530 + compile(NULL, expbuf, &expbuf[ESIZE], c); 1.1531 + if (!ia) { 1.1532 + globrd(&globuf, EOF); 1.1533 + if (globuf[0] == '\n') 1.1534 + globuf[0] = 'p', globuf[1] = '\n', globuf[2] = '\0'; 1.1535 + } else { 1.1536 + newline(); 1.1537 + spflag = pflag; 1.1538 + pflag = 0; 1.1539 + } 1.1540 + checkpoint(); 1.1541 + for (a1=zero; a1<=dol; a1++) { 1.1542 + *a1 &= ~01; 1.1543 + if (a1>=addr1 && a1<=addr2 && execute(0, a1, 0)==k) 1.1544 + *a1 |= 01; 1.1545 + } 1.1546 + /* 1.1547 + * Special case: g/.../d (avoid n^2 algorithm) 1.1548 + */ 1.1549 + if (!ia && globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') { 1.1550 + gdelete(); 1.1551 + return; 1.1552 + } 1.1553 + for (a1=zero; a1<=dol; a1++) { 1.1554 + if (*a1 & 01) { 1.1555 + *a1 &= ~01; 1.1556 + dot = a1; 1.1557 + if (ia) { 1.1558 + puts(getline(*a1, 0)); 1.1559 + if ((c = getchr()) == EOF) 1.1560 + error("command expected"); 1.1561 + if (c == 'a' || c == 'c' || c == 'i') 1.1562 + error("a, i, or c not allowed in G"); 1.1563 + else if (c == '&') { 1.1564 + if ((c = getchr()) != '\n') 1.1565 + error("end of line expected"); 1.1566 + if (globuf == 0 || *globuf == 0) 1.1567 + error("no remembered command"); 1.1568 + } else if (c == '\n') { 1.1569 + a1 = zero; 1.1570 + continue; 1.1571 + } else 1.1572 + globrd(&globuf, c); 1.1573 + } 1.1574 + globp = globuf; 1.1575 + commands(); 1.1576 + globp = NULL; 1.1577 + a1 = zero; 1.1578 + } 1.1579 + } 1.1580 + if (ia) 1.1581 + pflag = spflag; 1.1582 +} 1.1583 + 1.1584 +static void 1.1585 +globrd(char **globuf, register int c) 1.1586 +{ 1.1587 + register int i; 1.1588 + 1.1589 + if (*globuf == 0 && (*globuf = malloc(GBSIZE=256)) == 0) 1.1590 + error("global too long"); 1.1591 + i = 0; 1.1592 + if (c != EOF) 1.1593 + (*globuf)[i++] = c; 1.1594 + while ((c = getchr()) != '\n') { 1.1595 + if (c==EOF) 1.1596 + error("incomplete global expression"); 1.1597 + if (c=='\\') { 1.1598 + c = getchr(); 1.1599 + if (c!='\n') 1.1600 + (*globuf)[i++] = '\\'; 1.1601 + } 1.1602 + (*globuf)[i++] = c; 1.1603 + if (i>=GBSIZE-4 && (*globuf=realloc(*globuf,GBSIZE+=256)) == 0) 1.1604 + error("global too long"); 1.1605 + } 1.1606 + (*globuf)[i++] = '\n'; 1.1607 + (*globuf)[i++] = 0; 1.1608 +} 1.1609 + 1.1610 +static void 1.1611 +join(void) 1.1612 +{ 1.1613 + register int i, j; 1.1614 + register long *a1; 1.1615 + 1.1616 + j = 0; 1.1617 + for (a1=addr1; a1<=addr2; a1++) { 1.1618 + i = getline(*a1, 0) - linebuf; 1.1619 + while (genbuf[j] = linebuf[i++]) 1.1620 + if (j++ >= LBSIZE-2) 1.1621 + growlb("line too long"); 1.1622 + } 1.1623 + i = 0; 1.1624 + j = 0; 1.1625 + while (linebuf[i++] = genbuf[j++]) 1.1626 + ; 1.1627 + *addr1 = putline(); 1.1628 + if (addr1<addr2) 1.1629 + rdelete(addr1+1, addr2); 1.1630 + dot = addr1; 1.1631 +} 1.1632 + 1.1633 +static void 1.1634 +substitute(int inglob) 1.1635 +{ 1.1636 + register long *markp; 1.1637 + register long *a1; 1.1638 + intptr_t nl; 1.1639 + int gsubf; 1.1640 + 1.1641 + checkpoint(); 1.1642 + gsubf = compsub(); 1.1643 + insub = 1; 1.1644 + for (a1 = addr1; a1 <= addr2; a1++) { 1.1645 + long *ozero; 1.1646 + if (execute(0, a1, 1)==0) 1.1647 + continue; 1.1648 + inglob |= dosub(gsubf < 2); 1.1649 + if (gsubf) { 1.1650 + int i = 1; 1.1651 + 1.1652 + while (*loc2) { 1.1653 + if (execute(1, NULL, 1)==0) 1.1654 + break; 1.1655 + inglob |= dosub(gsubf == -1 || ++i == gsubf); 1.1656 + } 1.1657 + } 1.1658 + subnewa = putline(); 1.1659 + *a1 &= ~01; 1.1660 + if (anymarks) { 1.1661 + for (markp = names; markp < &names[26]; markp++) 1.1662 + if (*markp == *a1) 1.1663 + *markp = subnewa; 1.1664 + } 1.1665 + *a1 = subnewa; 1.1666 + ozero = zero; 1.1667 + nl = append(getsub, a1); 1.1668 + nl += zero-ozero; 1.1669 + a1 += nl; 1.1670 + addr2 += nl; 1.1671 + } 1.1672 + insub = 0; 1.1673 + if (inglob==0) 1.1674 + error("no match"); 1.1675 +} 1.1676 + 1.1677 +static int 1.1678 +compsub(void) 1.1679 +{ 1.1680 + register int seof, c, i; 1.1681 + static char *oldrhs; 1.1682 + static int orhssz; 1.1683 + char mb[MB_LEN_MAX+1]; 1.1684 + 1.1685 + if ((seof = GETWC(mb)) == '\n' || seof == ' ') 1.1686 + error("illegal or missing delimiter"); 1.1687 + nodelim = 0; 1.1688 + compile(NULL, expbuf, &expbuf[ESIZE], seof); 1.1689 + i = 0; 1.1690 + for (;;) { 1.1691 + c = GETWC(mb); 1.1692 + if (c=='\\') { 1.1693 + if (i >= RHSIZE-2) 1.1694 + growrhs("replacement string too long"); 1.1695 + rhsbuf[i++] = c; 1.1696 + c = GETWC(mb); 1.1697 + } else if (c=='\n') { 1.1698 + if (globp && *globp) { 1.1699 + if (i >= RHSIZE-2) 1.1700 + growrhs("replacement string too long"); 1.1701 + rhsbuf[i++] = '\\'; 1.1702 + } 1.1703 + else if (nodelim) 1.1704 + error("illegal or missing delimiter"); 1.1705 + else { 1.1706 + peekc = c; 1.1707 + pflag++; 1.1708 + break; 1.1709 + } 1.1710 + } else if (c==seof) 1.1711 + break; 1.1712 + for (c = 0; c==0 || mb[c]; c++) { 1.1713 + if (i >= RHSIZE-2) 1.1714 + growrhs("replacement string too long"); 1.1715 + rhsbuf[i++] = mb[c]; 1.1716 + } 1.1717 + } 1.1718 + rhsbuf[i++] = 0; 1.1719 + if (rhsbuf[0] == '%' && rhsbuf[1] == 0) { 1.1720 + if (orhssz == 0) 1.1721 + error("no remembered replacement string"); 1.1722 + strcpy(rhsbuf, oldrhs); 1.1723 + } else { 1.1724 + if (orhssz < RHSIZE && 1.1725 + (oldrhs = realloc(oldrhs, orhssz=RHSIZE)) == 0) 1.1726 + error("replacement string too long"); 1.1727 + strcpy(oldrhs, rhsbuf); 1.1728 + } 1.1729 + if ((peekc = getchr()) == 'g') { 1.1730 + peekc = 0; 1.1731 + newline(); 1.1732 + return(-1); 1.1733 + } else if (peekc >= '0' && peekc <= '9') { 1.1734 + c = getnum(); 1.1735 + if (c < 1 || c > LBSIZE) 1.1736 + error("invalid count"); 1.1737 + newline(); 1.1738 + return c; 1.1739 + } 1.1740 + newline(); 1.1741 + return(0); 1.1742 +} 1.1743 + 1.1744 +static int 1.1745 +getsub(void) 1.1746 +{ 1.1747 + register char *p1, *p2; 1.1748 + 1.1749 + p1 = linebuf; 1.1750 + if ((p2 = linebp) == 0) 1.1751 + return(EOF); 1.1752 + while (*p1++ = *p2++) 1.1753 + ; 1.1754 + linebp = 0; 1.1755 + return(0); 1.1756 +} 1.1757 + 1.1758 +static int 1.1759 +dosub(int really) 1.1760 +{ 1.1761 + register char *lp, *sp; 1.1762 + register int i, j, k; 1.1763 + int c; 1.1764 + 1.1765 + if (!really) 1.1766 + goto copy; 1.1767 + i = 0; 1.1768 + j = 0; 1.1769 + k = 0; 1.1770 + while (&linebuf[i] < loc1) 1.1771 + genbuf[j++] = linebuf[i++]; 1.1772 + while (c = rhsbuf[k++]&0377) { 1.1773 + if (c=='&') { 1.1774 + j = place(j, loc1, loc2); 1.1775 + continue; 1.1776 + } else if (c == '\\') { 1.1777 + c = rhsbuf[k++]&0377; 1.1778 + if (c >='1' && c < nbra+'1') { 1.1779 + j = place(j, braslist[c-'1'], braelist[c-'1']); 1.1780 + continue; 1.1781 + } 1.1782 + } 1.1783 + if (j >= LBSIZE) 1.1784 + growlb("line too long"); 1.1785 + genbuf[j++] = c; 1.1786 + } 1.1787 + i = loc2 - linebuf; 1.1788 + loc2 = j + linebuf; 1.1789 +#if defined (SUS) || defined (SU3) || defined (S42) 1.1790 + if (loc1 == &linebuf[i]) { 1.1791 + int n; 1.1792 + wchar_t wc; 1.1793 + if (mb_cur_max > 1 && (n = mbtowc(&wc, loc2, mb_cur_max)) > 0) 1.1794 + loc2 += n; 1.1795 + else 1.1796 + loc2++; 1.1797 + } 1.1798 +#endif /* SUS || SU3 || S42 */ 1.1799 + while (genbuf[j++] = linebuf[i++]) 1.1800 + if (j >= LBSIZE) 1.1801 + growlb("line too long"); 1.1802 + if (really) { 1.1803 + lp = linebuf; 1.1804 + sp = genbuf; 1.1805 + } else { 1.1806 + copy: sp = linebuf; 1.1807 + lp = genbuf; 1.1808 + } 1.1809 + while (*lp++ = *sp++) 1.1810 + ; 1.1811 + return really; 1.1812 +} 1.1813 + 1.1814 +static int 1.1815 +place(register int j, register const char *l1, register const char *l2) 1.1816 +{ 1.1817 + 1.1818 + while (l1 < l2) { 1.1819 + genbuf[j++] = *l1++; 1.1820 + if (j >= LBSIZE) 1.1821 + growlb("line too long"); 1.1822 + } 1.1823 + return(j); 1.1824 +} 1.1825 + 1.1826 +static void 1.1827 +move(int cflag) 1.1828 +{ 1.1829 + register long *adt, *ad1, *ad2; 1.1830 + 1.1831 + setdot(); 1.1832 + nonzero(); 1.1833 + if ((adt = address())==0) 1.1834 + error("illegal move destination"); 1.1835 + newline(); 1.1836 + checkpoint(); 1.1837 + if (cflag) { 1.1838 + long *ozero; 1.1839 + intptr_t delta; 1.1840 + ad1 = dol; 1.1841 + ozero = zero; 1.1842 + append(getcopy, ad1++); 1.1843 + ad2 = dol; 1.1844 + delta = zero - ozero; 1.1845 + ad1 += delta; 1.1846 + adt += delta; 1.1847 + } else { 1.1848 + ad2 = addr2; 1.1849 + for (ad1 = addr1; ad1 <= ad2;) 1.1850 + *ad1++ &= ~01; 1.1851 + ad1 = addr1; 1.1852 + } 1.1853 + ad2++; 1.1854 + if (adt<ad1) { 1.1855 + dot = adt + (ad2-ad1); 1.1856 + if ((++adt)==ad1) 1.1857 + return; 1.1858 + reverse(adt, ad1); 1.1859 + reverse(ad1, ad2); 1.1860 + reverse(adt, ad2); 1.1861 + } else if (adt >= ad2) { 1.1862 + dot = adt++; 1.1863 + reverse(ad1, ad2); 1.1864 + reverse(ad2, adt); 1.1865 + reverse(ad1, adt); 1.1866 + } else 1.1867 + error("illegal move destination"); 1.1868 + fchange = 1; 1.1869 +} 1.1870 + 1.1871 +static void 1.1872 +reverse(register long *a1, register long *a2) 1.1873 +{ 1.1874 + register int t; 1.1875 + 1.1876 + for (;;) { 1.1877 + t = *--a2; 1.1878 + if (a2 <= a1) 1.1879 + return; 1.1880 + *a2 = *a1; 1.1881 + *a1++ = t; 1.1882 + } 1.1883 +} 1.1884 + 1.1885 +static int 1.1886 +getcopy(void) 1.1887 +{ 1.1888 + if (addr1 > addr2) 1.1889 + return(EOF); 1.1890 + getline(*addr1++, 0); 1.1891 + return(0); 1.1892 +} 1.1893 + 1.1894 +static int 1.1895 +execute(int gf, long *addr, int subst) 1.1896 +{ 1.1897 + register char *p1, *p2, c; 1.1898 + 1.1899 + for (c=0; c<NBRA; c++) { 1.1900 + braslist[c&0377] = 0; 1.1901 + braelist[c&0377] = 0; 1.1902 + } 1.1903 + if (gf) { 1.1904 + if (circf) 1.1905 + return(0); 1.1906 + p1 = linebuf; 1.1907 + p2 = genbuf; 1.1908 + while (*p1++ = *p2++) 1.1909 + ; 1.1910 + locs = p1 = loc2; 1.1911 + } else { 1.1912 + if (addr==zero) 1.1913 + return(0); 1.1914 + p1 = getline(*addr, 1); 1.1915 + locs = 0; 1.1916 + } 1.1917 + needsub = subst; 1.1918 + return step(p1, expbuf); 1.1919 +} 1.1920 + 1.1921 +static void 1.1922 +cmplerr(int c) 1.1923 +{ 1.1924 + const char *msg; 1.1925 + 1.1926 +#if !defined (SUS) && !defined (S42) && !defined (SU3) 1.1927 + expbuf[0] = 0; 1.1928 +#endif 1.1929 + switch (c) { 1.1930 + case 11: 1.1931 + msg = "Range endpoint too large"; 1.1932 + break; 1.1933 + case 16: 1.1934 + msg = "bad number"; 1.1935 + break; 1.1936 + case 25: 1.1937 + msg = "`\\digit' out of range"; 1.1938 + break; 1.1939 + case 36: 1.1940 + msg = "illegal or missing delimiter"; 1.1941 + break; 1.1942 + case 41: 1.1943 + msg = "no remembered search string"; 1.1944 + break; 1.1945 + case 42: 1.1946 + msg = "'\\( \\)' imbalance"; 1.1947 + break; 1.1948 + case 43: 1.1949 + msg = "Too many `\\(' s"; 1.1950 + break; 1.1951 + case 44: 1.1952 + msg = "more than 2 numbers given"; 1.1953 + break; 1.1954 + case 45: 1.1955 + msg = "'\\}' expected"; 1.1956 + break; 1.1957 + case 46: 1.1958 + msg = "first number exceeds second"; 1.1959 + break; 1.1960 + case 49: 1.1961 + msg = "'[ ]' imbalance"; 1.1962 + break; 1.1963 + case 50: 1.1964 + msg = "regular expression overflow"; 1.1965 + break; 1.1966 + case 67: 1.1967 + msg = "illegal byte sequence"; 1.1968 + break; 1.1969 + default: 1.1970 + msg = "regular expression error"; 1.1971 + break; 1.1972 + } 1.1973 + error(msg); 1.1974 +} 1.1975 + 1.1976 +static void 1.1977 +doprnt(long *bot, long *top) 1.1978 +{ 1.1979 + long *a1; 1.1980 + 1.1981 + a1 = bot; 1.1982 + do { 1.1983 + if (numbf ^ Nflag) { 1.1984 + putd(a1-zero); 1.1985 + putchr('\t'); 1.1986 + } 1.1987 + nlputs(getline(*a1++, 0)); 1.1988 + } while (a1 <= top); 1.1989 + pflag = 0; 1.1990 + listf = 0; 1.1991 + numbf = 0; 1.1992 +} 1.1993 + 1.1994 +static void 1.1995 +putd(long c) 1.1996 +{ 1.1997 + register int r; 1.1998 + 1.1999 + r = c%10; 1.2000 + c /= 10; 1.2001 + if (c) 1.2002 + putd(c); 1.2003 + putchr(r + '0'); 1.2004 +} 1.2005 + 1.2006 +static void 1.2007 +nlputs(register const char *sp) 1.2008 +{ 1.2009 + if (listf) 1.2010 + list(sp); 1.2011 + else if (tabstops) 1.2012 + expand(sp); 1.2013 + else 1.2014 + puts(sp); 1.2015 +} 1.2016 + 1.2017 +static void 1.2018 +puts(register const char *sp) 1.2019 +{ 1.2020 + while (*sp) { 1.2021 + if (*sp != '\n') 1.2022 + putchr(*sp++ & 0377); 1.2023 + else 1.2024 + sp++, putchr('\0'); 1.2025 + } 1.2026 + putchr('\n'); 1.2027 +} 1.2028 + 1.2029 +static void 1.2030 +list(const char *lp) 1.2031 +{ 1.2032 + int col, n; 1.2033 + wchar_t c; 1.2034 + 1.2035 + col = numbf ^ Nflag ? 8 : 0; 1.2036 + while (*lp) { 1.2037 + if (mb_cur_max > 1 && *lp&0200) 1.2038 + n = mbtowc(&c, lp, mb_cur_max); 1.2039 + else { 1.2040 + n = 1; 1.2041 + c = *lp&0377; 1.2042 + } 1.2043 + if (col+1 >= 72) { 1.2044 + col = 0; 1.2045 + putchr('\\'); 1.2046 + putchr('\n'); 1.2047 + } 1.2048 + if (n<0 || 1.2049 +#if defined (SUS) || defined (S42) || defined (SU3) 1.2050 + c == '\\' || 1.2051 +#endif /* SUS || S42 || SU3 */ 1.2052 + !(mb_cur_max>1 ? iswprint(c) : isprint(c))) { 1.2053 + if (n<0) 1.2054 + n = 1; 1.2055 + while (n--) 1.2056 + col += lstchr(*lp++&0377); 1.2057 + } else if (mb_cur_max>1) { 1.2058 + col += wcwidth(c); 1.2059 + while (n--) 1.2060 + putchr(*lp++&0377); 1.2061 + } else { 1.2062 + putchr(*lp++&0377); 1.2063 + col++; 1.2064 + } 1.2065 + } 1.2066 +#if defined (SUS) || defined (S42) || defined (SU3) 1.2067 + putchr('$'); 1.2068 +#endif 1.2069 + putchr('\n'); 1.2070 +} 1.2071 + 1.2072 +static int 1.2073 +lstchr(int c) 1.2074 +{ 1.2075 + int cad = 1, d; 1.2076 + 1.2077 +#if !defined (SUS) && !defined (S42) && !defined (SU3) 1.2078 + if (c=='\t') { 1.2079 + c = '>'; 1.2080 + goto esc; 1.2081 + } 1.2082 + if (c=='\b') { 1.2083 + c = '<'; 1.2084 + esc: 1.2085 + putchr('-'); 1.2086 + putchr('\b'); 1.2087 + putchr(c); 1.2088 + } else if (c == '\n') { 1.2089 + putchr('\\'); 1.2090 + putchr('0'); 1.2091 + putchr('0'); 1.2092 + putchr('0'); 1.2093 + cad = 4; 1.2094 +#else /* !SUS, !S42, !SU3 */ 1.2095 + if (c == '\n') 1.2096 + c = '\0'; 1.2097 + if (c == '\\') { 1.2098 + putchr('\\'); 1.2099 + putchr('\\'); 1.2100 + cad = 2; 1.2101 + } else if (c == '\a') { 1.2102 + putchr('\\'); 1.2103 + putchr('a'); 1.2104 + cad = 2; 1.2105 + } else if (c == '\b') { 1.2106 + putchr('\\'); 1.2107 + putchr('b'); 1.2108 + cad = 2; 1.2109 + } else if (c == '\f') { 1.2110 + putchr('\\'); 1.2111 + putchr('f'); 1.2112 + cad = 2; 1.2113 + } else if (c == '\r') { 1.2114 + putchr('\\'); 1.2115 + putchr('r'); 1.2116 + cad = 2; 1.2117 + } else if (c == '\t') { 1.2118 + putchr('\\'); 1.2119 + putchr('t'); 1.2120 + cad = 2; 1.2121 + } else if (c == '\v') { 1.2122 + putchr('\\'); 1.2123 + putchr('v'); 1.2124 + cad = 2; 1.2125 +#endif /* !SUS, !S42, !SU3 */ 1.2126 + } else { 1.2127 + putchr('\\'); 1.2128 + putchr(((c&~077)>>6)+'0'); 1.2129 + c &= 077; 1.2130 + d = c & 07; 1.2131 + putchr(c > d ? ((c-d)>>3)+'0' : '0'); 1.2132 + putchr(d+'0'); 1.2133 + cad = 4; 1.2134 + } 1.2135 + return cad; 1.2136 +} 1.2137 + 1.2138 +static void 1.2139 +putstr(const char *s) 1.2140 +{ 1.2141 + while (*s) 1.2142 + putchr(*s++); 1.2143 +} 1.2144 + 1.2145 +static char line[70]; 1.2146 +static char *linp = line; 1.2147 + 1.2148 +static void 1.2149 +putchr(int ac) 1.2150 +{ 1.2151 + register char *lp; 1.2152 + register int c; 1.2153 + 1.2154 + lp = linp; 1.2155 + c = ac; 1.2156 + *lp++ = c; 1.2157 + if(c == '\n' || lp >= &line[64]) { 1.2158 + linp = line; 1.2159 + write(1, line, lp-line); 1.2160 + return; 1.2161 + } 1.2162 + linp = lp; 1.2163 +} 1.2164 + 1.2165 +static void 1.2166 +checkpoint(void) 1.2167 +{ 1.2168 + long *a1, *a2; 1.2169 + 1.2170 + if (undzero && globp == NULL) { 1.2171 + for (a1 = zero+1, a2 = undzero+1; a1 <= dol; a1++, a2++) 1.2172 + *a2 = *a1; 1.2173 + unddot = &undzero[dot-zero]; 1.2174 + unddol = &undzero[dol-zero]; 1.2175 + for (a1 = names, a2 = undnames; a1 < &names[26]; a1++, a2++) 1.2176 + *a2 = *a1; 1.2177 + } 1.2178 +} 1.2179 + 1.2180 +#define swap(a, b) (t = a, a = b, b = t) 1.2181 + 1.2182 +static void 1.2183 +undo(void) 1.2184 +{ 1.2185 + long *t; 1.2186 + 1.2187 + if (undzero == NULL) 1.2188 + error("no undo information saved"); 1.2189 + swap(zero, undzero); 1.2190 + swap(dot, unddot); 1.2191 + swap(dol, unddol); 1.2192 + swap(names, undnames); 1.2193 +} 1.2194 + 1.2195 +static int 1.2196 +maketf(int fd) 1.2197 +{ 1.2198 + char *tmpdir; 1.2199 + 1.2200 + if (fd == -1) { 1.2201 + if ((tmpdir = getenv("TMPDIR")) == NULL || 1.2202 + (fd = creatf(tmpdir)) < 0) 1.2203 + if ((fd = creatf("/var/tmp")) < 0 && 1.2204 + (fd = creatf("/tmp")) < 0) 1.2205 + error("cannot create temporary file"); 1.2206 + } else 1.2207 + ftruncate(fd, 0); /* blkio() will seek to 0 anyway */ 1.2208 + return fd; 1.2209 +} 1.2210 + 1.2211 +static int 1.2212 +creatf(const char *tmpdir) 1.2213 +{ 1.2214 + if (strlen(tmpdir) >= sizeof tfname - 9) 1.2215 + return -1; 1.2216 + strcpy(tfname, tmpdir); 1.2217 + strcat(tfname, "/eXXXXXX"); 1.2218 + return mkstemp(tfname); 1.2219 +} 1.2220 + 1.2221 +static int 1.2222 +sopen(const char *fn, int rdwr) 1.2223 +{ 1.2224 + int pf[2], fd = -1; 1.2225 + 1.2226 + if (fn[0] == '!') { 1.2227 + fn++; 1.2228 + if (pipe(pf) < 0) 1.2229 + error("write or open on pipe failed"); 1.2230 + switch (pipid = fork()) { 1.2231 + case 0: 1.2232 + if (rdwr == READ) 1.2233 + dup2(pf[1], 1); 1.2234 + else 1.2235 + dup2(pf[0], 0); 1.2236 + close(pf[0]); 1.2237 + close(pf[1]); 1.2238 + sigset(SIGHUP, oldhup); 1.2239 + sigset(SIGQUIT, oldquit); 1.2240 + sigset(SIGPIPE, oldpipe); 1.2241 + execl(SHELL, "sh", "-c", fn, NULL); 1.2242 + _exit(0100); 1.2243 + default: 1.2244 + close(pf[rdwr == READ ? 1 : 0]); 1.2245 + fd = pf[rdwr == READ ? 0 : 1]; 1.2246 + break; 1.2247 + case -1: 1.2248 + error("fork failed - try again"); 1.2249 + } 1.2250 + } else if (rdwr == READ) 1.2251 + fd = open(fn, O_RDONLY); 1.2252 + else if (rdwr == EXIST) 1.2253 + fd = open(fn, O_WRONLY); 1.2254 + else /*if (rdwr == WRITE)*/ 1.2255 + fd = creat(fn, 0666); 1.2256 + if (fd >= 0 && rdwr == READ) 1.2257 + readop = 1; 1.2258 + if (fd >= 0) 1.2259 + fstat(fd, &fstbuf); 1.2260 + return fd; 1.2261 +} 1.2262 + 1.2263 +static void 1.2264 +sclose(int fd) 1.2265 +{ 1.2266 + int status; 1.2267 + 1.2268 + close(fd); 1.2269 + if (pipid >= 0) { 1.2270 + while (wait(&status) != pipid); 1.2271 + pipid = -1; 1.2272 + } 1.2273 + readop = 0; 1.2274 +} 1.2275 + 1.2276 +static void 1.2277 +fspec(const char *lp) 1.2278 +{ 1.2279 + struct termios ts; 1.2280 + const char *cp; 1.2281 + 1.2282 + freetabs(); 1.2283 + maxlength = 0; 1.2284 + if (tcgetattr(1, &ts) < 0 1.2285 +#ifdef TAB3 1.2286 + || (ts.c_oflag&TAB3) == 0 1.2287 +#endif 1.2288 + ) 1.2289 + return; 1.2290 + while (lp[0]) { 1.2291 + if (lp[0] == '<' && lp[1] == ':') 1.2292 + break; 1.2293 + lp++; 1.2294 + } 1.2295 + if (lp[0]) { 1.2296 + lp += 2; 1.2297 + while ((cp = ftok(&lp)) != NULL) { 1.2298 + switch (*cp) { 1.2299 + case 't': 1.2300 + freetabs(); 1.2301 + if ((tabstops = tabstring(&cp[1])) == NULL) 1.2302 + goto err; 1.2303 + break; 1.2304 + case 's': 1.2305 + maxlength = atoi(&cp[1]); 1.2306 + break; 1.2307 + case 'm': 1.2308 + case 'd': 1.2309 + case 'e': 1.2310 + break; 1.2311 + case ':': 1.2312 + if (cp[1] == '>') { 1.2313 + if (tabstops == NULL) 1.2314 + if ((tabstops = tabstring("0")) 1.2315 + == NULL) 1.2316 + goto err; 1.2317 + return; 1.2318 + } 1.2319 + /*FALLTHRU*/ 1.2320 + default: 1.2321 + err: freetabs(); 1.2322 + maxlength = 0; 1.2323 + errput("PWB spec problem", NULL); 1.2324 + return; 1.2325 + } 1.2326 + } 1.2327 + } 1.2328 +} 1.2329 + 1.2330 +static const char * 1.2331 +ftok(const char **lp) 1.2332 +{ 1.2333 + const char *cp; 1.2334 + 1.2335 + while (**lp && **lp != ':' && (**lp == ' ' || **lp == '\t')) 1.2336 + (*lp)++; 1.2337 + cp = *lp; 1.2338 + while (**lp && **lp != ':' && **lp != ' ' && **lp != '\t') 1.2339 + (*lp)++; 1.2340 + return cp; 1.2341 +} 1.2342 + 1.2343 +static struct tabulator * 1.2344 +repetitive(int repetition) 1.2345 +{ 1.2346 + struct tabulator *tp, *tabspec; 1.2347 + int col, i; 1.2348 + 1.2349 + if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL) 1.2350 + return NULL; 1.2351 + tp->t_rep = repetition; 1.2352 + if (repetition > 0) { 1.2353 + for (col = 1+repetition, i = 0; i < 22; col += repetition) { 1.2354 + if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL) 1.2355 + return NULL; 1.2356 + tp = tp->t_nxt; 1.2357 + tp->t_tab = col; 1.2358 + } 1.2359 + } 1.2360 + return tabspec; 1.2361 +} 1.2362 + 1.2363 +#define blank(c) ((c) == ' ' || (c) == '\t') 1.2364 + 1.2365 +static struct tabulator * 1.2366 +tablist(const char *s) 1.2367 +{ 1.2368 + struct tabulator *tp, *tabspec; 1.2369 + char *x; 1.2370 + int prev = 0, val; 1.2371 + 1.2372 + if ((tp = tabspec = calloc(1, sizeof *tp)) == NULL) 1.2373 + return NULL; 1.2374 + for (;;) { 1.2375 + while (*s == ',') 1.2376 + s++; 1.2377 + if (*s == '\0' || blank(*s) || *s == ':') 1.2378 + break; 1.2379 + val = strtol(s, &x, 10); 1.2380 + if (*s == '+') 1.2381 + val += prev; 1.2382 + prev = val; 1.2383 + if (*s == '-' || (*x != ',' && !blank(*x) && *x != ':' && 1.2384 + *x != '\0')) 1.2385 + return NULL; 1.2386 + s = x; 1.2387 + if ((tp->t_nxt = calloc(1, sizeof *tp)) == NULL) 1.2388 + return NULL; 1.2389 + tp = tp->t_nxt; 1.2390 + tp->t_tab = val; 1.2391 + } 1.2392 + return tabspec; 1.2393 +} 1.2394 + 1.2395 +static struct tabulator * 1.2396 +tabstring(const char *s) 1.2397 +{ 1.2398 + const struct { 1.2399 + const char *c_nam; 1.2400 + const char *c_str; 1.2401 + } canned[] = { 1.2402 + { "a", "1,10,16,36,72" }, 1.2403 + { "a2", "1,10,16,40,72" }, 1.2404 + { "c", "1,8,12,16,20,55" }, 1.2405 + { "c2", "1,6,10,14,49" }, 1.2406 + { "c3", "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67" }, 1.2407 + { "f", "1,7,11,15,19,23" }, 1.2408 + { "p", "1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61" }, 1.2409 + { "s", "1,10,55" }, 1.2410 + { "u", "1,12,20,44" }, 1.2411 + { 0, 0 } 1.2412 + }; 1.2413 + 1.2414 + int i, j; 1.2415 + 1.2416 + if (s[0] == '-') { 1.2417 + if (s[1] >= '0' && s[1] <= '9' && ((i = atoi(&s[1])) != 0)) 1.2418 + return repetitive(i); 1.2419 + for (i = 0; canned[i].c_nam; i++) { 1.2420 + for (j = 0; canned[i].c_nam[j]; j++) 1.2421 + if (s[j+1] != canned[i].c_nam[j]) 1.2422 + break; 1.2423 + if ((s[j+1]=='\0' || s[j+1]==':' || blank(s[j+1])) && 1.2424 + canned[i].c_nam[j] == '\0') 1.2425 + return tablist(canned[i].c_str); 1.2426 + } 1.2427 + return NULL; 1.2428 + } else 1.2429 + return tablist(s); 1.2430 +} 1.2431 + 1.2432 +static void 1.2433 +freetabs(void) 1.2434 +{ 1.2435 + struct tabulator *tp; 1.2436 + 1.2437 + tp = tabstops; 1.2438 + while (tp) { 1.2439 + tabstops = tp->t_nxt; 1.2440 + free(tp); 1.2441 + tp = tabstops; 1.2442 + } 1.2443 +} 1.2444 + 1.2445 +static void 1.2446 +expand(const char *s) 1.2447 +{ 1.2448 + struct tabulator *tp = tabstops; 1.2449 + int col = 0, n = 1, m, tabcnt = 0, nspc; 1.2450 + wchar_t wc; 1.2451 + 1.2452 + while (*s) { 1.2453 + nspc = 0; 1.2454 + switch (*s) { 1.2455 + case '\n': 1.2456 + putchr('\0'); 1.2457 + s++; 1.2458 + continue; 1.2459 + case '\t': 1.2460 + if (tp) { 1.2461 + if (tp->t_rep) { 1.2462 + if (col % tp->t_rep == 0) { 1.2463 + nspc++; 1.2464 + col++; 1.2465 + } 1.2466 + while (col % tp->t_rep) { 1.2467 + nspc++; 1.2468 + col++; 1.2469 + } 1.2470 + break; 1.2471 + } 1.2472 + while (tp && (col>tp->t_tab || tp->t_tab == 0)) 1.2473 + tp = tp->t_nxt; 1.2474 + if (tp && col == tp->t_tab) { 1.2475 + nspc++; 1.2476 + col++; 1.2477 + tp = tp->t_nxt; 1.2478 + } 1.2479 + if (tp) { 1.2480 + while (col < tp->t_tab) { 1.2481 + nspc++; 1.2482 + col++; 1.2483 + } 1.2484 + tp = tp->t_nxt; 1.2485 + break; 1.2486 + } 1.2487 + } 1.2488 + tabcnt = 1; 1.2489 + nspc++; 1.2490 + break; 1.2491 + default: 1.2492 + if (mb_cur_max>1 && (n=mbtowc(&wc, s, mb_cur_max))>0) { 1.2493 + if ((m = wcwidth(wc)) > 0) 1.2494 + col += m; 1.2495 + } else { 1.2496 + col++; 1.2497 + n = 1; 1.2498 + } 1.2499 + } 1.2500 + if (maxlength && col > maxlength) { 1.2501 + putstr("\ntoo long"); 1.2502 + break; 1.2503 + } 1.2504 + if (nspc) { 1.2505 + while (nspc--) 1.2506 + putchr(' '); 1.2507 + s++; 1.2508 + } else 1.2509 + while (n--) 1.2510 + putchr(*s++); 1.2511 + } 1.2512 + if (tabcnt) 1.2513 + putstr("\ntab count"); 1.2514 + putchr('\n'); 1.2515 +} 1.2516 + 1.2517 +static wint_t 1.2518 +GETWC(char *mb) 1.2519 +{ 1.2520 + int c, n; 1.2521 + 1.2522 + n = 1; 1.2523 + mb[0] = c = GETC(); 1.2524 + mb[1] = '\0'; 1.2525 + if (mb_cur_max > 1 && c&0200 && c != EOF) { 1.2526 + int m; 1.2527 + wchar_t wc; 1.2528 + 1.2529 + while ((m = mbtowc(&wc, mb, mb_cur_max)) < 0 && n<mb_cur_max) { 1.2530 + mb[n++] = c = GETC(); 1.2531 + mb[n] = '\0'; 1.2532 + if (c == '\n' || c == EOF) 1.2533 + break; 1.2534 + } 1.2535 + if (m != n) 1.2536 + ERROR(67); 1.2537 + return wc; 1.2538 + } else 1.2539 + return c; 1.2540 +} 1.2541 + 1.2542 +static void 1.2543 +growlb(const char *msg) 1.2544 +{ 1.2545 + char *olb = linebuf; 1.2546 + int i; 1.2547 + 1.2548 + LBSIZE += 512; 1.2549 + if ((linebuf = realloc(linebuf, LBSIZE)) == NULL || 1.2550 + (genbuf = realloc(genbuf, LBSIZE)) == NULL) 1.2551 + error(msg); 1.2552 + if (linebuf != olb) { 1.2553 + loc1 += linebuf - olb; 1.2554 + loc2 += linebuf - olb; 1.2555 + for (i = 0; i < NBRA; i++) { 1.2556 + if (braslist[i]) 1.2557 + braslist[i] += linebuf - olb; 1.2558 + if (braelist[i]) 1.2559 + braelist[i] += linebuf - olb; 1.2560 + } 1.2561 + } 1.2562 +} 1.2563 + 1.2564 +static void 1.2565 +growrhs(const char *msg) 1.2566 +{ 1.2567 + RHSIZE += 256; 1.2568 + if ((rhsbuf = realloc(rhsbuf, RHSIZE)) == NULL) 1.2569 + error(msg); 1.2570 +} 1.2571 + 1.2572 +static void 1.2573 +growfn(const char *msg) 1.2574 +{ 1.2575 + FNSIZE += 64; 1.2576 + if ((savedfile = realloc(savedfile, FNSIZE)) == NULL || 1.2577 + (file = realloc(file, FNSIZE)) == NULL) 1.2578 + error(msg); 1.2579 + if (FNSIZE == 64) 1.2580 + file[0] = savedfile[0] = 0; 1.2581 +} 1.2582 + 1.2583 +#if defined (SUS) || defined (S42) || defined (SU3) 1.2584 +union ptrstore { 1.2585 + void *vp; 1.2586 + char bp[sizeof (void *)]; 1.2587 +}; 1.2588 + 1.2589 +static void * 1.2590 +fetchptr(const char *bp) 1.2591 +{ 1.2592 + union ptrstore u; 1.2593 + int i; 1.2594 + 1.2595 + for (i = 0; i < sizeof (void *); i++) 1.2596 + u.bp[i] = bp[i]; 1.2597 + return u.vp; 1.2598 +} 1.2599 + 1.2600 +static void 1.2601 +storeptr(void *vp, char *bp) 1.2602 +{ 1.2603 + union ptrstore u; 1.2604 + int i; 1.2605 + 1.2606 + u.vp = vp; 1.2607 + for (i = 0; i < sizeof (void *); i++) 1.2608 + bp[i] = u.bp[i]; 1.2609 +} 1.2610 + 1.2611 +#define add(c) ((i>=LBSIZE ? (growlb("regular expression overflow"),0) : 0), \ 1.2612 + genbuf[i++] = (c)) 1.2613 + 1.2614 +#define copy(s) { \ 1.2615 + int m; \ 1.2616 + for (m = 0; m==0 || s[m]; m++) \ 1.2617 + add(s[m]); \ 1.2618 +} 1.2619 + 1.2620 +static char * 1.2621 +compile(char *unused, char *ep, const char *endbuf, int seof) 1.2622 +{ 1.2623 + INIT 1.2624 + int c, d, i; 1.2625 + regex_t *rp; 1.2626 + char *op; 1.2627 + char mb[MB_LEN_MAX+1]; 1.2628 + 1.2629 + op = ep; 1.2630 + ep += 2; 1.2631 + if ((rp = fetchptr(ep)) == NULL) { 1.2632 + if ((rp = calloc(1, sizeof *rp)) == NULL) 1.2633 + ERROR(50); 1.2634 + storeptr(rp, ep); 1.2635 + } 1.2636 + ep += sizeof (void *); 1.2637 + i = 0; 1.2638 + nbra = 0; 1.2639 + do { 1.2640 + if ((c = GETWC(mb)) == seof) 1.2641 + add('\0'); 1.2642 + else if (c == '\\') { 1.2643 + copy(mb); 1.2644 + c = GETWC(mb); 1.2645 + if (c == '(') 1.2646 + nbra++; 1.2647 + goto normchar; 1.2648 + } else if (c == '[') { 1.2649 + add(c); 1.2650 + d = EOF; 1.2651 + do { 1.2652 + c = GETWC(mb); 1.2653 + if (c == EOF || c == '\n') 1.2654 + ERROR(49); 1.2655 + copy(mb); 1.2656 + if (d=='[' && (c==':' || c=='.' || c=='=')) { 1.2657 + d = c; 1.2658 + do { 1.2659 + c = GETWC(mb); 1.2660 + if (c == EOF || c == '\n') 1.2661 + ERROR(49); 1.2662 + copy(mb); 1.2663 + } while (c != d || PEEKC() != ']'); 1.2664 + c = GETWC(mb); 1.2665 + copy(mb); 1.2666 + c = EOF; 1.2667 + } 1.2668 + d = c; 1.2669 + } while (c != ']'); 1.2670 + } else { 1.2671 + if (c == EOF || c == '\n') { 1.2672 + if (c == '\n') 1.2673 + UNGETC(c); 1.2674 + mb[0] = c = '\0'; 1.2675 + } 1.2676 + if (c == '\0') 1.2677 + nodelim = 1; 1.2678 + normchar: copy(mb); 1.2679 + } 1.2680 + } while (genbuf[i-1] != '\0'); 1.2681 + if (genbuf[0]) { 1.2682 + int reflags = 0; 1.2683 + 1.2684 +#ifdef REG_ANGLES 1.2685 + reflags |= REG_ANGLES; 1.2686 +#endif 1.2687 +#if defined (SU3) && defined (REG_AVOIDNULL) 1.2688 + reflags |= REG_AVOIDNULL; 1.2689 +#endif 1.2690 + if (op[0]) 1.2691 + regfree(rp); 1.2692 + op[0] = 0; 1.2693 + switch (regcomp(rp, genbuf, reflags)) { 1.2694 + case 0: 1.2695 + break; 1.2696 + case REG_ESUBREG: 1.2697 + ERROR(25); 1.2698 + /*NOTREACHED*/ 1.2699 + case REG_EBRACK: 1.2700 + ERROR(49); 1.2701 + /*NOTREACHED*/ 1.2702 + case REG_EPAREN: 1.2703 + ERROR(42); 1.2704 + /*NOTREACHED*/ 1.2705 + case REG_BADBR: 1.2706 + case REG_EBRACE: 1.2707 + ERROR(45); 1.2708 + /*NOTREACHED*/ 1.2709 + case REG_ERANGE: 1.2710 + ERROR(11); 1.2711 + /*NOTREACHED*/ 1.2712 + case REG_ESPACE: 1.2713 + ERROR(50); 1.2714 + /*NOTREACHED*/ 1.2715 + default: 1.2716 + ERROR(-1); 1.2717 + } 1.2718 + op[0] = 1; 1.2719 + circf = op[1] = genbuf[0] == '^'; 1.2720 + } else if (op[0]) { 1.2721 + circf = op[1]; 1.2722 + } else 1.2723 + ERROR(41); 1.2724 + return ep + sizeof (void *); 1.2725 +} 1.2726 + 1.2727 +static int 1.2728 +step(const char *lp, const char *ep) 1.2729 +{ 1.2730 + regex_t *rp; 1.2731 + regmatch_t bralist[NBRA+1]; 1.2732 + int eflag = 0; 1.2733 + int res; 1.2734 + int i; 1.2735 + 1.2736 + rp = fetchptr(&ep[2]); 1.2737 + if (ep[0] == 0) 1.2738 + return 0; 1.2739 + if (locs) 1.2740 + eflag |= REG_NOTBOL; 1.2741 + if ((res = regexec(rp, lp, needsub? NBRA+1 : 0, bralist, eflag)) == 0 && 1.2742 + needsub) { 1.2743 + loc1 = (char *)lp + bralist[0].rm_so; 1.2744 + loc2 = (char *)lp + bralist[0].rm_eo; 1.2745 + for (i = 1; i <= NBRA; i++) { 1.2746 + if (bralist[i].rm_so != -1) { 1.2747 + braslist[i-1] = (char *)lp + bralist[i].rm_so; 1.2748 + braelist[i-1] = (char *)lp + bralist[i].rm_eo; 1.2749 + } else 1.2750 + braslist[i-1] = braelist[i-1] = NULL; 1.2751 + } 1.2752 + } 1.2753 + return res == 0; 1.2754 +} 1.2755 +#endif /* SUS || S42 || SU3 */ 1.2756 + 1.2757 +static void 1.2758 +help(void) 1.2759 +{ 1.2760 + const char *desc[] = { 1.2761 + "(.)a append up to .", 1.2762 + "(.)b[n] browse n lines", 1.2763 + "(.,.)c change up to .", 1.2764 + "(.,.)d delete lines", 1.2765 + "e [file] edit file", 1.2766 + "E [file] force edit", 1.2767 + "f [file] print or set file", 1.2768 + "(1,$)g/RE/cmd global cmd", 1.2769 + "(1,$)G/RE/ interactive global", 1.2770 + "h print last error", 1.2771 + "H toggle error messages", 1.2772 + "help print this screen", 1.2773 + "(.)i insert up to .", 1.2774 + "(.,.+1)j join lines", 1.2775 + "(.)kx mark line with x", 1.2776 + "(.,.)l list lines", 1.2777 + "(.,.)ma move lines to a", 1.2778 + "(.,.)n number lines", 1.2779 + "N revert n and p", 1.2780 + "(.)o[n] show n lines of context", 1.2781 + "(.,.)p print lines", 1.2782 + "P toggle prompt", 1.2783 + "q quit", 1.2784 + "Q force quit", 1.2785 + "($)r read file", 1.2786 + "(.,.)s/RE/repl/ search and replace", 1.2787 + "(.,.)s/RE/rp/g replace all occurrences", 1.2788 + "(.,.)s/RE/rp/n replace n-th occurrence", 1.2789 + "(.,.)ta transfer lines to a", 1.2790 + "u undo last change", 1.2791 + "(1,$)v/RE/cmd reverse global", 1.2792 + "(1,$)V/RE/ reverse i/a global", 1.2793 + "(1,$)w [file] write file", 1.2794 + "(1,$)W [file] append to file", 1.2795 + "z write buffer and quit", 1.2796 + "($)= print line number", 1.2797 + "!command execute shell command", 1.2798 + "(.+1)<newline> print one line", 1.2799 + "/RE find RE forwards", 1.2800 + "?RE find RE backwards", 1.2801 + "1 first line", 1.2802 + ". current line", 1.2803 + "$ last line", 1.2804 + ", 1,$", 1.2805 + "; .,$", 1.2806 + NULL 1.2807 + }; 1.2808 + char line[100]; 1.2809 + int c, half, i, k; 1.2810 + 1.2811 + half = (sizeof desc / sizeof *desc) / 2; 1.2812 + for (i = 0; i < half && desc[i]; i++) { 1.2813 + c = 0; 1.2814 + for (k = 0; desc[i][k]; k++) 1.2815 + line[c++] = desc[i][k]; 1.2816 + if (desc[i+half]) { 1.2817 + while (c < 40) 1.2818 + line[c++] = ' '; 1.2819 + for (k = 0; desc[i+half][k]; k++) 1.2820 + line[c++] = desc[i+half][k]; 1.2821 + } 1.2822 + line[c] = 0; 1.2823 + puts(line); 1.2824 + } 1.2825 +}