1 /*
2  * $Id: io-edit.c,v 1.13 2000/08/10 21:02:50 danny Exp $
3  *
4  * Copyright � 1992, 1993, 1999 Free Software Foundation, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this software; see the file COPYING.  If not, write to
18  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #ifdef	WITH_DMALLOC
27 #include <dmalloc.h>
28 #endif
29 
30 #include "funcdef.h"
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <ctype.h>
35 
36 #undef NULL
37 
38 #include "sysdef.h"
39 #include "global.h"
40 #include "cell.h"
41 #include "io-utils.h"
42 #include "io-edit.h"
43 #include "io-abstract.h"
44 #include "io-generic.h"
45 #include "cmd.h"
46 #include "format.h"
47 #include "lists.h"
48 #include "regions.h"
49 
50 /* Shorthand */
51 
52 #define the_cursor		the_cmd_arg.cursor
53 #define the_text 		the_cmd_arg.text
54 #define the_do_prompt		the_cmd_arg.do_prompt
55 #define the_is_set		the_cmd_arg.is_set
56 #define the_overwrite		the_cmd_arg.overwrite
57 
58 /* Editting primitives
59  *
60  * Commands that edit arguments to other commands should work by changing
61  * the string stored in the_cmd_arg.text.   These functions edit that string
62  * and correctly update the display.
63  */
64 
65 int
check_editting_mode(void)66 check_editting_mode (void)
67 {
68   if (!the_cmd_frame->cmd || cur_arg >= cmd_argc || !the_do_prompt || the_is_set)
69     {
70       io_error_msg ("Command '%s' is not appropriate now.",
71 		    cur_cmd->func_name);
72       /* not reached */
73     }
74   return 0;
75 }
76 
77 /* Set the currently-being-editted line.
78  *
79  * When this function is called, it indicates that some argument
80  * is being read interactively from the user.  That fact is recorded
81  * in the command frame because it relevant to error handling.
82  * (See cmd_error in cmd.c)
83  *
84  */
85 void
begin_edit(void)86 begin_edit (void)
87 {
88   Global->topclear = 0;
89   the_cmd_frame->complex_to_user = 1;
90   io_fix_input ();
91 }
92 
93 void
setn_edit_line(char * str,int len)94 setn_edit_line (char * str, int len)
95 {
96   setn_line (&the_text, str, len);
97   the_cursor = len;
98 }
99 
100 void
toggle_overwrite(int set,int setting)101 toggle_overwrite (int set, int setting)
102 {
103   if (!set)
104     the_overwrite = !the_overwrite;
105   else
106     the_overwrite = (setting > 0);
107 }
108 
109 void
beginning_of_line(void)110 beginning_of_line (void)
111 {
112   if (check_editting_mode ())
113     return;
114   the_cursor = 0;
115   io_move_cursor ();
116 }
117 
118 
119 void
end_of_line(void)120 end_of_line (void)
121 {
122   if (check_editting_mode ())
123     return;
124   the_cursor = strlen (the_text.buf);
125   io_move_cursor ();
126 }
127 
128 void
backward_char(int n)129 backward_char (int n)
130 {
131   if (check_editting_mode ())
132     return;
133   if (n < 0)
134     forward_char (-n);
135   else
136     {
137       char * error = 0;
138       if (the_cursor < n)
139 	{
140 	  error = "Beginning of buffer.";
141 	  the_cursor = 0;
142 	}
143       else
144 	the_cursor -= n;
145       io_move_cursor ();
146       if (error)
147 	io_error_msg (error);	/* Doesn't return. */
148     }
149 }
150 
151 void
backward_word(int n)152 backward_word (int n)
153 {
154   if (check_editting_mode ())
155     return;
156   if (n < 0)
157     forward_word (-n);
158   else
159     {
160       if (the_cursor == strlen (the_text.buf))
161 	--the_cursor;
162       while (n)
163 	{
164 	  while (the_cursor
165 		 && !isalnum (the_text.buf[the_cursor]))
166 	    --the_cursor;
167 	  while (the_cursor
168 		 && isalnum (the_text.buf[the_cursor]))
169 	    --the_cursor;
170 	  --n;
171 	}
172       io_move_cursor ();
173     }
174 }
175 
176 
177 void
forward_char(int n)178 forward_char (int n)
179 {
180   if (check_editting_mode ())
181     return;
182   if (n < 0)
183     backward_char (-n);
184   else
185     {
186       char * error = 0;
187       int len = strlen(the_text.buf);
188       if ((the_cursor + n) > len)
189 	{
190 	  error = "End of buffer.";
191 	  the_cursor = len;
192 	}
193       else
194 	the_cursor += n;
195       io_move_cursor ();
196       if (error)
197 	io_error_msg (error);	/* Doesn't return. */
198     }
199 }
200 
201 
202 void
goto_char(int n)203 goto_char (int n)
204 {
205   int len;
206   if (n < 0)
207     n = 0;
208   len = strlen(the_text.buf);
209   if (n > len)
210     n = len;
211   the_cursor = n;
212   io_move_cursor ();
213 }
214 
215 void
forward_word(int n)216 forward_word (int n)
217 {
218   if (check_editting_mode ())
219     return;
220   if (n < 0)
221     backward_word (-n);
222   else
223     {
224       int len = strlen (the_text.buf);
225       while (n)
226 	{
227 	  while ((the_cursor < len)
228 		 && !isalnum (the_text.buf[the_cursor]))
229 	    ++the_cursor;
230 	  while ((the_cursor < len)
231 		 && isalnum (the_text.buf[the_cursor]))
232 	    ++the_cursor;
233 	  --n;
234 	}
235       io_move_cursor ();
236     }
237 }
238 
239 
240 static void
erase(int len)241 erase (int len)
242 {
243   if (check_editting_mode ())
244     return;
245   else
246     {
247       strcpy (&the_text.buf[the_cursor],
248 	      &the_text.buf[the_cursor + len]);
249       io_erase (len);
250     }
251 }
252 
253 
254 void
backward_delete_char(int n)255 backward_delete_char (int n)
256 {
257   if (check_editting_mode ())
258     return;
259   if (n < 0)
260     delete_char (-n);
261   else
262     {
263       char * error = 0;
264       if (the_cursor < n)
265 	{
266 	  error = "Beginning of buffer.";
267 	  n = the_cursor;
268 	}
269       the_cursor -= n;
270       erase (n);
271       if (error)
272 	io_error_msg (error);	/* Doesn't return. */
273     }
274 }
275 
276 
277 void
backward_delete_word(int n)278 backward_delete_word (int n)
279 {
280   if (check_editting_mode ())
281     return;
282   else
283     {
284       int at = the_cursor;
285       while (n)
286 	{
287 	  while (the_cursor
288 		 && !isalnum (the_text.buf[the_cursor]))
289 	    --the_cursor;
290 
291 	  while (the_cursor
292 		 && isalnum (the_text.buf[the_cursor - 1]))
293 	    --the_cursor;
294 	  --n;
295 	}
296       erase (at - the_cursor);
297     }
298 }
299 
300 
301 void
delete_to_start(void)302 delete_to_start(void)
303 {
304   if (check_editting_mode ())
305     return;
306   else
307     {
308       int at = the_cursor;
309       the_cursor = 0;
310       erase (at);
311     }
312 }
313 
314 
315 void
delete_char(int n)316 delete_char (int n)
317 {
318   if (check_editting_mode ())
319     return;
320   if (n < 0)
321     backward_delete_char (-n);
322   else
323     {
324       char * error = 0;
325       int len = strlen (the_text.buf);
326       if (the_cursor + n > len)
327 	{
328 	  error = "End of buffer.";
329 	  n = len - the_cursor;
330 	}
331       erase (n);
332       if (error)
333 	io_error_msg (error);	/* Doesn't return. */
334     }
335 }
336 
337 void
delete_word(int n)338 delete_word (int n)
339 {
340   if (check_editting_mode ())
341     return;
342   if (n < 0)
343     backward_delete_word (-n);
344   else
345     {
346       int len = strlen (the_text.buf);
347       int erase_len = 0;
348       while (n)
349 	{
350 	  while (((the_cursor + erase_len) < len)
351 		 && !isalnum (the_text.buf[(the_cursor + erase_len)]))
352 	    ++erase_len;
353 	  while (((the_cursor + erase_len) < len)
354 		 && isalnum (the_text.buf[(the_cursor + erase_len)]))
355 	    ++erase_len;
356 	  --n;
357 	}
358       erase (erase_len);
359     }
360 }
361 
362 
363 void
kill_line(void)364 kill_line(void)
365 {
366   if (check_editting_mode ())
367     return;
368   else
369     {
370       int len = strlen (the_text.buf);
371       erase (len - the_cursor);
372     }
373 }
374 
375 void
insert_string(char * str,int len)376 insert_string (char * str, int len)
377 {
378   if (check_editting_mode ())
379     return;
380   splicen_line (&the_text, str, len, the_cursor);
381   io_insert (len);
382   the_cursor += len;
383 }
384 
385 void
over_string(char * str,int len)386 over_string (char * str, int len)
387 {
388   if (check_editting_mode ())
389     return;
390   if (the_cursor + len > strlen (the_text.buf))
391     {
392       catn_line (&the_text, str + the_text.alloc - the_cursor,
393 		 len - (the_text.alloc - the_cursor));
394       len = the_text.alloc - the_cursor;
395     }
396   if (len)
397     bcopy (str, the_text.buf + the_cursor, len);
398   io_over (str, len);
399   the_cursor += len;
400 }
401 
402 void
put_string(char * str,int len)403 put_string (char * str, int len)
404 {
405   if (check_editting_mode ())
406     return;
407   (the_overwrite ? over_string : insert_string) (str, len);
408 }
409 
410 /* Higher Level editting commands. */
411 
412 void
insert_cell_expression(void)413 insert_cell_expression (void)
414 {
415   if (check_editting_mode ())
416     return;
417   else
418     {
419       CELL *cp;
420       char * in_str;
421       if (!(cp = find_cell (curow, cucol)))
422 	return;
423       in_str = decomp (curow, cucol, cp);
424       put_string (in_str, strlen(in_str));
425       decomp_free ();
426     }
427 }
428 
429 
430 void
insert_other_cell_expression(struct rng * rng)431 insert_other_cell_expression (struct rng * rng)
432 {
433   if (check_editting_mode ())
434     return;
435   else
436     {
437       CELL *cp;
438       char * in_str;
439       if (!(cp = find_cell (rng->lr, rng->lc)))
440         return;
441       in_str = decomp (rng->lr, rng->lc, cp);
442       put_string (in_str, strlen(in_str));
443       decomp_free ();
444     }
445 }
446 
447 /* No quotes are provided here, because it's easier to add
448  * quotes at the end of a macro than to strip them in the
449  * middle of one.
450  * --FB 1997.12.28
451  */
452 void
insert_cell_value(void)453 insert_cell_value(void)
454 {
455   if (check_editting_mode ())
456     return;
457   else
458     {
459       char * in_str;
460       in_str = cell_value_string (curow, cucol, 0);
461       put_string (in_str, strlen(in_str));
462     }
463 }
464 
465 /* Ditto.
466  * --FB 1997.12.28
467  */
468 
469 void
insert_other_cell_value(struct rng * rng)470 insert_other_cell_value(struct rng * rng)
471 {
472   if (check_editting_mode ())
473     return;
474   else
475     {
476       char * in_str;
477       in_str = cell_value_string (rng->lr, rng->lc, 0);
478       put_string (in_str, strlen(in_str));
479     }
480 }
481 
482 void
insert_rel_ref(void)483 insert_rel_ref(void)
484 {
485   if (check_editting_mode ())
486     return;
487   else
488     {
489       char vbuf[50];
490       char * in_str;
491       if (Global->a0)
492 	{
493 	  if (mkrow != NON_ROW)
494 	    {
495 	      struct rng r;
496 	      set_rng (&r, curow, cucol, mkrow, mkcol);
497 	      in_str = range_name (&r);
498 	    }
499 	  else
500 	    in_str = cell_name (curow, cucol);
501 	}
502       else
503 	{
504 	  if (mkrow != NON_ROW)
505 	    {
506 	      switch (((curow == setrow) << 3)
507 		      + ((mkrow == setrow) << 2)
508 		      + ((cucol == setcol) << 1)
509 		      + (mkcol == setcol))
510 		{
511 		case 0:
512 		case 1:
513 		case 2:
514 		case 4:
515 		case 5:
516 		case 6:
517 		case 8:
518 		case 9:
519 		case 10:
520 		  sprintf (vbuf, "r[%+d:%+d]c[%+d:%+d]",
521 			   (curow < mkrow ? curow : mkrow) - setrow,
522 			   (curow < mkrow ? mkrow : curow) - setrow,
523 			   (cucol < mkcol ? cucol : mkcol) - setcol,
524 			   (cucol < mkcol ? mkcol : cucol) - setcol);
525 		  break;
526 
527 		case 3:
528 		case 7:
529 		case 11:
530 		  sprintf (vbuf, "r[%+d:%+d]c",
531 			   (curow < mkrow ? curow : mkrow) - setrow,
532 			   (curow < mkrow ? mkrow : curow) - setrow);
533 		  break;
534 
535 		case 12:
536 		case 14:
537 		case 13:
538 		  sprintf (vbuf, "rc[%+d:%+d]",
539 			   (cucol < mkcol ? cucol : mkcol) - setcol,
540 			   (cucol < mkcol ? mkcol : cucol) - setcol);
541 		  break;
542 
543 		case 15:
544 		  strcpy (vbuf, "rc");
545 		  break;
546 		}
547 	    }
548 	  else
549 	    {
550 	      switch (((curow == setrow) << 1) + (cucol == setcol))
551 		{
552 		case 0:
553 		  sprintf (vbuf, "r[%+d]c[%+d]", curow - setrow, cucol - setcol);
554 		  break;
555 		case 1:
556 		  sprintf (vbuf, "r[%+d]c", curow - setrow);
557 		  break;
558 		case 2:
559 		  sprintf (vbuf, "rc[%+d]", cucol - setcol);
560 		  break;
561 		case 3:
562 		  strcpy (vbuf, "rc");
563 		  break;
564 #ifdef TEST
565 		default:
566 		  panic ("huh what");
567 #endif
568 		}
569 	    }
570 	  in_str = vbuf;
571 	}
572       put_string (in_str, strlen (in_str));
573     }
574 }
575 
576 
577 void
insert_abs_ref(int x)578 insert_abs_ref(int x)
579 {
580   if (check_editting_mode ())
581     return;
582   else
583     {
584       char vbuf[50];
585       char * in_str;
586       CELLREF mr = mkrow;
587       CELLREF mc = mkcol;
588 /* Insert current cell/range name as an absolute reference
589  * but if argument x is 1, insert current cell address,
590  * leaving out mark information.
591  */
592       if (x)
593         {
594           mr = curow;
595           mc = cucol;
596         }
597       if (Global->a0)
598 	{
599 	  if (mr != NON_ROW)
600 	    sprintf (vbuf, "$%s$%u:$%s:$%u",
601 		     col_to_str (cucol), curow, col_to_str (mc), mr) ;
602 	  else
603 	    sprintf (vbuf, "$%s$%u", col_to_str (cucol), curow);
604 	  in_str = vbuf;
605 	}
606       else
607 	{
608 	  if (mr != NON_ROW)
609 	    {
610 	      struct rng r;
611 
612 	      set_rng (&r, curow, cucol, mr, mc);
613 	      in_str = range_name (&r);
614 	    }
615 	  else
616 	    in_str = cell_name (curow, cucol);
617 	}
618       put_string (in_str, strlen (in_str));
619     }
620 }
621 
622 void
insert_cell_attr(struct rng * rng,char * attr)623 insert_cell_attr (struct rng * rng, char * attr)
624 {
625   struct line line;
626   init_line (&line);
627   if (!stricmp (attr, "width"))
628     {
629       int wid = get_nodef_width (rng->lc);
630       if (wid == 0)
631 	set_line (&line, "def");
632       else
633 	sprint_line (&line, "%d", wid - 1);
634     }
635   else if (!stricmp (attr, "height"))
636     {
637       int hgt = get_nodef_height (rng->lr);
638       if (hgt == 0)
639 	set_line (&line, "def");
640       else
641 	sprint_line (&line, "%d", hgt - 1);
642     }
643   else if (!stricmp (attr, "format"))
644     {
645       CELL * cp = find_cell (rng->lr, rng->lc);
646       if (!cp)
647 	set_line (&line, "def");
648       else
649 	{
650 	  set_line(&line, cell_format_string(cp));
651 	}
652     }
653   else if (!stricmp (attr, "font"))
654     {
655       CELL * cp = find_cell (rng->lr, rng->lc);
656       if (!(cp && cp->cell_font))
657 	set_line (&line, "def");
658       else
659 	set_line (&line, cp->cell_font->names->oleo_name);
660     }
661   else if (!stricmp (attr, "font-scale"))
662     {
663       CELL * cp = find_cell (rng->lr, rng->lc);
664       if (!(cp && cp->cell_font))
665 	set_line (&line, "1.0");
666       else
667 	sprint_line (&line, "%lf", cp->cell_font->scale);
668     }
669   put_string (line.buf, strlen (line.buf));
670 }
671 
672 void
insert_usr_fmt_part(int fmt,int stat)673 insert_usr_fmt_part (int fmt, int stat)
674 {
675   char * usr_stats[9];
676   if ((fmt < 1) || (fmt > 16))
677     io_error_msg
678       ("insert-user-format-part arg 1 out of range (%d); should be in [1-16].",
679        fmt);
680   --fmt;
681   if ((stat < 1) || (stat > 16))
682     io_error_msg
683       ("insert-user-format-part arg 2 out of range (%d); should be in [1-9].",
684        stat);
685   --stat;
686   get_usr_stats (fmt, usr_stats);
687   put_string (usr_stats[stat], strlen (usr_stats[stat]));
688 }
689 
690 void
self_insert_command(int ch,int count)691 self_insert_command (int ch, int count)
692 {
693   if (check_editting_mode ())
694     return;
695   else if (count == 1)
696     {
697       char chr = ch;
698       put_string (&chr, 1);
699     }
700   else if (count > 0)
701     {
702       char * buf = (char *)ck_malloc (count); /* sleazy, huh? */
703       int x;
704       for (x = 0; x < count; ++x)
705 	buf[x] = ch;
706       put_string (buf, count);
707     }
708 }
709 
710 
711 /* Keysequences are read using the `keyseq' keymap.
712  * Every key in that map should be bound to this function.
713  */
714 void
self_map_command(int c)715 self_map_command (int c)
716 {
717   struct keymap * map = the_maps[the_cmd_arg.val.key.cmd.code];
718   char space = ' ';
719   char * str = char_to_string (c);
720 
721   insert_string (str, strlen (str));
722   insert_string (&space, 1);
723 
724   while (map)
725     {
726       the_cmd_arg.val.key.cmd = map->keys[c];
727       if (the_cmd_arg.val.key.cmd.vector < 0)
728 	{
729 	  if (the_cmd_arg.val.key.cmd.code < 0)
730 	    map = map->map_next;
731 	  else
732 	    return;
733 	}
734       else
735 	break;
736     }
737   exit_minibuffer ();
738   return;
739 }
740 
741 void
insert_current_filename(void)742 insert_current_filename (void)
743 {
744   if (FileGetCurrentFileName())
745     put_string(FileGetCurrentFileName(), strlen (FileGetCurrentFileName()));
746 }
747 
748 
749 /* Reading a single character is done with the read-char
750  * map.  Every key in that map should be bound to this function.
751  */
752 void
exit_self_inserting(int c)753 exit_self_inserting (int c)
754 {
755   char * str = char_to_string (c);
756 
757   insert_string (str, strlen (str));
758   exit_minibuffer ();
759 }
760 
761 
762 static int
issymb(int c)763 issymb (int c)
764 {
765   return isalpha (c) || isdigit (c) || (c == '_');
766 }
767 
768 #undef the_text
769 #undef the_cursor
770 #undef the_do_prompt
771 void
insert_context_word(void)772 insert_context_word (void)
773 {
774   struct command_frame * cf = the_cmd_frame->prev;
775   if (   (cf == the_cmd_frame)
776       || !cf->cmd
777       || !cf->argv [cf->_cur_arg].do_prompt)
778     return;
779   {
780     struct command_arg * ca = &cf->argv [cf->_cur_arg];
781     char * beg_text = ca->text.buf;
782     char * last = beg_text + ca->cursor;
783     char * start;
784 
785     while ((last > beg_text) && !issymb(*last))
786       --last;
787     while (*last && issymb (*last))
788       ++last;
789     --last;
790     start = last;
791     while ((start > beg_text) && issymb(*start))
792       --start;
793     if (!issymb (*start) && (start < last))
794       ++start;
795 
796     if ((start <= last) && issymb (*start))
797       {
798 	insert_string (start, last - start + 1);
799 	the_cmd_arg.cursor = 0;
800       }
801   }
802 }
803