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