1 /*- 2 * Copyright (c) 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1993, 1994, 1995, 1996 5 * Keith Bostic. All rights reserved. 6 * 7 * See the LICENSE file for redistribution information. 8 */ 9 10 #include "config.h" 11 12 #ifndef lint 13 static const char sccsid[] = "$Id: ex_z.c,v 10.12 2001/06/25 15:19:22 skimo Exp $"; 14 #endif /* not lint */ 15 16 #include <sys/types.h> 17 #include <sys/queue.h> 18 #include <sys/time.h> 19 20 #include <bitstring.h> 21 #include <limits.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include "../common/common.h" 27 28 /* 29 * ex_z -- :[line] z [^-.+=] [count] [flags] 30 * Adjust window. 31 * 32 * PUBLIC: int ex_z __P((SCR *, EXCMD *)); 33 */ 34 int 35 ex_z(SCR *sp, EXCMD *cmdp) 36 { 37 MARK abs; 38 recno_t cnt, equals, lno; 39 int eofcheck; 40 41 NEEDFILE(sp, cmdp); 42 43 /* 44 * !!! 45 * If no count specified, use either two times the size of the 46 * scrolling region, or the size of the window option. POSIX 47 * 1003.2 claims that the latter is correct, but historic ex/vi 48 * documentation and practice appear to use the scrolling region. 49 * I'm using the window size as it means that the entire screen 50 * is used instead of losing a line to roundoff. Note, we drop 51 * a line from the cnt if using the window size to leave room for 52 * the next ex prompt. 53 */ 54 if (FL_ISSET(cmdp->iflags, E_C_COUNT)) 55 cnt = cmdp->count; 56 else 57 #ifdef HISTORICAL_PRACTICE 58 cnt = O_VAL(sp, O_SCROLL) * 2; 59 #else 60 cnt = O_VAL(sp, O_WINDOW) - 1; 61 #endif 62 63 equals = 0; 64 eofcheck = 0; 65 lno = cmdp->addr1.lno; 66 67 switch (FL_ISSET(cmdp->iflags, 68 E_C_CARAT | E_C_DASH | E_C_DOT | E_C_EQUAL | E_C_PLUS)) { 69 case E_C_CARAT: /* Display cnt * 2 before the line. */ 70 eofcheck = 1; 71 if (lno > cnt * 2) 72 cmdp->addr1.lno = (lno - cnt * 2) + 1; 73 else 74 cmdp->addr1.lno = 1; 75 cmdp->addr2.lno = (cmdp->addr1.lno + cnt) - 1; 76 break; 77 case E_C_DASH: /* Line goes at the bottom of the screen. */ 78 cmdp->addr1.lno = lno > cnt ? (lno - cnt) + 1 : 1; 79 cmdp->addr2.lno = lno; 80 break; 81 case E_C_DOT: /* Line goes in the middle of the screen. */ 82 /* 83 * !!! 84 * Historically, the "middleness" of the line overrode the 85 * count, so that "3z.19" or "3z.20" would display the first 86 * 12 lines of the file, i.e. (N - 1) / 2 lines before and 87 * after the specified line. 88 */ 89 eofcheck = 1; 90 cnt = (cnt - 1) / 2; 91 cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; 92 cmdp->addr2.lno = lno + cnt; 93 94 /* 95 * !!! 96 * Historically, z. set the absolute cursor mark. 97 */ 98 abs.lno = sp->lno; 99 abs.cno = sp->cno; 100 (void)mark_set(sp, ABSMARK1, &abs, 1); 101 break; 102 case E_C_EQUAL: /* Center with hyphens. */ 103 /* 104 * !!! 105 * Strangeness. The '=' flag is like the '.' flag (see the 106 * above comment, it applies here as well) but with a special 107 * little hack. Print out lines of hyphens before and after 108 * the specified line. Additionally, the cursor remains set 109 * on that line. 110 */ 111 eofcheck = 1; 112 cnt = (cnt - 1) / 2; 113 cmdp->addr1.lno = lno > cnt ? lno - cnt : 1; 114 cmdp->addr2.lno = lno - 1; 115 if (ex_pr(sp, cmdp)) 116 return (1); 117 (void)ex_puts(sp, "----------------------------------------\n"); 118 cmdp->addr2.lno = cmdp->addr1.lno = equals = lno; 119 if (ex_pr(sp, cmdp)) 120 return (1); 121 (void)ex_puts(sp, "----------------------------------------\n"); 122 cmdp->addr1.lno = lno + 1; 123 cmdp->addr2.lno = (lno + cnt) - 1; 124 break; 125 default: 126 /* If no line specified, move to the next one. */ 127 if (F_ISSET(cmdp, E_ADDR_DEF)) 128 ++lno; 129 /* FALLTHROUGH */ 130 case E_C_PLUS: /* Line goes at the top of the screen. */ 131 eofcheck = 1; 132 cmdp->addr1.lno = lno; 133 cmdp->addr2.lno = (lno + cnt) - 1; 134 break; 135 } 136 137 if (eofcheck) { 138 if (db_last(sp, &lno)) 139 return (1); 140 if (cmdp->addr2.lno > lno) 141 cmdp->addr2.lno = lno; 142 } 143 144 if (ex_pr(sp, cmdp)) 145 return (1); 146 if (equals) 147 sp->lno = equals; 148 return (0); 149 } 150