1 /*
2 * $Id: regions.c,v 1.16 2000/08/10 21:02:51 danny Exp $
3 *
4 * Copyright � 1990, 1992, 1993 Free Software Foundation, Inc.
5 *
6 * This file is part of Oleo, the GNU Spreadsheet.
7 *
8 * Oleo is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * Oleo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Oleo; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #ifdef WITH_DMALLOC
28 #include <dmalloc.h>
29 #endif
30
31 #include "funcdef.h"
32 #include <stdio.h>
33 #include "sysdef.h"
34 #include "global.h"
35 #include "cell.h"
36 #include "io-generic.h"
37 #include "io-abstract.h"
38 #include "io-utils.h"
39 #include "lists.h"
40 #include "ref.h"
41 #include "regions.h"
42 #include "io-term.h"
43 #include "window.h"
44 #include "cmd.h"
45 #include "sort.h"
46 #include "basic.h"
47
48 /* Apparently "all_rng" is read-only, therefore need not be put in Global. */
49 struct rng all_rng = {MIN_ROW, MIN_COL, MAX_ROW, MAX_COL};
50
51 /* Take a struct rng (R) and init its elements to R1 C1 R2 C2, making sure
52 they are put in in the right order.
53 */
54 void
set_rng(struct rng * r,CELLREF r1,CELLREF c1,CELLREF r2,CELLREF c2)55 set_rng (struct rng *r, CELLREF r1, CELLREF c1, CELLREF r2, CELLREF c2)
56 {
57 if (r1 <= r2)
58 {
59 r->lr = r1;
60 r->hr = r2;
61 }
62 else
63 {
64 r->lr = r2;
65 r->hr = r1;
66 }
67 if (c1 <= c2)
68 {
69 r->lc = c1;
70 r->hc = c2;
71 }
72 else
73 {
74 r->lc = c2;
75 r->hc = c1;
76 }
77 }
78
79 /* Flush all the cells in a region */
80 void
delete_region(struct rng * where)81 delete_region (struct rng *where)
82 {
83 CELLREF rr, cc;
84 CELL *pp;
85
86 Global->modified = 1;
87
88 find_cells_in_range (where);
89 while ((pp = next_row_col_in_range (&rr, &cc)))
90 {
91 if (!pp->cell_formula && !GET_TYP (pp))
92 {
93 bzero(&(pp->cell_flags), sizeof(pp->cell_flags));
94 pp->cell_font = 0;
95 continue;
96 }
97 cur_row = rr;
98 cur_col = cc;
99 my_cell = pp;
100 flush_old_value ();
101 pp->cell_formula = 0;
102 bzero(&(pp->cell_flags), sizeof(pp->cell_flags));
103 pp->cell_font = 0;
104 push_refs (pp->cell_refs_from);
105 io_pr_cell (rr, cc, pp);
106 }
107 my_cell = 0;
108 }
109
110 /* Turn on/off the locked bits in a region */
111 void
lock_region(struct rng * where,int locked)112 lock_region (struct rng *where, int locked)
113 {
114 CELL *cp;
115
116 Global->modified = 1;
117 make_cells_in_range (where);
118 while ((cp = next_cell_in_range ()))
119 SET_LCK (cp, locked);
120 }
121
122 void
format_region(struct rng * where,int fmt,int just)123 format_region (struct rng *where, int fmt, int just)
124 {
125 CELL *cp;
126 CELLREF rr, cc;
127
128 Global->modified = 1;
129 make_cells_in_range (where);
130 while ((cp = next_row_col_in_range (&rr, &cc)))
131 {
132 if (fmt != -1) {
133 SET_FORMAT (cp, fmt); /* Only the format, not the precision !! */
134 }
135 if (just != -1)
136 SET_JST (cp, just);
137 io_pr_cell (rr, cc, cp);
138 }
139 }
140
141 void
precision_region(struct rng * where,int precision)142 precision_region (struct rng *where, int precision)
143 {
144 CELL *cp;
145 CELLREF rr, cc;
146
147 Global->modified = 1;
148 make_cells_in_range (where);
149 while ((cp = next_row_col_in_range (&rr, &cc)))
150 {
151 if (precision != -1)
152 SET_PRECISION (cp, precision);
153 io_pr_cell (rr, cc, cp);
154 }
155 }
156
157 unsigned int print_width;
158
159 void
txt_print_region(struct rng * print,FILE * fp)160 txt_print_region (struct rng *print, FILE *fp)
161 {
162 CELLREF rr, cc;
163 CELL *cp;
164 char *ptr;
165 int w;
166 int j;
167 int lenstr;
168 int spaces;
169 CELLREF c_lo, c_hi;
170
171 for (c_lo = print->lc, c_hi = 0; c_hi != print->hc; c_lo = c_hi + 1)
172 {
173 w = 0;
174 for (w = get_width (cc = c_lo); w <= print_width && cc <= print->hc; w += get_width (++cc))
175 ;
176 if (cc != c_lo)
177 --cc;
178 c_hi = cc;
179
180 for (rr = print->lr; rr <= print->hr; rr++)
181 {
182 spaces = 0;
183 for (cc = c_lo; cc <= c_hi; cc++)
184 {
185 w = get_width (cc);
186 if (!w)
187 continue;
188 cp = find_cell (rr, cc);
189 if (!cp || !GET_TYP (cp))
190 {
191 spaces += w;
192 continue;
193 }
194 ptr = print_cell (cp);
195 lenstr = strlen (ptr);
196 if (lenstr == 0)
197 {
198 spaces += w;
199 continue;
200 }
201 if (spaces)
202 {
203 fprintf (fp, "%*s", spaces, "");
204 spaces = 0;
205 }
206 j = GET_JST (cp);
207 if (j == JST_DEF)
208 j = default_jst;
209 if (lenstr <= w - 1)
210 {
211 if (j == JST_LFT)
212 {
213 fprintf (fp, "%s", ptr);
214 spaces = w - lenstr;
215 }
216 else if (j == JST_RGT)
217 {
218 fprintf (fp, "%*s", w - 1, ptr);
219 spaces = 1;
220 }
221 else if (j == JST_CNT)
222 {
223 w = (w - 1) - lenstr;
224 fprintf (fp, "%*s", w / 2 + lenstr, ptr);
225 spaces = (w + 3) / 2;
226 }
227 #ifdef TEST
228 else
229 {
230 panic ("What just %d", j);
231 }
232 #endif
233 }
234 else
235 {
236 CELLREF ccc = cc;
237 CELL *ccp;
238 int tmp_wid;
239 unsigned int ww;
240
241 for (ww = w;; tmp_wid = get_width (ccc), w += tmp_wid, spaces -= tmp_wid)
242 {
243 if (lenstr < w - 1)
244 break;
245 if (++ccc > c_hi)
246 break;
247 ccp = find_cell (rr, ccc);
248 if (!ccp || !GET_TYP (ccp) || GET_FORMAT (ccp) == FMT_HID)
249 continue;
250 if (GET_FORMAT (ccp) == FMT_DEF && default_fmt == FMT_HID)
251 continue;
252 break;
253 }
254 if (lenstr > w - 1)
255 {
256 if (GET_TYP (cp) == TYP_FLT)
257 {
258 ptr = adjust_prc (ptr, cp, w - 1, ww - 1, j);
259 lenstr = strlen (ptr);
260 }
261 else if (GET_TYP (cp) == TYP_INT)
262 {
263 ptr = numb_oflo;
264 lenstr = 80;
265 }
266 fprintf (fp, "%.*s", w - 1, ptr);
267 if (lenstr < w)
268 spaces += w - lenstr;
269 else
270 spaces++;
271 }
272 else
273 {
274 fprintf (fp, "%s", ptr);
275 spaces += w - lenstr;
276 }
277 }
278 }
279 (void) putc ('\n', fp);
280 }
281 }
282 }
283
284
285 /*
286 Set up regions for the move/copy functions. This deals with default
287 sizing of the target region, regions that don't fit, etc.
288
289 This returns
290 -1 if the regions overlap
291 0 if there is a *real* error
292 1 if the target is a multiple of the source
293 2 if everything is OK.
294 */
295
296 static int
set_to_region(struct rng * fm,struct rng * to)297 set_to_region (struct rng *fm, struct rng *to)
298 {
299 /* Delta {row,col} {from,to} */
300 int drf, dcf;
301 int drt, dct;
302 int ret = 2;
303
304 drf = fm->hr - fm->lr;
305 drt = to->hr - to->lr;
306 if (drt == 0)
307 {
308 if (to->lr > MAX_ROW - drf)
309 {
310 io_error_msg ("The range won't fit this far down!");
311 return 0;
312 }
313 to->hr = to->lr + drf;
314 }
315 else if (drf != drt)
316 {
317 if ((drt + 1) % (drf + 1) == 0)
318 ret = 1;
319 else
320 {
321 io_error_msg ("Rows %u:%u and %u:%u don't fit", fm->lr, fm->hr, to->lr, to->hr);
322 return 0;
323 }
324 }
325 dcf = fm->hc - fm->lc;
326 dct = to->hc - to->lc;
327 if (dct == 0)
328 {
329 if (to->lc > MAX_COL - dcf)
330 {
331 io_error_msg ("The range won't fit this far over!");
332 return 0;
333 }
334 to->hc = to->lc + dcf;
335 }
336 else if (dcf != dct)
337 {
338 if ((dct + 1) % (dcf + 1) == 0)
339 ret = 1;
340 else
341 {
342 io_error_msg ("Cols %u:%u and %u:%u don't fit", fm->lc, fm->hc, to->lc, to->hc);
343 return 0;
344 }
345 }
346
347 if (fm->lr == to->lr && fm->lc == to->lc)
348 {
349 io_error_msg ("Regions are in the same place");
350 return 0;
351 }
352
353 if (((fm->lr <= to->lr && to->lr <= fm->hr) || (fm->lr <= to->hr && to->hr <= fm->hr))
354 && ((fm->lc <= to->lc && to->lc <= fm->hc) || (fm->lc <= to->hc && to->hc <= fm->hc)))
355 return -1;
356 Global->modified = 1;
357 return ret;
358 }
359
360 /* This is only complicated because it must deal with overlap, and it wants
361 to be smart about copying empty space. . .
362 */
363 void
move_region(struct rng * fm,struct rng * to)364 move_region (struct rng *fm, struct rng *to)
365 {
366 /* Delta {row,col} */
367 int dr, dc;
368 int nr, nc;
369 int ov, dn;
370 struct rng del_to_1, del_to_2;
371 int do_2, dirs[2];
372 int maxr, maxc;
373 CELLREF cmax, rmax;
374 int cdmax, rdmax;
375 int must_repaint = 0; /* If this move changes cell widths/heights */
376
377 switch (set_to_region (fm, to))
378 {
379 case 0:
380 return;
381
382 case 1:
383 io_error_msg ("Can't move source to multiple targets");
384 return;
385
386 case 2:
387 del_to_1 = *to;
388
389 do_2 = 0;
390 dirs[0] = 1;
391 dirs[1] = 1;
392
393 /* del_fm_1= *fm; */
394 break;
395
396 default:
397 /* They overlap. There are eight ways that
398 they can overlap. */
399 if (to->lc == fm->lc && to->lr < fm->lr)
400 {
401 /* State 1: 'from' on bottom */
402 del_to_1.lr = to->lr;
403 del_to_1.lc = to->lc;
404 del_to_1.hr = fm->lr - 1;
405 del_to_1.hc = to->hc;
406
407 do_2 = 0;
408 dirs[0] = 1;
409 dirs[1] = 1;
410
411 /* del_fm_1.lr=to->hr+1; del_fm_1.lc=fm->lc;
412 del_fm_1.hr=fm->hr; del_fm_1.hc=fm->hc; */
413 }
414 else if (to->lc == fm->lc)
415 {
416 /* State 2: 'from' on top */
417 del_to_1.lr = fm->hr + 1;
418 del_to_1.lc = to->lc;
419 del_to_1.hr = to->hr;
420 del_to_1.hc = to->hc;
421
422 do_2 = 0;
423 dirs[0] = -1;
424 dirs[1] = 1;
425
426 /* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
427 del_fm_1.hr=to->lr-1; del_fm_1.hc=fm->hc; */
428 }
429 else if (to->lr == fm->lr && to->lc < fm->lc)
430 {
431 /* State 3: 'from' on right */
432 del_to_1.lr = to->lr;
433 del_to_1.lc = to->lc;
434 del_to_1.hr = to->hr;
435 del_to_1.hc = fm->lc - 1;
436
437 do_2 = 0;
438 dirs[0] = 1;
439 dirs[1] = 1;
440
441 /* del_fm_1.lr=fm->lr; del_fm_1.lc=to->hc+1;
442 del_fm_1.hr=fm->hr; del_fm_1.hc=fm->hc; */
443 }
444 else if (to->lr == fm->lr)
445 {
446 /* State 4: 'from' on left */
447 del_to_1.lr = to->lr;
448 del_to_1.lc = fm->hc + 1;
449 del_to_1.hr = to->hr;
450 del_to_1.hc = to->hc;
451
452 do_2 = 0;
453 dirs[0] = 1;
454 dirs[1] = -1;
455
456 /* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
457 del_fm_1.hr=fm->hr; del_fm_1.hc=to->lc-1; */
458 }
459 else if (fm->lr < to->lr && fm->lc < to->lc)
460 {
461 /* State 5: From on topleft */
462
463 del_to_1.lr = to->lr;
464 del_to_1.lc = fm->hc + 1;
465 del_to_1.hr = fm->hr;
466 del_to_1.hc = to->hc;
467
468 del_to_2.lr = fm->hr + 1;
469 del_to_2.lc = to->lc;
470 del_to_2.hr = to->hr;
471 del_to_2.hc = to->hc;
472
473 do_2 = 1;
474 dirs[0] = -1;
475 dirs[1] = -1;
476
477 /* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
478 del_fm_1.hr=to->lr-1; del_fm_1.hc=fm->hc;
479
480 del_fm_2.lr=to->lr; del_fm_2.lc=fm->lc;
481 del_fm_2.hr=fm->hr; del_fm_2.hc=to->lc-1; */
482 }
483 else if (fm->lr < to->lr)
484 {
485 /* State 6: 'from' on topright */
486 del_to_1.lr = to->lr;
487 del_to_1.lc = to->lc;
488 del_to_1.hr = fm->hr;
489 del_to_1.hc = fm->lc - 1;
490
491 del_to_2.lr = fm->hr + 1;
492 del_to_2.lc = to->lc;
493 del_to_2.hr = to->hr;
494 del_to_2.hc = to->hc;
495
496 do_2 = 1;
497 dirs[0] = -1;
498 dirs[1] = 1;
499
500 /* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
501 del_fm_1.hr=to->lr-1; del_fm_1.hc=fm->hc;
502
503 del_fm_2.lr=to->lr; del_fm_2.lc=to->hc+1;
504 del_fm_2.hr=fm->hr; del_fm_2.hc=fm->hc; */
505 }
506 else if (fm->lc < to->lc)
507 {
508 /* State 7: 'from on bottomleft */
509 del_to_1.lr = to->lr;
510 del_to_1.lc = to->lc;
511 del_to_1.hr = fm->lr - 1;
512 del_to_1.hc = to->hc;
513
514 del_to_2.lr = fm->lr;
515 del_to_2.lc = fm->hc;
516 del_to_2.hr = to->hr;
517 del_to_2.hc = to->hc;
518
519 do_2 = 1;
520 dirs[0] = 1;
521 dirs[1] = -1;
522
523 /* del_fm_1.lr=fm->lr; del_fm_1.lc=fm->lc;
524 del_fm_1.hr=to->hr; del_fm_1.hc=to->lc-1;
525
526 del_fm_2.lr=to->hr+1; del_fm_2.lc=fm->lc;
527 del_fm_2.hr=to->hr+1; del_fm_2.hc=to->lc-1; */
528 }
529 else
530 {
531 /* State 8: 'from' on bottomright */
532 del_to_1.lr = to->lr;
533 del_to_1.lc = to->lc;
534 del_to_1.hr = fm->lr - 1;
535 del_to_1.hc = to->hc;
536
537 del_to_2.lr = fm->lr;
538 del_to_2.lc = to->lc;
539 del_to_2.hr = to->hr;
540 del_to_2.hc = fm->lc - 1;
541
542 do_2 = 1;
543 dirs[0] = 1;
544 dirs[1] = 1;
545
546 /* del_fm_1.lr=fm->lr; del_fm_1.lc=to->hc+1;
547 del_fm_1.hr=to->hr; del_fm_1.hc=fm->hc;
548
549 del_fm_2.lr=to->hr+1; del_fm_2.lc=fm->lc;
550 del_fm_2.hr=fm->hr; del_fm_2.hc=fm->hc; */
551 }
552 }
553 dn = to->hr - fm->hr;
554 ov = to->hc - fm->hc;
555
556 dr = fm->hr - fm->lr;
557 dc = fm->hc - fm->lc;
558
559 delete_region (&del_to_1);
560 if (do_2)
561 delete_region (&del_to_2);
562
563 if (to->lr == MIN_ROW && to->hr == MAX_ROW)
564 {
565 shift_widths (ov, fm->lc, fm->hc);
566 must_repaint = 1;
567 }
568
569 if (to->lc == MIN_COL && to->hc == MAX_COL)
570 {
571 shift_heights (dn, fm->lr, fm->hr);
572 must_repaint = 1;
573 }
574
575 shift_outside (fm, dn, ov);
576
577 rmax = highest_row ();
578 if (rmax < fm->lr)
579 rdmax = -1;
580 else if (rmax > fm->hr)
581 rdmax = dr;
582 else
583 rdmax = rmax - fm->lr;
584 nr = (dirs[0] > 0) ? 0 : rdmax;
585 maxr = (dirs[0] > 0) ? rdmax + 1 : -1;
586 for (; nr != maxr; nr += dirs[0])
587 {
588 cmax = max_col (fm->lr + nr);
589 if (cmax < fm->lc)
590 cdmax = -1;
591 else if (cmax > fm->hc)
592 cdmax = dc;
593 else
594 {
595 cdmax = cmax - fm->lc;
596 }
597 nc = (dirs[1] > 0) ? 0 : cdmax;
598 maxc = (dirs[1] > 0) ? cdmax + 1 : -1;
599 for (; nc != maxc; nc += dirs[1])
600 {
601 CELLREF rf, cf, rt, ct;
602 CELL *cpf;
603
604 rf = fm->lr + nr;
605 cf = fm->lc + nc;
606 rt = to->lr + nr;
607 ct = to->lc + nc;
608
609 cpf = find_cell (rf, cf);
610 cur_row = rt;
611 cur_col = ct;
612 my_cell = find_cell (cur_row, cur_col);
613 if ((!cpf || (!cpf->cell_font &&
614 ((cpf->cell_flags.cell_format == 0)
615 && (cpf->cell_flags.cell_precision == 0)
616 && (cpf->cell_flags.cell_justify == 0)
617 && (cpf->cell_flags.cell_type == 0))
618 && (cpf->cell_flags.cell_lock == 0)
619 && !cpf->cell_formula))
620 && !my_cell)
621 continue;
622
623 if (!cpf)
624 {
625 bzero(&(my_cell->cell_flags), sizeof(my_cell->cell_flags));
626 my_cell->cell_font = 0;
627 my_cell->cell_refs_to = 0;
628 my_cell->cell_formula = 0;
629 my_cell->cell_cycle = 0;
630 my_cell = 0;
631 continue;
632 }
633 if (!my_cell)
634 {
635 my_cell = find_or_make_cell (cur_row, cur_col);
636 cpf = find_cell (rf, cf);
637 }
638 else
639 flush_old_value ();
640
641 my_cell->cell_flags = cpf->cell_flags;
642 my_cell->cell_font = cpf->cell_font;
643 my_cell->cell_refs_to = cpf->cell_refs_to;
644 my_cell->cell_formula = cpf->cell_formula;
645 my_cell->cell_cycle = cpf->cell_cycle;
646 my_cell->c_z = cpf->c_z;
647
648 bzero(&(cpf->cell_flags), sizeof(cpf->cell_flags));
649 cpf->cell_font = 0;
650 cpf->cell_refs_to = 0;
651 cpf->cell_formula = 0;
652 cpf->cell_cycle = 0;
653
654 push_cell (cur_row, cur_col);
655
656 if (!must_repaint)
657 {
658 if (cpf)
659 io_pr_cell (rf, cf, cpf);
660 if (my_cell)
661 io_pr_cell (rt, ct, my_cell);
662 }
663 my_cell = 0;
664 }
665 }
666 if (must_repaint)
667 io_repaint ();
668 /* Perpetration of an interface change here. If we really
669 * need to get back to the old region, we can do it by
670 * wrapping the move-region command in macros that set
671 * and return to a hardy mark. We might, however, want
672 * to jump the moved text again, or reformat it in some
673 * way, so the mark should travel with us.
674 *
675 * to->lr and to->lc give the lowest column and row (northwest
676 * corner) in the destination region, to->hr and to->hc five the
677 * highest, or southeast corner. The absolute value if their
678 * difference tells us how far to move over and down from
679 * northwest to mark the region just moved. This way the new
680 * region can be operated on as a chunk immediately
681 *
682 * --FB 1997.12.17
683 */
684 if (mkrow != NON_ROW) {
685 mkrow = to->lr + abs(to->lr - to->hr);
686 mkcol = to->lc + abs(to->lc - to->hc);
687 }
688 goto_region (to);
689 return;
690 }
691
692 void
copy_region(struct rng * fm,struct rng * to)693 copy_region (struct rng *fm, struct rng *to)
694 {
695 CELLREF rf, rt, cf, ct;
696
697 if (set_to_region (fm, to) < 1)
698 return;
699
700 for (rf = fm->lr, rt = to->lr; (rt > 0) && (rt <= to->hr); rt++, rf++)
701 {
702 for (cf = fm->lc, ct = to->lc; (ct > 0) && (ct <= to->hc); ct++, cf++)
703 {
704 copy_cell (rf, cf, rt, ct);
705
706 if (cf == fm->hc)
707 cf = fm->lc - 1;
708 }
709 if (rf == fm->hr)
710 rf = fm->lr - 1;
711 }
712 if (mkrow != NON_ROW) {
713 mkrow = to->lr + abs(to->lr - to->hr);
714 mkcol = to->lc + abs(to->lc - to->hc);
715 }
716 goto_region (to);
717 }
718
719 void
copy_values_region(struct rng * fm,struct rng * to)720 copy_values_region (struct rng *fm, struct rng *to)
721 {
722 CELLREF rf, rt, cf, ct;
723 union vals dummy;
724 CELL *cpf;
725
726 if (set_to_region (fm, to) < 1)
727 return;
728
729 for (rf = fm->lr, rt = to->lr; rt <= to->hr; rt++, rf++)
730 {
731 for (cf = fm->lc, ct = to->lc; ct <= to->hc; ct++, cf++)
732 {
733 cpf = find_cell (rf, cf);
734 set_new_value (rt, ct, cpf ? GET_TYP (cpf) : 0, cpf ? &(cpf->c_z) : &dummy);
735
736 if (cf == fm->hc)
737 cf = fm->lc - 1;
738 }
739 if (rf == fm->hr)
740 rf = fm->lr - 1;
741 }
742 }
743
744 struct rng sort_rng;
745 struct rng sort_ele;
746 struct cmp *sort_keys;
747 int sort_keys_alloc;
748 int sort_keys_num = 0;
749
750 static int srdiff, erdiff, scdiff, ecdiff;
751
752 #ifdef TEST
753 extern int debug;
754 #endif
755
756 void
sort_region(void)757 sort_region (void)
758 {
759 srdiff = 1 + sort_rng.hr - sort_rng.lr;
760 erdiff = 1 + sort_ele.hr - sort_ele.lr;
761
762 scdiff = 1 + sort_rng.hc - sort_rng.lc;
763 ecdiff = 1 + sort_ele.hc - sort_ele.lc;
764
765 if (srdiff != erdiff && srdiff % erdiff != 0)
766 {
767 io_error_msg ("Rows %u:%u and %u:%u don't fit", sort_rng.lr, sort_rng.hr, sort_ele.lr, sort_ele.hr);
768 return;
769 }
770 if (scdiff != ecdiff && scdiff % ecdiff != 0)
771 {
772 io_error_msg ("Cols %u:%u and %u:%u don't fit", sort_rng.lc, sort_rng.hc, sort_ele.lc, sort_ele.hc);
773 return;
774 }
775 if (scdiff != ecdiff && srdiff != erdiff)
776 {
777 io_error_msg ("Can't sort this region!");
778 return;
779 }
780 Global->modified = 1;
781 if (scdiff != ecdiff)
782 {
783 erdiff = 0;
784 sort (scdiff / ecdiff, cmp_cells, swp_cells, rot_cells);
785 }
786 else
787 {
788 ecdiff = 0;
789 sort (srdiff / erdiff, cmp_cells, swp_cells, rot_cells);
790 }
791 }
792
793 int
cmp_cells(int n1,int n2)794 cmp_cells (int n1, int n2)
795 {
796 CELL *c1, *c2;
797 int t1, t2;
798 union vals v1, v2;
799 CELLREF row1, row2, col1, col2;
800 int keyn;
801 int cmpval;
802
803 if (n1 == n2)
804 return 0;
805
806 for (keyn = 0; keyn < sort_keys_num; keyn++)
807 {
808 row1 = sort_rng.lr + (n1 * erdiff) + sort_keys[keyn].row;
809 col1 = sort_rng.lc + (n1 * ecdiff) + sort_keys[keyn].col;
810 row2 = sort_rng.lr + (n2 * erdiff) + sort_keys[keyn].row;
811 col2 = sort_rng.lc + (n2 * ecdiff) + sort_keys[keyn].col;
812 #ifdef TEST
813 if (debug & 04)
814 io_error_msg ("Cmp %u %u r%uc%u <-%u-> r%uc%u", n1, n2, row1, col1, sort_keys[keyn].mult, row2, col2);
815 #endif
816 c1 = find_cell (row1, col1);
817 c2 = find_cell (row2, col2);
818 if (!c1 && !c2)
819 continue;
820
821 if (c1)
822 {
823 t1 = GET_TYP (c1);
824 v1 = c1->c_z;
825 }
826 else
827 t1 = 0;
828 if (c2)
829 {
830 t2 = GET_TYP (c2);
831 v2 = c2->c_z;
832 }
833 else
834 t2 = 0;
835
836 if (t1 == TYP_ERR || t1 == TYP_BOL)
837 {
838 t1 = TYP_STR;
839 v1.c_s = print_cell (c1);
840 }
841 if (t2 == TYP_ERR || t2 == TYP_BOL)
842 {
843 t2 = TYP_STR;
844 v2.c_s = print_cell (c2);
845 }
846 if (t1 != t2)
847 {
848 if (t1 == 0)
849 {
850 if (t2 == TYP_STR)
851 {
852 t1 = TYP_STR;
853 v1.c_s = "";
854 }
855 else if (t2 == TYP_INT)
856 {
857 t1 = TYP_INT;
858 v1.c_l = 0;
859 }
860 else
861 {
862 t1 = TYP_FLT;
863 v1.c_d = 0.0;
864 }
865 }
866 else if (t2 == 0)
867 {
868 if (t1 == TYP_STR)
869 {
870 t2 = TYP_STR;
871 v2.c_s = "";
872 }
873 else if (t1 == TYP_INT)
874 {
875 t2 = TYP_INT;
876 v2.c_l = 0;
877 }
878 else
879 {
880 t2 = TYP_FLT;
881 v2.c_d = 0.0;
882 }
883 }
884 else if (t1 == TYP_STR)
885 {
886 t2 = TYP_STR;
887 v2.c_s = print_cell (c2);
888 }
889 else if (t2 == TYP_STR)
890 {
891 t1 = TYP_STR;
892 v1.c_s = print_cell (c1);
893 /* If we get here, one is INT, and the other
894 is FLT Make them both FLT */
895 }
896 else if (t1 == TYP_INT)
897 {
898 t1 = TYP_FLT;
899 v1.c_d = (double) v1.c_l;
900 }
901 else
902 {
903 t2 = TYP_FLT;
904 v2.c_d = (double) v2.c_l;
905 }
906 }
907 if (t1 == TYP_STR)
908 cmpval = strcmp (v1.c_s, v2.c_s);
909 else if (t1 == TYP_FLT)
910 cmpval = (v1.c_d < v2.c_d) ? -1 : ((v1.c_d > v2.c_d) ? 1 : 0);
911 else if (t1 == TYP_INT)
912 cmpval = (v1.c_l < v2.c_l) ? -1 : ((v1.c_l > v2.c_l) ? 1 : 0);
913 else
914 cmpval = 0;
915 if (cmpval)
916 return cmpval * sort_keys[keyn].mult;
917 }
918
919 return 0;
920 }
921
922 void
swp_cells(int n1,int n2)923 swp_cells (int n1, int n2)
924 {
925 int rn, cn;
926 CELLREF r1, r2, c1, c2;
927
928 #ifdef TEST
929 if (debug & 04)
930 io_error_msg ("Swap %u<-->%u", n1, n2);
931 #endif
932 for (rn = sort_ele.lr; rn <= sort_ele.hr; rn++)
933 for (cn = sort_ele.lc; cn <= sort_ele.hc; cn++)
934 {
935 r1 = sort_rng.lr + (n1 * erdiff) + rn;
936 r2 = sort_rng.lr + (n2 * erdiff) + rn;
937 c1 = sort_rng.lc + (n1 * ecdiff) + cn;
938 c2 = sort_rng.lc + (n2 * ecdiff) + cn;
939 #ifdef TEST
940 if (debug & 04)
941 io_error_msg ("Save r%uc%u", r1, c1);
942 #endif
943 move_cell (r1, c1, NON_ROW, NON_COL);
944 #ifdef TEST
945 if (debug & 04)
946 io_error_msg ("Copy r%uc%u --> r%uc%u", r2, c2, r1, c1);
947 #endif
948 move_cell (r2, c2, r1, c1);
949
950 #ifdef TEST
951 if (debug & 04)
952 io_error_msg ("Restore r%uc%u", r2, c2);
953 #endif
954 move_cell (NON_ROW, NON_COL, r2, c2);
955
956 /* push_cell(r1,c1);
957 push_cell(r2,c2); */
958 }
959 }
960
961 void
rot_cells(int n1,int n2)962 rot_cells (int n1, int n2)
963 {
964 int rn, cn;
965 int nn;
966 CELLREF r1, r2, c1, c2;
967
968 if (n1 + 1 == n2 || n2 + 1 == n1)
969 {
970 swp_cells (n1, n2);
971 return;
972 }
973 #ifdef TEST
974 if (debug & 04)
975 io_error_msg ("Rot cells %u -- %u", n1, n2);
976 #endif
977 for (rn = sort_ele.lr; rn <= sort_ele.hr; rn++)
978 for (cn = sort_ele.lc; cn <= sort_ele.hc; cn++)
979 {
980
981 /* store a copy of cell # n2 */
982 r2 = sort_rng.lr + (n2 * erdiff) + rn;
983 c2 = sort_rng.lc + (n2 * ecdiff) + cn;
984 move_cell (r2, c2, NON_ROW, NON_COL);
985
986 #ifdef TEST
987 if (debug & 04)
988 io_error_msg ("Save r%uc%u", r2, c2);
989 #endif
990 /* Copy each cell from n1 to n2-1 up one */
991 for (nn = n2; nn > n1; --nn)
992 {
993 r2 = sort_rng.lr + (nn * erdiff) + rn;
994 c2 = sort_rng.lc + (nn * ecdiff) + cn;
995
996 r1 = sort_rng.lr + ((nn - 1) * erdiff) + rn;
997 c1 = sort_rng.lc + ((nn - 1) * ecdiff) + cn;
998
999 move_cell (r1, c1, r2, c2);
1000 #ifdef TEST
1001 if (debug & 04)
1002 io_error_msg ("Copy r%uc%u --> r%uc%u", r1, c1, r2, c2);
1003 #endif
1004 /* push_cell(r2,c2); */
1005 }
1006
1007 r1 = sort_rng.lr + (nn * erdiff) + rn;
1008 c1 = sort_rng.lc + (nn * ecdiff) + cn;
1009 #ifdef TEST
1010 if (debug & 04)
1011 io_error_msg ("Restore r%uc%u", r1, c1);
1012 #endif
1013 move_cell (NON_ROW, NON_COL, r1, c1);
1014
1015 /* push_cell(r1,c1); */
1016 }
1017 }
1018
1019 /* End of functions for sort_region() */
1020