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