1b8ba871bSPeter Wemm /*- 2b8ba871bSPeter Wemm * Copyright (c) 1992, 1993, 1994 3b8ba871bSPeter Wemm * The Regents of the University of California. All rights reserved. 4b8ba871bSPeter Wemm * Copyright (c) 1992, 1993, 1994, 1995, 1996 5b8ba871bSPeter Wemm * Keith Bostic. All rights reserved. 6b8ba871bSPeter Wemm * 7b8ba871bSPeter Wemm * See the LICENSE file for redistribution information. 8b8ba871bSPeter Wemm */ 9b8ba871bSPeter Wemm 10b8ba871bSPeter Wemm #include "config.h" 11b8ba871bSPeter Wemm 12b8ba871bSPeter Wemm #ifndef lint 13*f0957ccaSPeter Wemm static const char sccsid[] = "$Id: ex_shift.c,v 10.17 2001/06/25 15:19:20 skimo Exp $"; 14b8ba871bSPeter Wemm #endif /* not lint */ 15b8ba871bSPeter Wemm 16b8ba871bSPeter Wemm #include <sys/types.h> 17b8ba871bSPeter Wemm #include <sys/queue.h> 18*f0957ccaSPeter Wemm #include <sys/time.h> 19b8ba871bSPeter Wemm 20b8ba871bSPeter Wemm #include <bitstring.h> 21b8ba871bSPeter Wemm #include <limits.h> 22b8ba871bSPeter Wemm #include <stdio.h> 23b8ba871bSPeter Wemm #include <stdlib.h> 24b8ba871bSPeter Wemm #include <string.h> 25b8ba871bSPeter Wemm 26b8ba871bSPeter Wemm #include "../common/common.h" 27b8ba871bSPeter Wemm 28b8ba871bSPeter Wemm enum which {LEFT, RIGHT}; 29b8ba871bSPeter Wemm static int shift __P((SCR *, EXCMD *, enum which)); 30b8ba871bSPeter Wemm 31b8ba871bSPeter Wemm /* 32b8ba871bSPeter Wemm * ex_shiftl -- :<[<...] 33b8ba871bSPeter Wemm * 34b8ba871bSPeter Wemm * 35b8ba871bSPeter Wemm * PUBLIC: int ex_shiftl __P((SCR *, EXCMD *)); 36b8ba871bSPeter Wemm */ 37b8ba871bSPeter Wemm int 38*f0957ccaSPeter Wemm ex_shiftl(SCR *sp, EXCMD *cmdp) 39b8ba871bSPeter Wemm { 40b8ba871bSPeter Wemm return (shift(sp, cmdp, LEFT)); 41b8ba871bSPeter Wemm } 42b8ba871bSPeter Wemm 43b8ba871bSPeter Wemm /* 44b8ba871bSPeter Wemm * ex_shiftr -- :>[>...] 45b8ba871bSPeter Wemm * 46b8ba871bSPeter Wemm * PUBLIC: int ex_shiftr __P((SCR *, EXCMD *)); 47b8ba871bSPeter Wemm */ 48b8ba871bSPeter Wemm int 49*f0957ccaSPeter Wemm ex_shiftr(SCR *sp, EXCMD *cmdp) 50b8ba871bSPeter Wemm { 51b8ba871bSPeter Wemm return (shift(sp, cmdp, RIGHT)); 52b8ba871bSPeter Wemm } 53b8ba871bSPeter Wemm 54b8ba871bSPeter Wemm /* 55b8ba871bSPeter Wemm * shift -- 56b8ba871bSPeter Wemm * Ex shift support. 57b8ba871bSPeter Wemm */ 58b8ba871bSPeter Wemm static int 59*f0957ccaSPeter Wemm shift(SCR *sp, EXCMD *cmdp, enum which rl) 60b8ba871bSPeter Wemm { 61b8ba871bSPeter Wemm recno_t from, to; 62b8ba871bSPeter Wemm size_t blen, len, newcol, newidx, oldcol, oldidx, sw; 63b8ba871bSPeter Wemm int curset; 64*f0957ccaSPeter Wemm CHAR_T *p; 65*f0957ccaSPeter Wemm CHAR_T *bp, *tbp; 66b8ba871bSPeter Wemm 67b8ba871bSPeter Wemm NEEDFILE(sp, cmdp); 68b8ba871bSPeter Wemm 69b8ba871bSPeter Wemm if (O_VAL(sp, O_SHIFTWIDTH) == 0) { 70b8ba871bSPeter Wemm msgq(sp, M_INFO, "152|shiftwidth option set to 0"); 71b8ba871bSPeter Wemm return (0); 72b8ba871bSPeter Wemm } 73b8ba871bSPeter Wemm 74b8ba871bSPeter Wemm /* Copy the lines being shifted into the unnamed buffer. */ 75b8ba871bSPeter Wemm if (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE)) 76b8ba871bSPeter Wemm return (1); 77b8ba871bSPeter Wemm 78b8ba871bSPeter Wemm /* 79b8ba871bSPeter Wemm * The historic version of vi permitted the user to string any number 80b8ba871bSPeter Wemm * of '>' or '<' characters together, resulting in an indent of the 81b8ba871bSPeter Wemm * appropriate levels. There's a special hack in ex_cmd() so that 82b8ba871bSPeter Wemm * cmdp->argv[0] points to the string of '>' or '<' characters. 83b8ba871bSPeter Wemm * 84b8ba871bSPeter Wemm * Q: What's the difference between the people adding features 85b8ba871bSPeter Wemm * to vi and the Girl Scouts? 86b8ba871bSPeter Wemm * A: The Girl Scouts have mint cookies and adult supervision. 87b8ba871bSPeter Wemm */ 88b8ba871bSPeter Wemm for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p) 89b8ba871bSPeter Wemm sw += O_VAL(sp, O_SHIFTWIDTH); 90b8ba871bSPeter Wemm 91*f0957ccaSPeter Wemm GET_SPACE_RETW(sp, bp, blen, 256); 92b8ba871bSPeter Wemm 93b8ba871bSPeter Wemm curset = 0; 94b8ba871bSPeter Wemm for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) { 95b8ba871bSPeter Wemm if (db_get(sp, from, DBG_FATAL, &p, &len)) 96b8ba871bSPeter Wemm goto err; 97b8ba871bSPeter Wemm if (!len) { 98b8ba871bSPeter Wemm if (sp->lno == from) 99b8ba871bSPeter Wemm curset = 1; 100b8ba871bSPeter Wemm continue; 101b8ba871bSPeter Wemm } 102b8ba871bSPeter Wemm 103b8ba871bSPeter Wemm /* 104b8ba871bSPeter Wemm * Calculate the old indent amount and the number of 105b8ba871bSPeter Wemm * characters it used. 106b8ba871bSPeter Wemm */ 107b8ba871bSPeter Wemm for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx) 108b8ba871bSPeter Wemm if (p[oldidx] == ' ') 109b8ba871bSPeter Wemm ++oldcol; 110b8ba871bSPeter Wemm else if (p[oldidx] == '\t') 111b8ba871bSPeter Wemm oldcol += O_VAL(sp, O_TABSTOP) - 112b8ba871bSPeter Wemm oldcol % O_VAL(sp, O_TABSTOP); 113b8ba871bSPeter Wemm else 114b8ba871bSPeter Wemm break; 115b8ba871bSPeter Wemm 116b8ba871bSPeter Wemm /* Calculate the new indent amount. */ 117b8ba871bSPeter Wemm if (rl == RIGHT) 118b8ba871bSPeter Wemm newcol = oldcol + sw; 119b8ba871bSPeter Wemm else { 120b8ba871bSPeter Wemm newcol = oldcol < sw ? 0 : oldcol - sw; 121b8ba871bSPeter Wemm if (newcol == oldcol) { 122b8ba871bSPeter Wemm if (sp->lno == from) 123b8ba871bSPeter Wemm curset = 1; 124b8ba871bSPeter Wemm continue; 125b8ba871bSPeter Wemm } 126b8ba871bSPeter Wemm } 127b8ba871bSPeter Wemm 128b8ba871bSPeter Wemm /* Get a buffer that will hold the new line. */ 129*f0957ccaSPeter Wemm ADD_SPACE_RETW(sp, bp, blen, newcol + len); 130b8ba871bSPeter Wemm 131b8ba871bSPeter Wemm /* 132b8ba871bSPeter Wemm * Build a new indent string and count the number of 133b8ba871bSPeter Wemm * characters it uses. 134b8ba871bSPeter Wemm */ 135b8ba871bSPeter Wemm for (tbp = bp, newidx = 0; 136b8ba871bSPeter Wemm newcol >= O_VAL(sp, O_TABSTOP); ++newidx) { 137b8ba871bSPeter Wemm *tbp++ = '\t'; 138b8ba871bSPeter Wemm newcol -= O_VAL(sp, O_TABSTOP); 139b8ba871bSPeter Wemm } 140b8ba871bSPeter Wemm for (; newcol > 0; --newcol, ++newidx) 141b8ba871bSPeter Wemm *tbp++ = ' '; 142b8ba871bSPeter Wemm 143b8ba871bSPeter Wemm /* Add the original line. */ 144*f0957ccaSPeter Wemm MEMCPY(tbp, p + oldidx, len - oldidx); 145b8ba871bSPeter Wemm 146b8ba871bSPeter Wemm /* Set the replacement line. */ 147b8ba871bSPeter Wemm if (db_set(sp, from, bp, (tbp + (len - oldidx)) - bp)) { 148*f0957ccaSPeter Wemm err: FREE_SPACEW(sp, bp, blen); 149b8ba871bSPeter Wemm return (1); 150b8ba871bSPeter Wemm } 151b8ba871bSPeter Wemm 152b8ba871bSPeter Wemm /* 153b8ba871bSPeter Wemm * !!! 154b8ba871bSPeter Wemm * The shift command in historic vi had the usual bizarre 155b8ba871bSPeter Wemm * collection of cursor semantics. If called from vi, the 156b8ba871bSPeter Wemm * cursor was repositioned to the first non-blank character 157b8ba871bSPeter Wemm * of the lowest numbered line shifted. If called from ex, 158b8ba871bSPeter Wemm * the cursor was repositioned to the first non-blank of the 159b8ba871bSPeter Wemm * highest numbered line shifted. Here, if the cursor isn't 160b8ba871bSPeter Wemm * part of the set of lines that are moved, move it to the 161b8ba871bSPeter Wemm * first non-blank of the last line shifted. (This makes 162b8ba871bSPeter Wemm * ":3>>" in vi work reasonably.) If the cursor is part of 163b8ba871bSPeter Wemm * the shifted lines, it doesn't get moved at all. This 164b8ba871bSPeter Wemm * permits shifting of marked areas, i.e. ">'a." shifts the 165b8ba871bSPeter Wemm * marked area twice, something that couldn't be done with 166b8ba871bSPeter Wemm * historic vi. 167b8ba871bSPeter Wemm */ 168b8ba871bSPeter Wemm if (sp->lno == from) { 169b8ba871bSPeter Wemm curset = 1; 170b8ba871bSPeter Wemm if (newidx > oldidx) 171b8ba871bSPeter Wemm sp->cno += newidx - oldidx; 172b8ba871bSPeter Wemm else if (sp->cno >= oldidx - newidx) 173b8ba871bSPeter Wemm sp->cno -= oldidx - newidx; 174b8ba871bSPeter Wemm } 175b8ba871bSPeter Wemm } 176b8ba871bSPeter Wemm if (!curset) { 177b8ba871bSPeter Wemm sp->lno = to; 178b8ba871bSPeter Wemm sp->cno = 0; 179b8ba871bSPeter Wemm (void)nonblank(sp, to, &sp->cno); 180b8ba871bSPeter Wemm } 181b8ba871bSPeter Wemm 182*f0957ccaSPeter Wemm FREE_SPACEW(sp, bp, blen); 183b8ba871bSPeter Wemm 184b8ba871bSPeter Wemm sp->rptlines[L_SHIFT] += cmdp->addr2.lno - cmdp->addr1.lno + 1; 185b8ba871bSPeter Wemm return (0); 186b8ba871bSPeter Wemm } 187