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