version 1.0
[nvi.git] / vi / v_increment.c
blobeed059176592437bdbc0672dda043d499f224677
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: v_increment.c,v 8.6 1993/12/09 19:43:12 bostic Exp $ (Berkeley) $Date: 1993/12/09 19:43:12 $";
10 #endif /* not lint */
12 #include <sys/types.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include "vi.h"
19 #include "vcmd.h"
21 static char * const fmt[] = {
22 #define DEC 0
23 "%ld",
24 #define SDEC 1
25 "%+ld",
26 #define HEXC 2
27 "%#0.*lX",
28 #define HEXL 3
29 "%#0.*lx",
30 #define OCTAL 4
31 "%#0.*lo",
35 * v_increment -- [count]#[#+-]
36 * Increment/decrement a keyword number.
38 int
39 v_increment(sp, ep, vp, fm, tm, rp)
40 SCR *sp;
41 EXF *ep;
42 VICMDARG *vp;
43 MARK *fm, *tm, *rp;
45 VI_PRIVATE *vip;
46 u_long ulval;
47 long lval;
48 size_t blen, len, nlen;
49 int rval;
50 char *bp, *ntype, *p, nbuf[100];
52 vip = VIP(sp);
54 /* Do repeat operations. */
55 if (vp->character == '#')
56 vp->character = vip->inc_lastch;
58 /* Get new value. */
59 if (F_ISSET(vp, VC_C1SET))
60 vip->inc_lastval = vp->count;
62 if (vp->character != '+' && vp->character != '-') {
63 msgq(sp, M_ERR, "usage: %s.", vp->kp->usage);
64 return (1);
66 vip->inc_lastch = vp->character;
68 /* Figure out the resulting type and number. */
69 p = vp->keyword;
70 len = vp->klen;
71 if (len > 1 && p[0] == '0') {
72 if (vp->character == '+') {
73 ulval = strtoul(vp->keyword, NULL, 0);
74 if (ULONG_MAX - ulval < vip->inc_lastval)
75 goto overflow;
76 ulval += vip->inc_lastval;
77 } else {
78 ulval = strtoul(vp->keyword, NULL, 0);
79 if (ulval < vip->inc_lastval)
80 goto underflow;
81 ulval -= vip->inc_lastval;
83 ntype = fmt[OCTAL];
84 if (len > 2)
85 if (p[1] == 'X')
86 ntype = fmt[HEXC];
87 else if (p[1] == 'x')
88 ntype = fmt[HEXL];
89 nlen = snprintf(nbuf, sizeof(nbuf), ntype, len, ulval);
90 } else {
91 if (vp->character == '+') {
92 lval = strtol(vp->keyword, NULL, 0);
93 if (lval > 0 && LONG_MAX - lval < vip->inc_lastval) {
94 overflow: msgq(sp, M_ERR, "Resulting number too large.");
95 return (1);
97 lval += vip->inc_lastval;
98 } else {
99 lval = strtol(vp->keyword, NULL, 0);
100 if (lval < 0 && -(LONG_MIN - lval) < vip->inc_lastval) {
101 underflow: msgq(sp, M_ERR, "Resulting number too small.");
102 return (1);
104 lval -= vip->inc_lastval;
106 ntype = lval != 0 &&
107 (*vp->keyword == '+' || *vp->keyword == '-') ?
108 fmt[SDEC] : fmt[DEC];
109 nlen = snprintf(nbuf, sizeof(nbuf), ntype, lval);
112 if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
113 GETLINE_ERR(sp, fm->lno);
114 return (1);
117 GET_SPACE_RET(sp, bp, blen, len + nlen);
118 memmove(bp, p, fm->cno);
119 memmove(bp + fm->cno, nbuf, nlen);
120 memmove(bp + fm->cno + nlen,
121 p + fm->cno + vp->klen, len - fm->cno - vp->klen);
122 len = len - vp->klen + nlen;
124 rval = file_sline(sp, ep, fm->lno, bp, len);
125 FREE_SPACE(sp, bp, blen);
126 return (rval);