1 /*	SC	A Spreadsheet Calculator
2  *		Framed range manipulation
3  *
4  *		Chuck Martin <nrocinu@myrealbox.com>
5  *		Originally created:  December, 2000
6  *
7  *		$Revision: 7.16 $
8  */
9 
10 #include <sys/types.h>
11 #ifdef BSD42
12 #include <strings.h>
13 #else
14 #ifndef SYSIII
15 #include <string.h>
16 #endif
17 #endif
18 
19 #include <stdio.h>
20 #include <ctype.h>
21 #include "sc.h"
22 
23 static struct frange *frame_base;
24 extern struct frange *lastfr;
25 
26 void
add_frange(struct ent * or_left,struct ent * or_right,struct ent * ir_left,struct ent * ir_right,int toprows,int bottomrows,int leftcols,int rightcols)27 add_frange(struct ent *or_left, struct ent *or_right, struct ent *ir_left,
28 	struct ent *ir_right, int toprows, int bottomrows, int leftcols,
29 	int rightcols)
30 {
31     struct frange *r;
32     int minr, minc, maxr, maxc;
33 
34     minr = or_left->row < or_right->row ? or_left->row : or_right->row;
35     minc = or_left->col < or_right->col ? or_left->col : or_right->col;
36     maxr = or_left->row > or_right->row ? or_left->row : or_right->row;
37     maxc = or_left->col > or_right->col ? or_left->col : or_right->col;
38 
39     or_left = lookat(minr, minc);
40     or_right = lookat(maxr, maxc);
41 
42     if (ir_left) {
43 	minr = ir_left->row < ir_right->row ? ir_left->row : ir_right->row;
44 	minc = ir_left->col < ir_right->col ? ir_left->col : ir_right->col;
45 	maxr = ir_left->row > ir_right->row ? ir_left->row : ir_right->row;
46 	maxc = ir_left->col > ir_right->col ? ir_left->col : ir_right->col;
47 
48 	ir_left = lookat(minr, minc);
49 	ir_right = lookat(maxr, maxc);
50 
51 	if (ir_left->row < or_left->row ||
52 		ir_left->col < or_left->col ||
53 		ir_right->row > or_right->row ||
54 		ir_right->col > or_right->col) {
55 	    error("Invalid parameters");
56 	    return;
57 	}
58     }
59 
60     if (frame_base) {
61 	/*
62 	 * Has this frange already been created?  If so, any negative
63 	 * parameters mean "don't change this value."
64 	 */
65 	for (r = frame_base; r; r = r->r_next) {
66 	    if ((r->or_left == or_left) && (r->or_right == or_right)) {
67 		if (ir_left) {
68 		    r->ir_left = ir_left;
69 		    r->ir_right = ir_right;
70 		} else {
71 		    if (toprows < 0)
72 			toprows = r->ir_left->row - r->or_left->row;
73 		    if (bottomrows < 0)
74 			bottomrows = r->or_right->row - r->ir_right->row;
75 		    if (leftcols < 0)
76 			leftcols = r->ir_left->col - r->or_left->col;
77 		    if (rightcols < 0)
78 			rightcols = r->or_right->col - r->ir_right->col;
79 		    r->ir_left = lookat(r->or_left->row + toprows,
80 			    r->or_left->col + leftcols);
81 		    r->ir_right = lookat(r->or_right->row - bottomrows,
82 			    r->or_right->col - rightcols);
83 		}
84 
85 		/* If all frame sides are 0, delete the frange */
86 		if (r->ir_left == r->or_left && r->ir_right == r->or_right) {
87 		    if (r->r_next)
88 			r->r_next->r_prev = r->r_prev;
89 		    if (r->r_prev)
90 			r->r_prev->r_next = r->r_next;
91 		    else
92 			frame_base = r->r_next;
93 		    scxfree((char *)r);
94 		    if (lastfr == r) lastfr = NULL;
95 		}
96 		modflg++;
97 		FullUpdate++;
98 		return;
99 	    }
100 	}
101 	/*
102 	 * See if the specified range overlaps any previously created frange.
103 	 */
104 	for (r = frame_base; r; r = r->r_next) {
105 	    if (  !(r->or_left->row  > or_right->row ||
106 		    r->or_right->row < or_left->row  ||
107 		    r->or_left->col  > or_right->col ||
108 		    r->or_right->col < or_left->col)) {
109 		error("Framed ranges may not be nested or overlapping");
110 		return;
111 	    }
112 	}
113     }
114 
115     if (ir_left != or_left || ir_right != or_right) {
116 	r = (struct frange *)scxmalloc((unsigned)sizeof(struct frange));
117 	r->or_left = or_left;
118 	r->or_right = or_right;
119 
120 	if (ir_left) {
121 	    r->ir_left  = ir_left;
122 	    r->ir_right = ir_right;
123 	} else {
124 	    if (toprows    < 0) toprows    = 0;
125 	    if (bottomrows < 0) bottomrows = 0;
126 	    if (leftcols   < 0) leftcols   = 0;
127 	    if (rightcols  < 0) rightcols  = 0;
128 	    r->ir_left = lookat(r->or_left->row + toprows,
129 		    r->or_left->col + leftcols);
130 	    r->ir_right = lookat(r->or_right->row - bottomrows,
131 		    r->or_right->col - rightcols);
132 	}
133 
134 	r->r_next = frame_base;
135 	r->r_prev = NULL;
136 	if (frame_base)
137 	    frame_base->r_prev = r;
138 	frame_base = r;
139 	modflg++;
140 	FullUpdate++;
141     }
142 }
143 
144 void
clean_frange()145 clean_frange()
146 {
147     register struct frange *fr;
148     register struct frange *nextfr;
149 
150     fr = frame_base;
151     frame_base = NULL;
152 
153     while (fr) {
154 	nextfr = fr->r_next;
155 	scxfree((char *)fr);
156 	fr = nextfr;
157     }
158     lastfr = NULL;
159 }
160 
161 struct frange *
find_frange(int row,int col)162 find_frange(int row, int col)
163 {
164     struct frange *r;
165 
166     if (frame_base)
167 	for (r = frame_base; r; r = r->r_next) {
168 	    if ((r->or_left->row <= row) && (r->or_left->col <= col) &&
169 		    (r->or_right->row >= row) && (r->or_right->col >= col))
170 		return r;
171 	}
172     return 0;
173 }
174 
175 void
sync_franges()176 sync_franges()
177 {
178     struct frange *fr;
179 
180     fr = frame_base;
181     while (fr) {
182 	fr->or_left  = lookat(fr->or_left->row,  fr->or_left->col);
183 	fr->or_right = lookat(fr->or_right->row, fr->or_right->col);
184 	fr->ir_left  = lookat(fr->ir_left->row,  fr->ir_left->col);
185 	fr->ir_right = lookat(fr->ir_right->row, fr->ir_right->col);
186 	fr = fr->r_next;
187     }
188 }
189 
190 void
write_franges(FILE * f)191 write_franges(FILE *f)
192 {
193     register struct frange *r;
194     register struct frange *nextr;
195 
196     for (r = nextr = frame_base; nextr; r = nextr, nextr = r->r_next) /**/ ;
197     while (r) {
198 	fprintf(f, "frame %s", v_name(r->or_left->row, r->or_left->col));
199 	fprintf(f, ":%s", v_name(r->or_right->row, r->or_right->col));
200 	fprintf(f, " %s", v_name(r->ir_left->row, r->ir_left->col));
201 	fprintf(f, ":%s\n", v_name(r->ir_right->row, r->ir_right->col));
202 
203 	r = r->r_prev;
204     }
205 }
206 
207 void
list_frames(FILE * f)208 list_frames(FILE *f)
209 {
210     register struct frange *r;
211     register struct frange *nextr;
212 
213     if (!are_frames()) {
214 	fprintf(f, "  No frames");
215 	return;
216     }
217 
218     (void) fprintf(f, "  %-30s %s\n","Outer Range","Inner Range");
219     if (!brokenpipe)
220 	(void) fprintf(f, "  %-30s %s\n","-----------","-----------");
221 
222     for (r = nextr = frame_base; nextr; r = nextr, nextr = r->r_next) /* */ ;
223     while (r) {
224 	fprintf(f, "  %-30s", r_name(r->or_left->row, r->or_left->col,
225 		r->or_right->row, r->or_right->col));
226 	fprintf(f, " %s\n", r_name(r->ir_left->row, r->ir_left->col,
227 		r->ir_right->row, r->ir_right->col));
228 	if (brokenpipe) return;
229 	r = r->r_prev;
230     }
231 }
232 
233 int
are_frames()234 are_frames()
235 {
236     return (frame_base != 0);
237 }
238 
239 void
fix_frames(int row1,int col1,int row2,int col2,int delta1,int delta2)240 fix_frames(int row1, int col1, int row2, int col2, int delta1, int delta2)
241 {
242     int r1, r2, c1, c2;
243     struct frange *fr, *cfr;
244 
245     cfr = find_frange(currow, curcol);
246     if (frame_base)
247 	for (fr = frame_base; fr; fr = fr->r_next) {
248 	    r1 = fr->or_left->row;
249 	    c1 = fr->or_left->col;
250 	    r2 = fr->or_right->row;
251 	    c2 = fr->or_right->col;
252 
253 	    if (!(cfr && (c1 < cfr->or_left->col || c1 > cfr->or_right->col))) {
254 		if (r1 >= row1 && r1 <= row2) r1 = row2 - delta1;
255 		if (c1 >= col1 && c1 <= col2) c1 = col2 - delta1;
256 	    }
257 
258 	    if (!(cfr && (c2 < cfr->or_left->col || c2 > cfr->or_right->col))) {
259 		if (r2 >= row1 && r2 <= row2) r2 = row1 + delta2;
260 		if (c2 >= col1 && c2 <= col2) c2 = col1 + delta2;
261 	    }
262 
263 	    fr->or_left = lookat(r1, c1);
264 	    fr->or_right = lookat(r2, c2);
265 
266 	    r1 = fr->ir_left->row;
267 	    c1 = fr->ir_left->col;
268 	    r2 = fr->ir_right->row;
269 	    c2 = fr->ir_right->col;
270 
271 	    if (!(cfr && (c1 < cfr->or_left->col || c1 > cfr->or_right->col))) {
272 		if (r1 >= row1 && r1 <= row2) r1 = row2 - delta1;
273 		if (c1 >= col1 && c1 <= col2) c1 = col2 - delta1;
274 	    }
275 
276 	    if (!(cfr && (c2 < cfr->or_left->col || c2 > cfr->or_right->col))) {
277 		if (r2 >= row1 && r2 <= row2) r2 = row1 + delta2;
278 		if (c2 >= col1 && c2 <= col2) c2 = col1 + delta2;
279 	    }
280 
281 	    fr->ir_left = lookat(r1, c1);
282 	    fr->ir_right = lookat(r2, c2);
283 	}
284 }
285