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