blob: ce31f4241b81e7fb845f52dd147404f2500a8f16 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
5 * Copyright (C) 1999 Chris Allegretta *
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 1, 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 program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <signal.h>
26#include <unistd.h>
27#include <string.h>
28#include <fcntl.h>
29#include <sys/stat.h>
30#include <sys/ioctl.h>
31#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000032#include <sys/types.h>
33#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000034#include <errno.h>
35#include <ctype.h>
36#include <locale.h>
37#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000038#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000039
40#include "config.h"
41#include "proto.h"
42#include "nano.h"
43
44#ifndef NANO_SMALL
45#include <libintl.h>
46#define _(string) gettext(string)
47#else
48#define _(string) (string)
49#endif
50
51#ifdef HAVE_TERMIOS_H
52#include <termios.h>
53#endif
54
55#ifdef HAVE_TERMIO_H
56#include <termio.h>
57#endif
58
59#ifdef HAVE_GETOPT_H
60#include <getopt.h>
61#endif
62
63/* Former globals, now static */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000064int fill = 0; /* Fill - where to wrap lines, basically */
65static char *alt_speller; /* Alternative spell command */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000066struct termios oldterm; /* The user's original term settings */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000067static char *help_text_init = "";
68 /* Initial message, not including shortcuts */
Chris Allegretta18f8be02000-09-04 03:20:38 +000069static struct sigaction act; /* For all out fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070
Chris Allegretta27eb13f2000-11-05 16:52:21 +000071char *last_search = NULL; /* Last string we searched for */
72char *last_replace = NULL; /* Last replacement string */
73int search_last_line; /* Is this the last search line? */
74
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +000075void keypad_on(int yesno)
76{
77 keypad(edit, yesno);
78 keypad(bottomwin, yesno);
79}
80
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000081/* What we do when we're all set to exit */
82RETSIGTYPE finish(int sigage)
83{
84 if (!ISSET(NO_HELP)) {
85 mvwaddstr(bottomwin, 1, 0, hblank);
86 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000087 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +000089
90 /* Apparently you REALLY can't get away with not calling keypad()
91 or your window looks awful when it exits. so we just call it right
92 before we exit, muhaha :-) */
93 keypad_on(TRUE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094 wrefresh(bottomwin);
95 endwin();
96
97 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000098 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099
100 exit(sigage);
101}
102
103/* Die (gracefully?) */
104void die(char *msg, ...)
105{
106 va_list ap;
107
108 va_start(ap, msg);
109 vfprintf(stderr, msg, ap);
110 va_end(ap);
111
112 /* if we can't save we have REAL bad problems,
Robert Siemborskifcf32bf2000-07-17 03:04:54 +0000113 * but we might as well TRY. */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000114 if (filename[0] == '\0') {
Robert Siemborskifcf32bf2000-07-17 03:04:54 +0000115 write_file("nano.save", 0);
116 } else {
117 char buf[BUFSIZ];
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000118 strncpy(buf, filename, BUFSIZ);
119 strncat(buf, ".save", BUFSIZ - strlen(buf));
Robert Siemborskifcf32bf2000-07-17 03:04:54 +0000120 write_file(buf, 0);
121 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000122 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000123 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000124
125 clear();
126 refresh();
127 resetty();
128 endwin();
129
130 fprintf(stderr, msg);
131 fprintf(stderr, _("\nBuffer written to 'nano.save'\n"));
132
133 exit(1); /* We have a problem: exit w/ errorlevel(1) */
134}
135
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000136void print_view_warning(void)
137{
138 statusbar(_("Key illegal in VIEW mode"));
139}
140
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +0000141
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000142/* Initialize global variables - no better way for now */
143void global_init(void)
144{
145 int i;
146
147 center_x = COLS / 2;
148 center_y = LINES / 2;
149 current_x = 0;
150 current_y = 0;
151 editwinrows = LINES - 5 + no_help();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000152 fileage = NULL;
153 cutbuffer = NULL;
154 current = NULL;
155 edittop = NULL;
156 editbot = NULL;
157 totlines = 0;
158 placewewant = 0;
159 if (!fill)
160 fill = COLS - 8;
161 hblank = nmalloc(COLS + 1);
162
163 /* Thanks BG for this bit... */
164 for (i = 0; i <= COLS - 1; i++)
165 hblank[i] = ' ';
166 hblank[i] = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000167}
168
169void init_help_msg(void)
170{
171
172#ifndef NANO_SMALL
173
174 help_text_init =
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000175 _(" nano help text\n\n "
176 "The nano editor is designed to emulate the functionality and "
177 "ease-of-use of the UW Pico text editor. There are four main "
178 "sections of the editor: The top line shows the program "
179 "version, the current filename being edited, and whether "
180 "or not the file has been modified. Next is the main editor "
181 "window showing the file being edited. The status line is "
182 "the third line from the bottom and shows important messages. "
183 "The bottom two lines show the most commonly used shortcuts "
184 "in the editor.\n\n "
185 "The notation for shortcuts is as follows: Control-key "
Chris Allegrettae49f1232000-09-02 07:20:39 +0000186 "sequences are notated with a caret (^) symbol and are entered "
Chris Allegrettad56bd792000-09-02 07:27:10 +0000187 "with the Control (Ctrl) key. Escape-key sequences are notated "
188 "with the Meta (M) symbol and can be entered using either the "
189 "Esc, Alt or Meta key depending on your keyboard setup. The "
190 "following keystrokes are available in the main editor window. "
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000191 "Optional keys are shown in parentheses:\n\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192#endif
193
194}
195
196/* Make a copy of a node to a pointer (space will be malloc()ed) */
197filestruct *copy_node(filestruct * src)
198{
199 filestruct *dst;
200
201 dst = nmalloc(sizeof(filestruct));
202 dst->data = nmalloc(strlen(src->data) + 1);
203
204 dst->next = src->next;
205 dst->prev = src->prev;
206
207 strcpy(dst->data, src->data);
208 dst->lineno = src->lineno;
209
210 return dst;
211}
212
213/* Unlink a node from the rest of the struct */
214void unlink_node(filestruct * fileptr)
215{
216 if (fileptr->prev != NULL)
217 fileptr->prev->next = fileptr->next;
218
219 if (fileptr->next != NULL)
220 fileptr->next->prev = fileptr->prev;
221}
222
223void delete_node(filestruct * fileptr)
224{
225 if (fileptr->data != NULL)
226 free(fileptr->data);
227 free(fileptr);
228}
229
230/* Okay, now let's duplicate a whole struct! */
231filestruct *copy_filestruct(filestruct * src)
232{
233 filestruct *dst, *tmp, *head, *prev;
234
235 head = copy_node(src);
236 dst = head; /* Else we barf on copying just one line */
237 head->prev = NULL;
238 tmp = src->next;
239 prev = head;
240
241 while (tmp != NULL) {
242 dst = copy_node(tmp);
243 dst->prev = prev;
244 prev->next = dst;
245
246 prev = dst;
247 tmp = tmp->next;
248 }
249
250 dst->next = NULL;
251 return head;
252}
253
254/* Free() a single node */
255int free_node(filestruct * src)
256{
257 if (src == NULL)
258 return 0;
259
260 if (src->next != NULL)
261 free(src->data);
262 free(src);
263 return 1;
264}
265
266int free_filestruct(filestruct * src)
267{
268 filestruct *fileptr = src;
269
270 if (src == NULL)
271 return 0;
272
273 while (fileptr->next != NULL) {
274 fileptr = fileptr->next;
275 free_node(fileptr->prev);
276
277#ifdef DEBUG
278 fprintf(stderr, _("free_node(): free'd a node, YAY!\n"));
279#endif
280 }
281 free_node(fileptr);
282#ifdef DEBUG
283 fprintf(stderr, _("free_node(): free'd last node.\n"));
284#endif
285
286 return 1;
287}
288
289int renumber_all(void)
290{
291 filestruct *temp;
292 long i = 1;
293
294 for (temp = fileage; temp != NULL; temp = temp->next) {
295 temp->lineno = i++;
296 }
297
298 return 0;
299}
300
301int renumber(filestruct * fileptr)
302{
303 filestruct *temp;
304
305 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage) {
306 renumber_all();
307 return 0;
308 }
309 for (temp = fileptr; temp != NULL; temp = temp->next) {
310 temp->lineno = temp->prev->lineno + 1;
311 }
312
313 return 0;
314}
315
316/* Fix the memory allocation for a string */
317void align(char **strp)
318{
319 /* There was a serious bug here: the new address was never
320 stored anywhere... */
321
322 *strp = nrealloc(*strp, strlen(*strp) + 1);
323}
324
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000325/* Null a string at a certain index and align it */
326void null_at(char *data, int index)
327{
328 data[index] = 0;
329 align(&data);
330}
331
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000332void usage(void)
333{
334#ifdef HAVE_GETOPT_LONG
335 printf(_("Usage: nano [GNU long option] [option] +LINE <file>\n\n"));
336 printf(_("Option Long option Meaning\n"));
Chris Allegretta6724a7e2000-06-19 23:19:07 +0000337 printf(_
338 (" -T --tabsize=[num] Set width of a tab to num\n"));
Chris Allegretta805c26d2000-09-06 13:39:17 +0000339#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000340 printf(_
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000341 (" -R --regexp Use regular expressions for search\n"));
Chris Allegretta47805612000-07-07 02:35:34 +0000342#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000343 printf
344 (_
345 (" -V --version Print version information and exit\n"));
346 printf(_
347 (" -c --const Constantly show cursor position\n"));
348 printf(_
349 (" -h --help Show this message\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000350#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000351 printf(_
Chris Allegretta627de192000-07-12 02:09:17 +0000352 (" -k --cut Let ^K cut from cursor to end of line\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000353#endif
Chris Allegretta627de192000-07-12 02:09:17 +0000354 printf(_
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000355 (" -i --autoindent Automatically indent new lines\n"));
356 printf(_
Chris Allegretta71348ee2000-10-02 04:21:23 +0000357 (" -l --nofollow Don't follow symbolic links, overwrite\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000358#ifndef NANO_SMALL
359#ifdef NCURSES_MOUSE_VERSION
360 printf(_(" -m --mouse Enable mouse\n"));
361#endif
362#endif
363 printf
364 (_
365 (" -r [#cols] --fill=[#cols] Set fill cols to (wrap lines at) #cols\n"));
366 printf(_
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000367 (" -p --pico Emulate Pico as closely as possible\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000368 printf(_
369 (" -s [prog] --speller=[prog] Enable alternate speller\n"));
370 printf(_
371 (" -t --tempfile Auto save on exit, don't prompt\n"));
372 printf(_
373 (" -v --view View (read only) mode\n"));
374 printf(_
375 (" -w --nowrap Don't wrap long lines\n"));
376 printf(_
377 (" -x --nohelp Don't show help window\n"));
378 printf(_
379 (" -z --suspend Enable suspend\n"));
380 printf(_
381 (" +LINE Start at line number LINE\n"));
382#else
383 printf(_("Usage: nano [option] +LINE <file>\n\n"));
384 printf(_("Option Meaning\n"));
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000385 printf(_(" -T [num] Set width of a tab to num\n"));
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000386 printf(_(" -R Use regular expressions for search\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000387 printf(_(" -V Print version information and exit\n"));
388 printf(_(" -c Constantly show cursor position\n"));
389 printf(_(" -h Show this message\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000390#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +0000391 printf(_(" -k Let ^K cut from cursor to end of line\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000392#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000393 printf(_(" -i Automatically indent new lines\n"));
394 printf(_
Chris Allegretta71348ee2000-10-02 04:21:23 +0000395 (" -l Don't follow symbolic links, overwrite\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000396#ifndef NANO_SMALL
397#ifdef NCURSES_MOUSE_VERSION
398 printf(_(" -m Enable mouse\n"));
399#endif
400#endif
401 printf(_
402 (" -r [#cols] Set fill cols to (wrap lines at) #cols\n"));
403 printf(_(" -s [prog] Enable alternate speller\n"));
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +0000404 printf(_(" -p Emulate Pico as closely as possible\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000405 printf(_(" -t Auto save on exit, don't prompt\n"));
406 printf(_(" -v View (read only) mode\n"));
407 printf(_(" -w Don't wrap long lines\n"));
408 printf(_(" -x Don't show help window\n"));
409 printf(_(" -z Enable suspend\n"));
410 printf(_(" +LINE Start at line number LINE\n"));
411#endif
412 exit(0);
413}
414
415void version(void)
416{
417 printf(_(" nano version %s by Chris Allegretta (compiled %s, %s)\n"),
418 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000419 printf(_
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000420 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000421 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000422
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000423#ifdef NANO_SMALL
424 printf(" --enable-tiny");
425#endif
426#ifdef NANO_EXTRA
427 printf(" --enable-extra");
428#endif
429#ifdef DISABLE_TABCOMP
430 printf(" --disable-tabcomp");
431#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000432#ifdef DISABLE_JUSTIFY
433 printf(" --disable-justify");
434#endif
435#ifdef DISABLE_SPELL
436 printf(" --disable-spell");
437#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000438#ifdef USE_SLANG
439 printf(" --with-slang");
440#endif
441 printf("\n");
442
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000443}
444
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000445filestruct *make_new_node(filestruct * prevnode)
446{
447 filestruct *newnode;
448
449 newnode = nmalloc(sizeof(filestruct));
450 newnode->data = NULL;
451
452 newnode->prev = prevnode;
453 newnode->next = NULL;
454
455 if (prevnode != NULL)
456 newnode->lineno = prevnode->lineno + 1;
457
458 return newnode;
459}
460
Chris Allegretta7975ed82000-07-28 00:58:35 +0000461/* Splice a node into an existing filestruct */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000462void splice_node(filestruct * begin, filestruct * new, filestruct * end)
Chris Allegretta7975ed82000-07-28 00:58:35 +0000463{
464 new->next = end;
465 new->prev = begin;
466 begin->next = new;
467 if (end != NULL)
468 end->prev = new;
469}
470
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000471int do_mark()
472{
473#ifdef NANO_SMALL
474 nano_small_msg();
475#else
476 if (!ISSET(MARK_ISSET)) {
477 statusbar(_("Mark Set"));
478 SET(MARK_ISSET);
479 mark_beginbuf = current;
480 mark_beginx = current_x;
481 } else {
482 statusbar(_("Mark UNset"));
483 UNSET(MARK_ISSET);
484 mark_beginbuf = NULL;
485 mark_beginx = 0;
486
487 edit_refresh();
488 }
489#endif
490 return 1;
491}
492
493int no_help(void)
494{
495 if ISSET
496 (NO_HELP)
497 return 2;
498 else
499 return 0;
500}
501
502void nano_small_msg(void)
503{
504 statusbar("Sorry, this function not available with nano-tiny option");
505}
506
Chris Allegrettaff269f82000-12-01 18:46:01 +0000507void nano_disabled_msg(void)
508{
509 statusbar("Sorry, support for this function has been disabled");
510}
511
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000512/* The user typed a printable character; add it to the edit buffer */
513void do_char(char ch)
514{
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000515 /* magic-line: when a character is inserted on the current magic line,
516 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000517 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000518 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000519 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000520 }
521
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000522 /* More dangerousness fun =) */
523 current->data = nrealloc(current->data, strlen(current->data) + 2);
524 memmove(&current->data[current_x + 1],
525 &current->data[current_x],
526 strlen(current->data) - current_x + 1);
527 current->data[current_x] = ch;
528 do_right();
529
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000530 if (!ISSET(NO_WRAP) && (ch != '\t'))
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000531 check_wrap(current, ch);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000532 set_modified();
533 check_statblank();
534 UNSET(KEEP_CUTBUFFER);
535 totsize++;
536
537}
538
539/* Someone hits return *gasp!* */
540int do_enter(filestruct * inptr)
541{
542 filestruct *new;
543 char *tmp, *spc;
544 int extra = 0;
545
546 new = make_new_node(inptr);
547 tmp = &current->data[current_x];
548 current_x = 0;
549
550 /* Do auto-indenting, like the neolithic Turbo Pascal editor */
551 if (ISSET(AUTOINDENT)) {
552 spc = current->data;
553 if (spc) {
554 while ((*spc == ' ') || (*spc == '\t')) {
555 extra++;
556 spc++;
557 current_x++;
558 }
559 new->data = nmalloc(strlen(tmp) + extra + 1);
560 strncpy(new->data, current->data, extra);
561 strcpy(&new->data[extra], tmp);
562 }
563 } else {
564 new->data = nmalloc(strlen(tmp) + 1);
565 strcpy(new->data, tmp);
566 }
567 *tmp = 0;
568
Chris Allegrettada721be2000-07-31 01:26:42 +0000569 if (inptr->next == NULL) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000570 filebot = new;
571 editbot = new;
572 }
Chris Allegretta7975ed82000-07-28 00:58:35 +0000573 splice_node(inptr, new, inptr->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574
575 totsize++;
576 renumber(current);
577 current = new;
578 align(&current->data);
579
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000580 /* The logic here is as follows:
581 * -> If we are at the bottom of the buffer, we want to recenter
582 * (read: rebuild) the screen and forcably move the cursor.
583 * -> otherwise, we want simply to redraw the screen and update
584 * where we think the cursor is.
585 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586 if (current_y == editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +0000587 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000588 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000589 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000591 edit_refresh();
592 update_cursor();
593 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594
595 totlines++;
596 set_modified();
597
Chris Allegrettab0ae3932000-06-15 23:39:14 +0000598 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000599 return 1;
600}
601
602int do_enter_void(void)
603{
604 return do_enter(current);
605}
606
607void do_next_word(void)
608{
609 filestruct *fileptr;
610 int i;
611
612 if (current == NULL)
613 return;
614
615 i = current_x;
616 for (fileptr = current; fileptr != NULL; fileptr = fileptr->next) {
617 if (fileptr == current) {
618 while (isalnum((int) fileptr->data[i])
619 && fileptr->data[i] != 0)
620 i++;
621
622 if (fileptr->data[i] == 0) {
623 i = 0;
624 continue;
625 }
626 }
627 while (!isalnum((int) fileptr->data[i]) && fileptr->data[i] != 0)
628 i++;
629
630 if (fileptr->data[i] != 0)
631 break;
632
633 i = 0;
634 }
635 if (fileptr == NULL)
636 current = filebot;
637 else
638 current = fileptr;
639
640 current_x = i;
641 placewewant = xplustabs();
642 if (current->lineno >= editbot->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000643 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000644
645}
646
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000647void do_wrap(filestruct * inptr, char input_char)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000648{
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000649 int i = 0; /* Index into ->data for line. */
650 int i_tabs = 0; /* Screen position of ->data[i]. */
651 int last_word_end = -1; /* Location of end of last word found. */
652 int current_word_start = -1; /* Location of start of current word. */
653 int current_word_start_t = -1; /* Location of start of current word screen position. */
654 int current_word_end = -1; /* Location of end of current word */
655 int current_word_end_t = -1; /* Location of end of current word screen position. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000656 int len = strlen(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000657
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000658 int down = 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000659 int right = 0;
660 struct filestruct *temp = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000661
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000662 assert(strlenpt(inptr->data) > fill);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000663
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000664 for (i = 0, i_tabs = 0; i < len; i++, i_tabs++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000665 if (!isspace((int) inptr->data[i])) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000666 last_word_end = current_word_end;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000667
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000668 current_word_start = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000669 current_word_start_t = i_tabs;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000670
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000671 while (!isspace((int) inptr->data[i])
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000672 && inptr->data[i]) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000673 i++;
674 i_tabs++;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000675 if (inptr->data[i] < 32)
676 i_tabs++;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000677 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000678
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000679 if (inptr->data[i]) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000680 current_word_end = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000681 current_word_end_t = i_tabs;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000682 } else {
683 current_word_end = i - 1;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000684 current_word_end_t = i_tabs - 1;
685 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000686 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000687
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000688 if (inptr->data[i] == NANO_CONTROL_I) {
Chris Allegretta6d690a32000-08-03 22:51:21 +0000689 if (i_tabs % tabsize != 0);
690 i_tabs += tabsize - (i_tabs % tabsize);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000691 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000692
Adam Rogoyski09f97962000-06-20 02:50:33 +0000693 if (current_word_end_t > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000694 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000695 }
696
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000697 /* There are a few (ever changing) cases of what the line could look like.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000698 * 1) only one word on the line before wrap point.
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000699 * a) one word takes up the whole line with no starting spaces.
700 * - do nothing and return.
701 * b) cursor is on word or before word at wrap point and there are spaces at beginning.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000702 * - word starts new line.
703 * - keep white space on original line up to the cursor.
704 * *) cursor is after word at wrap point
705 * - either it's all white space after word, and this routine isn't called.
706 * - or we are actually in case 2 (2 words).
707 * 2) Two or more words on the line before wrap point.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000708 * a) cursor is at a word or space before wrap point
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000709 * - word at wrap point starts a new line.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000710 * - white space at end of original line is cleared, unless
711 * it is all spaces between previous word and next word which appears after fill.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000712 * b) cursor is at the word at the wrap point.
713 * - word at wrap point starts a new line.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000714 * 1. pressed a space and at first character of wrap point word.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000715 * - white space on original line is kept to where cursor was.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000716 * 2. pressed non space (or space elsewhere).
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000717 * - white space at end of original line is cleared.
718 * c) cursor is past the word at the wrap point.
719 * - word at wrap point starts a new line.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000720 * - white space at end of original line is cleared
721 */
722
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000723 temp = nmalloc(sizeof(filestruct));
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000724
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000725 /* Category 1a: one word taking up the whole line with no beginning spaces. */
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000726 if ((last_word_end == -1) && (!isspace((int) inptr->data[0]))) {
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000727 for (i = current_word_end; i < len; i++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000728 if (!isspace((int) inptr->data[i]) && i < len) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000729 current_word_start = i;
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000730 while (!isspace((int) inptr->data[i]) && (i < len)) {
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000731 i++;
732 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000733 last_word_end = current_word_end;
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000734 current_word_end = i;
735 break;
736 }
737 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000738
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000739 if (last_word_end == -1) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000740 free(temp);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000741 return;
742 }
743 if (current_x >= last_word_end) {
744 right = (current_x - current_word_start) + 1;
745 current_x = last_word_end;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000746 down = 1;
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000747 }
748
749 temp->data = nmalloc(strlen(&inptr->data[current_word_start]) + 1);
750 strcpy(temp->data, &inptr->data[current_word_start]);
751 inptr->data = nrealloc(inptr->data, last_word_end + 2);
752 inptr->data[last_word_end + 1] = 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000753 } else
754 /* Category 1b: one word on the line and word not taking up whole line
755 (i.e. there are spaces at the beginning of the line) */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000756 if (last_word_end == -1) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000757 temp->data = nmalloc(strlen(&inptr->data[current_word_start]) + 1);
758 strcpy(temp->data, &inptr->data[current_word_start]);
759
760 /* Inside word, remove it from original, and move cursor to right spot. */
761 if (current_x >= current_word_start) {
762 right = current_x - current_word_start;
763 current_x = 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000764 down = 1;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000765 }
766
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000767 null_at(inptr->data, current_x);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000768
769 if (ISSET(MARK_ISSET) && (mark_beginbuf == inptr)) {
770 mark_beginbuf = temp;
771 mark_beginx = 0;
772 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000773 }
774
775 /* Category 2: two or more words on the line. */
776 else {
777
778 /* Case 2a: cursor before word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000779 if (current_x < current_word_start) {
780 temp->data =
781 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
782 strcpy(temp->data, &inptr->data[current_word_start]);
783
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000784 if (!isspace((int) input_char)) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000785 i = current_word_start - 1;
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000786 while (isspace((int) inptr->data[i])) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000787 i--;
788 assert(i >= 0);
789 }
790 } else if (current_x <= last_word_end)
791 i = last_word_end - 1;
792 else
793 i = current_x;
794
795 inptr->data = nrealloc(inptr->data, i + 2);
796 inptr->data[i + 1] = 0;
797 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000798
799
800 /* Case 2b: cursor at word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000801 else if ((current_x >= current_word_start)
802 && (current_x <= (current_word_end + 1))) {
803 temp->data =
804 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000805 strcpy(temp->data, &inptr->data[current_word_start]);
806
807 down = 1;
808
809 right = current_x - current_word_start;
810 i = current_word_start - 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000811 if (isspace((int) input_char)
812 && (current_x == current_word_start)) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000813 current_x = current_word_start;
814
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000815 null_at(inptr->data, current_word_start);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000816 } else {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000817
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000818 while (isspace((int) inptr->data[i])) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000819 i--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000820 assert(i >= 0);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000821 }
822 inptr->data = nrealloc(inptr->data, i + 2);
823 inptr->data[i + 1] = 0;
824 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000825 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000826
827
828 /* Case 2c: cursor past word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000829 else {
830 temp->data =
831 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000832 strcpy(temp->data, &inptr->data[current_word_start]);
833
834 down = 1;
835 right = current_x - current_word_start;
836
837 current_x = current_word_start;
838 i = current_word_start - 1;
839
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000840 while (isspace((int) inptr->data[i])) {
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000841 i--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000842 assert(i >= 0);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000843 inptr->data = nrealloc(inptr->data, i + 2);
844 inptr->data[i + 1] = 0;
845 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000846 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000847 }
848
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000849 /* We pre-pend wrapped part to next line. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000850 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000851 /* Plus one for the space which concatenates the two lines together plus 1 for \0. */
852 char *p =
853 nmalloc(strlen(temp->data) + strlen(inptr->next->data) + 2);
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000854 int old_x = current_x, old_y = current_y;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000855
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000856 strcpy(p, temp->data);
857 strcat(p, " ");
858 strcat(p, inptr->next->data);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000859
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000860 free(inptr->next->data);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000861 inptr->next->data = p;
862
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000863 free(temp->data);
864 free(temp);
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000865
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000866 current_x = old_x;
867 current_y = old_y;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000868 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000869 /* Else we start a new line. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000870 else {
871 temp->prev = inptr;
872 temp->next = inptr->next;
873
874 if (inptr->next)
875 inptr->next->prev = temp;
876 inptr->next = temp;
877
878 if (!temp->next)
879 filebot = temp;
880
881 SET(SAMELINEWRAP);
882 }
883
884
885 totlines++;
Robert Siemborskia417ddc2000-07-24 23:18:48 +0000886 /* Everything about it makes me want this line here but it causes
887 * totsize to be high by one for some reason. Sigh. (Rob) */
888 /* totsize++; */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000889
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000890 renumber(inptr);
Chris Allegretta234a34d2000-07-29 04:33:38 +0000891 edit_update(edittop, TOP);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000892
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000893
894 /* Move the cursor to the new line if appropriate. */
895 if (down) {
896 do_right();
897 }
898
899 /* Move the cursor to the correct spot in the line if appropriate. */
900 while (right--) {
901 do_right();
902 }
903
Chris Allegretta234a34d2000-07-29 04:33:38 +0000904 edit_update(edittop, TOP);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000905 reset_cursor();
906 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000907}
908
909/* Check to see if we've just caused the line to wrap to a new line */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000910void check_wrap(filestruct * inptr, char ch)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000911{
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000912 int len = strlenpt(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000913#ifdef DEBUG
914 fprintf(stderr, _("check_wrap called with inptr->data=\"%s\"\n"),
915 inptr->data);
916#endif
917
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000918 if (len <= fill)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000919 return;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000920 else {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000921 int i = actual_x(inptr, fill);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000922
923 /* Do not wrap if there are no words on or after wrap point. */
Adam Rogoyski09f97962000-06-20 02:50:33 +0000924 int char_found = 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000925
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000926 while (isspace((int) inptr->data[i]) && inptr->data[i])
Adam Rogoyski09f97962000-06-20 02:50:33 +0000927 i++;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000928
Adam Rogoyski09f97962000-06-20 02:50:33 +0000929 if (!inptr->data[i])
930 return;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000931
Adam Rogoyski09f97962000-06-20 02:50:33 +0000932 /* String must be at least 1 character long. */
933 for (i = strlen(inptr->data) - 1; i >= 0; i--) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000934 if (isspace((int) inptr->data[i])) {
Adam Rogoyski09f97962000-06-20 02:50:33 +0000935 if (!char_found)
936 continue;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000937 char_found = 2; /* 2 for yes do wrap. */
Adam Rogoyski09f97962000-06-20 02:50:33 +0000938 break;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000939 } else
940 char_found = 1; /* 1 for yes found a word, but must check further. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000941 }
Adam Rogoyski09f97962000-06-20 02:50:33 +0000942
943 if (char_found == 2)
944 do_wrap(inptr, ch);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000945 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000946}
947
948/* Stuff we do when we abort from programs and want to clean up the
949 * screen. This doesnt do much right now.
950 */
951void do_early_abort(void)
952{
953 blank_statusbar_refresh();
954}
955
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000956int do_backspace(void)
957{
958 filestruct *previous, *tmp;
959
960 if (current_x != 0) {
961 /* Let's get dangerous */
962 memmove(&current->data[current_x - 1], &current->data[current_x],
963 strlen(current->data) - current_x + 1);
964#ifdef DEBUG
965 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
966#endif
967 align(&current->data);
968 do_left();
969 } else {
970 if (current == fileage)
971 return 0; /* Can't delete past top of file */
972
973 previous = current->prev;
974 current_x = strlen(previous->data);
975 previous->data = nrealloc(previous->data,
976 strlen(previous->data) +
977 strlen(current->data) + 1);
978 strcat(previous->data, current->data);
979
980 tmp = current;
981 unlink_node(current);
982 delete_node(current);
983 if (current == edittop) {
984 if (previous->next)
985 current = previous->next;
986 else
987 current = previous;
Chris Allegrettada721be2000-07-31 01:26:42 +0000988 page_up_center();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000989 } else {
990 if (previous->next)
991 current = previous->next;
992 else
993 current = previous;
994 update_line(current, current_x);
995 }
996
997 /* Ooops, sanity check */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000998 if (tmp == filebot) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000999 filebot = current;
1000 editbot = current;
Chris Allegretta28a0f892000-07-05 22:47:54 +00001001
1002 /* Recreate the magic line if we're deleting it AND if the
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001003 line we're on now is NOT blank. if it is blank we
1004 can just use IT for the magic line. This is how Pico
1005 appears to do it, in any case */
Chris Allegretta28a0f892000-07-05 22:47:54 +00001006 if (strcmp(current->data, "")) {
1007 new_magicline();
1008 fix_editbot();
Chris Allegretta55373872000-07-06 22:38:37 +00001009 totsize++;
Chris Allegretta28a0f892000-07-05 22:47:54 +00001010 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001011 }
1012
1013 current = previous;
1014 renumber(current);
1015 previous_line();
1016 totlines--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001017#ifdef DEBUG
1018 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1019#endif
1020
1021 }
1022
1023 totsize--;
1024 set_modified();
1025 UNSET(KEEP_CUTBUFFER);
1026 edit_refresh();
1027 return 1;
1028}
1029
1030int do_delete(void)
1031{
1032 filestruct *foo;
1033
1034 if (current_x != strlen(current->data)) {
1035 /* Let's get dangerous */
1036 memmove(&current->data[current_x], &current->data[current_x + 1],
1037 strlen(current->data) - current_x);
1038
1039 align(&current->data);
1040
1041 } else if (current->next != NULL) {
1042 current->data = nrealloc(current->data,
1043 strlen(current->data) +
1044 strlen(current->next->data) + 1);
1045 strcat(current->data, current->next->data);
1046
1047 foo = current->next;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001048 if (filebot == foo) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001049 filebot = current;
1050 editbot = current;
1051 }
1052
1053 unlink_node(foo);
1054 delete_node(foo);
1055 update_line(current, current_x);
1056
Chris Allegretta28a0f892000-07-05 22:47:54 +00001057 /* Please see the comment in do_basckspace if you don't understand
1058 this test */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001059 if (current == filebot && strcmp(current->data, "")) {
Chris Allegretta28a0f892000-07-05 22:47:54 +00001060 new_magicline();
1061 fix_editbot();
Chris Allegretta55373872000-07-06 22:38:37 +00001062 totsize++;
Chris Allegretta28a0f892000-07-05 22:47:54 +00001063 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001064 renumber(current);
1065 totlines--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001066 } else
1067 return 0;
1068
1069 totsize--;
1070 set_modified();
1071 UNSET(KEEP_CUTBUFFER);
1072 edit_refresh();
1073 return 1;
1074}
1075
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001076void wrap_reset(void)
1077{
1078 UNSET(SAMELINEWRAP);
1079}
1080
Chris Allegrettaff269f82000-12-01 18:46:01 +00001081#if !defined(NANO_SMALL) && !defined(DISABLE_SPELL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001082
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001083int do_int_spell_fix(char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001084{
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001085 char *prevanswer = NULL, *save_search = NULL, *save_replace = NULL;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001086 filestruct *begin;
1087 int i = 0, j = 0, beginx, beginx_top;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001088
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001089 /* save where we are */
1090 begin = current;
1091 beginx = current_x + 1;
1092
1093 /* save the current search/replace strings */
1094 search_init_globals();
1095 save_search = mallocstrcpy(save_search, last_search);
1096 save_replace = mallocstrcpy(save_replace, last_replace);
1097
1098 /* set search/replace strings to mis-spelt word */
1099 prevanswer = mallocstrcpy(prevanswer, word);
1100 last_search = mallocstrcpy(last_search, word);
1101 last_replace = mallocstrcpy(last_replace, word);
1102
1103 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001104 current = fileage;
1105 current_x = beginx_top = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001106
1107 search_last_line = FALSE;
1108
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001109 edit_update(fileage, TOP);
1110
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001111 /* make sure word is still mis-spelt (i.e. when multi-errors) */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001112 if (findnextstr(TRUE, fileage, beginx_top, prevanswer) != NULL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001113 {
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001114 do_replace_highlight(TRUE, prevanswer);
1115
1116 /* allow replace word to be corrected */
1117 i = statusq(0, spell_list, SPELL_LIST_LEN, last_replace,
1118 _("Edit a replacement"));
1119
1120 do_replace_highlight(FALSE, prevanswer);
1121
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001122 /* start from the start of this line again */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001123 current = fileage;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001124 current_x = beginx_top;
1125
1126 search_last_line = FALSE;
1127
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001128 j = i;
1129 do_replace_loop(prevanswer, fileage, &beginx_top, TRUE, &j);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001130 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001131
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001132 /* restore the search/replace strings */
1133 last_search = mallocstrcpy(last_search, save_search);
1134 last_replace = mallocstrcpy(last_replace, save_replace);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001135
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001136 /* restore where we were */
1137 current = begin;
1138 current_x = beginx - 1;
1139
1140 edit_update(current, CENTER);
1141
1142 if (i == -1)
1143 return FALSE;
1144
1145 return TRUE;
1146}
1147#endif
1148
Chris Allegrettaff269f82000-12-01 18:46:01 +00001149#if !defined(NANO_SMALL) && !defined(DISABLE_SPELL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001150
1151/* Integrated spell checking using 'spell' program */
Chris Allegretta271e9722000-11-10 18:15:43 +00001152int do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001153{
Chris Allegretta271e9722000-11-10 18:15:43 +00001154 char *read_buff, *read_buff_ptr, *read_buff_word;
1155 long pipe_buff_size;
1156 int in_fd[2], tempfile_fd;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001157 int spell_status;
1158 pid_t pid_spell;
1159 ssize_t bytesread;
1160
Chris Allegretta271e9722000-11-10 18:15:43 +00001161 /* Create a pipe to spell program */
1162
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001163 if (pipe(in_fd) == -1)
1164 return FALSE;
1165
Chris Allegretta271e9722000-11-10 18:15:43 +00001166 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001167
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001168 if ( (pid_spell = fork()) == 0) {
1169
1170 /* Child continues, (i.e. future spell process) */
1171
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001172 close(in_fd[0]);
1173
Chris Allegretta271e9722000-11-10 18:15:43 +00001174 /* replace the standard in with the tempfile */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001175
Chris Allegretta271e9722000-11-10 18:15:43 +00001176 if ( (tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) {
1177
1178 close(in_fd[1]);
1179 exit(1);
1180 }
1181
1182 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) {
1183
1184 close(tempfile_fd);
1185 close(in_fd[1]);
1186 exit(1);
1187 }
1188 close(tempfile_fd);
1189
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001190
Chris Allegretta271e9722000-11-10 18:15:43 +00001191 /* send spell's standard out to the pipe */
1192
1193 if (dup2(in_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1194
1195 close(in_fd[1]);
1196 exit(1);
1197 }
1198 close(in_fd[1]);
1199
1200 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001201 execlp("spell", "spell", NULL);
1202
Chris Allegretta271e9722000-11-10 18:15:43 +00001203 /* Should not be reached, if spell is found!!! */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001204
Chris Allegretta271e9722000-11-10 18:15:43 +00001205 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001206 }
1207
1208 /* Parent continues here */
1209
Chris Allegretta271e9722000-11-10 18:15:43 +00001210 close(in_fd[1]);
1211
1212 /* Child process was not forked successfully */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001213
1214 if (pid_spell < 0) {
1215
Chris Allegretta271e9722000-11-10 18:15:43 +00001216 close(in_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001217 return FALSE;
1218 }
1219
Chris Allegretta271e9722000-11-10 18:15:43 +00001220 /* Get system pipe buffer size */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001221
Chris Allegretta271e9722000-11-10 18:15:43 +00001222 if ( (pipe_buff_size = fpathconf(in_fd[0], _PC_PIPE_BUF)) < 1) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001223
Chris Allegretta271e9722000-11-10 18:15:43 +00001224 close(in_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001225 return FALSE;
Chris Allegretta271e9722000-11-10 18:15:43 +00001226 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001227
Chris Allegretta271e9722000-11-10 18:15:43 +00001228 read_buff = nmalloc( pipe_buff_size + 1 );
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001229
Chris Allegretta271e9722000-11-10 18:15:43 +00001230 /* Process the returned spelling errors */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001231
Chris Allegretta271e9722000-11-10 18:15:43 +00001232 while ( (bytesread = read(in_fd[0], read_buff, pipe_buff_size)) > 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001233
Chris Allegretta271e9722000-11-10 18:15:43 +00001234 read_buff[bytesread] = (char) NULL;
1235 read_buff_word = read_buff_ptr = read_buff;
1236
1237 while (*read_buff_ptr != (char) NULL) {
1238
1239 /* Windows version may need to process additional char '\r' */
1240
1241 /* Possible problem here if last word not followed by '\n' */
1242
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001243 if (*read_buff_ptr == '\n') {
Chris Allegretta271e9722000-11-10 18:15:43 +00001244 *read_buff_ptr = (char) NULL;
1245 if (!do_int_spell_fix(read_buff_word)) {
1246
1247 close(in_fd[0]);
1248 free(read_buff);
1249 replace_abort();
1250
1251 return TRUE;
1252 }
1253 read_buff_word = read_buff_ptr;
1254 read_buff_word++;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001255 }
1256
1257 read_buff_ptr++;
1258 }
1259 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001260
1261 close(in_fd[0]);
1262 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001263 replace_abort();
1264
Chris Allegretta271e9722000-11-10 18:15:43 +00001265 /* Process end of spell process */
1266
1267 wait(&spell_status);
1268 if (WIFEXITED(spell_status)) {
1269 if (WEXITSTATUS(spell_status) != 0)
1270 return FALSE;
1271 }
1272 else
1273 return FALSE;
1274
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001275 return TRUE;
1276}
1277#endif
1278
Chris Allegrettaff269f82000-12-01 18:46:01 +00001279#if !defined(NANO_SMALL) && !defined(DISABLE_SPELL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001280
1281/* External spell checking */
Chris Allegretta271e9722000-11-10 18:15:43 +00001282int do_alt_speller(char *file_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001283{
Chris Allegretta271e9722000-11-10 18:15:43 +00001284 int alt_spell_status;
1285 pid_t pid_spell;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001286
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001287 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001288
Chris Allegretta271e9722000-11-10 18:15:43 +00001289 /* Start a new process for the alternate speller */
1290
1291 if ( (pid_spell = fork()) == 0) {
1292
1293 /* Start alternate spell program, we are using the PATH here!?!? */
1294 execlp(alt_speller, alt_speller, file_name, NULL);
1295
1296 /* Should not be reached, if alternate speller is found!!! */
1297
1298 exit(1);
1299 }
1300
1301 /* Could not fork?? */
1302
1303 if (pid_spell < 0)
1304 return FALSE;
1305
1306 /* Wait for alternate speller to complete */
1307
1308 wait(&alt_spell_status);
1309 if (WIFEXITED(alt_spell_status)) {
1310 if (WEXITSTATUS(alt_spell_status) != 0)
1311 return FALSE;
1312 }
1313 else
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001314 return FALSE;
1315
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001316 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001317 free_filestruct(fileage);
1318 global_init();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001319 open_file(file_name, 0, 1);
Chris Allegretta234a34d2000-07-29 04:33:38 +00001320 edit_update(fileage, CENTER);
Chris Allegretta271e9722000-11-10 18:15:43 +00001321 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001322 set_modified();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001323
1324 return TRUE;
1325}
1326#endif
1327
1328int do_spell(void)
1329{
1330
Chris Allegrettaff269f82000-12-01 18:46:01 +00001331#if defined(NANO_SMALL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001332 nano_small_msg();
1333 return (TRUE);
Chris Allegrettaff269f82000-12-01 18:46:01 +00001334#elif defined(DISABLE_SPELL)
1335 nano_disabled_msg();
1336 return (TRUE);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001337#else
Chris Allegretta271e9722000-11-10 18:15:43 +00001338 char *temp;
1339 int spell_res;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001340
Chris Allegretta271e9722000-11-10 18:15:43 +00001341 if ((temp = tempnam(0, "nano.")) == NULL) {
1342 statusbar(_("Could not create a temporary filename: %s"),
1343 strerror(errno));
1344 return 0;
1345 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001346
Chris Allegretta271e9722000-11-10 18:15:43 +00001347 if (write_file(temp, 1) == -1)
1348 return 0;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001349
Chris Allegretta271e9722000-11-10 18:15:43 +00001350 if (alt_speller)
1351 spell_res = do_alt_speller(temp);
1352 else
1353 spell_res = do_int_speller(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001354
Chris Allegretta271e9722000-11-10 18:15:43 +00001355 remove(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001356
1357 if (spell_res)
1358 statusbar(_("Finished checking spelling"));
1359 else
1360 statusbar(_("Spell checking failed"));
1361
1362 return spell_res;
1363
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001364#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001365}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001366
1367int do_exit(void)
1368{
1369 int i;
1370
1371 if (!ISSET(MODIFIED))
1372 finish(0);
1373
Chris Allegretta30885552000-07-14 01:20:12 +00001374 if (ISSET(TEMP_OPT)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001375 i = 1;
1376 } else {
1377 i =
1378 do_yesno(0, 0,
1379 _
1380 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
1381 }
1382
1383#ifdef DEBUG
1384 dump_buffer(fileage);
1385#endif
1386
1387 if (i == 1) {
1388 if (do_writeout(1) > 0)
1389 finish(0);
1390 } else if (i == 0)
1391 finish(0);
1392 else
1393 statusbar(_("Cancelled"));
1394
1395 display_main_list();
1396 return 1;
1397}
1398
1399#ifndef NANO_SMALL
1400#ifdef NCURSES_MOUSE_VERSION
1401void do_mouse(void)
1402{
1403 MEVENT mevent;
Chris Allegrettae10debd2000-08-22 01:26:42 +00001404 int foo = 0, tab_found = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001405
1406 if (getmouse(&mevent) == ERR)
1407 return;
1408
1409 /* If mouse not in edit window, return (add help selection later). */
1410 if (!wenclose(edit, mevent.y, mevent.x))
1411 return;
1412
1413 /* Subtract out size of topwin. Perhaps we need a constant somewhere? */
1414 mevent.y -= 2;
1415
1416 /* Selecting where the cursor is sets the mark.
1417 * Selecting beyond the line length with the cursor at the end of the
1418 * line sets the mark as well.
1419 */
1420 if ((mevent.y == current_y) &&
1421 ((mevent.x == current_x) || (current_x == strlen(current->data)
1422 && (mevent.x >
1423 strlen(current->data))))) {
1424 if (ISSET(VIEW_MODE)) {
1425 print_view_warning();
1426 return;
1427 }
1428 do_mark();
1429 } else if (mevent.y > current_y) {
1430 while (mevent.y > current_y) {
1431 if (current->next != NULL)
1432 current = current->next;
1433 else
1434 break;
1435 current_y++;
1436 }
1437 } else if (mevent.y < current_y) {
1438 while (mevent.y < current_y) {
1439 if (current->prev != NULL)
1440 current = current->prev;
1441 else
1442 break;
1443 current_y--;
1444 }
1445 }
1446 current_x = mevent.x;
Chris Allegrettae10debd2000-08-22 01:26:42 +00001447 placewewant = current_x;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001448 while (foo < current_x) {
1449 if (current->data[foo] == NANO_CONTROL_I) {
Chris Allegrettae10debd2000-08-22 01:26:42 +00001450 current_x -= tabsize - (foo % tabsize);
1451 tab_found = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001452 } else if (current->data[foo] & 0x80);
1453 else if (current->data[foo] < 32)
Chris Allegrettae10debd2000-08-22 01:26:42 +00001454 current_x--;
1455 foo++;
1456 }
1457 /* This is where tab_found comes in. I can't figure out why,
1458 * but without it any line with a tab will place the cursor
1459 * one character behind. Whatever, this fixes it. */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001460 if (tab_found == 1)
Chris Allegrettae10debd2000-08-22 01:26:42 +00001461 current_x++;
1462
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001463 if (current_x > strlen(current->data))
1464 current_x = strlen(current->data);
1465
1466 update_cursor();
1467 edit_refresh();
1468
1469}
1470#endif
1471#endif
1472
1473/* Handler for SIGHUP */
1474RETSIGTYPE handle_hup(int signal)
1475{
1476 write_file("nano.save", 0);
1477 finish(1);
1478}
1479
Chris Allegretta18f8be02000-09-04 03:20:38 +00001480/* What do we do when we catch the suspend signal */
1481RETSIGTYPE do_suspend(int signal)
1482{
1483
1484 act.sa_handler = SIG_DFL;
1485 sigemptyset(&act.sa_mask);
1486 sigaction(SIGTSTP, &act, NULL);
1487
1488 endwin();
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001489 fprintf(stderr, "\n\n\n\n\nUse \"fg\" to return to nano\n");
Chris Allegretta18f8be02000-09-04 03:20:38 +00001490 raise(SIGTSTP);
1491}
1492
1493/* Restore the suspend handler when we come back into the prog */
1494RETSIGTYPE do_cont(int signal)
1495{
1496
1497 act.sa_handler = do_suspend;
1498 sigemptyset(&act.sa_mask);
1499 sigaction(SIGTSTP, &act, NULL);
1500 initscr();
1501 total_refresh();
1502}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001503
1504void handle_sigwinch(int s)
1505{
1506#ifndef NANO_SMALL
1507 char *tty = NULL;
1508 int fd = 0;
1509 int result = 0;
1510 int i = 0;
1511 struct winsize win;
1512
1513 tty = ttyname(0);
1514 if (!tty)
1515 return;
1516 fd = open(tty, O_RDWR);
1517 if (fd == -1)
1518 return;
1519 result = ioctl(fd, TIOCGWINSZ, &win);
1520 if (result == -1)
1521 return;
1522
1523
1524 COLS = win.ws_col;
1525 LINES = win.ws_row;
1526
1527 center_x = COLS / 2;
1528 center_y = LINES / 2;
1529 editwinrows = LINES - 5 + no_help();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001530 fill = COLS - 8;
1531
1532 free(hblank);
1533 hblank = nmalloc(COLS + 1);
1534
1535 for (i = 0; i <= COLS - 1; i++)
1536 hblank[i] = ' ';
1537 hblank[i] = 0;
1538
1539#ifdef HAVE_NCURSES_H
1540 resizeterm(LINES, COLS);
1541#ifdef HAVE_WRESIZE
1542 if (wresize(topwin, 2, COLS) == ERR)
1543 die(_("Cannot resize top win"));
1544 if (mvwin(topwin, 0, 0) == ERR)
1545 die(_("Cannot move top win"));
1546 if (wresize(edit, editwinrows, COLS) == ERR)
1547 die(_("Cannot resize edit win"));
1548 if (mvwin(edit, 2, 0) == ERR)
1549 die(_("Cannot move edit win"));
1550 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
1551 die(_("Cannot resize bottom win"));
1552 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
1553 die(_("Cannot move bottom win"));
1554#endif /* HAVE_WRESIZE */
1555#endif /* HAVE_NCURSES_H */
1556
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001557 fix_editbot();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001558
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001559 if (current_y > editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001560 edit_update(editbot, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001561 }
1562 erase();
Chris Allegretta97accc62000-06-19 05:45:52 +00001563
1564 /* Do these b/c width may have changed... */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001565 refresh();
Chris Allegretta97accc62000-06-19 05:45:52 +00001566 titlebar();
1567 edit_refresh();
1568 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001569 total_refresh();
1570#endif
1571}
1572
Chris Allegretta756f2202000-09-01 13:32:47 +00001573void signal_init(void)
1574{
Chris Allegretta756f2202000-09-01 13:32:47 +00001575
1576 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
1577 memset(&act, 0, sizeof(struct sigaction));
1578 act.sa_handler = SIG_IGN;
1579 sigaction(SIGINT, &act, NULL);
Chris Allegretta756f2202000-09-01 13:32:47 +00001580
Chris Allegretta18f8be02000-09-04 03:20:38 +00001581 if (!ISSET(SUSPEND)) {
Chris Allegretta756f2202000-09-01 13:32:47 +00001582 sigaction(SIGTSTP, &act, NULL);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001583 } else {
Chris Allegretta18f8be02000-09-04 03:20:38 +00001584 act.sa_handler = do_suspend;
1585 sigaction(SIGTSTP, &act, NULL);
1586
1587 act.sa_handler = do_cont;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001588 sigaction(SIGCONT, &act, NULL);
Chris Allegretta18f8be02000-09-04 03:20:38 +00001589 }
1590
Chris Allegretta756f2202000-09-01 13:32:47 +00001591
1592 /* Trap SIGHUP cuz we want to write the file out. */
1593 act.sa_handler = handle_hup;
1594 sigaction(SIGHUP, &act, NULL);
1595
1596 act.sa_handler = handle_sigwinch;
1597 sigaction(SIGWINCH, &act, NULL);
1598
1599}
1600
Chris Allegretta2a42af12000-09-12 23:02:49 +00001601void window_init(void)
1602{
Chris Allegretta92c9dd22000-09-13 14:03:27 +00001603 editwinrows = LINES - 5 + no_help();
1604
Chris Allegretta2a42af12000-09-12 23:02:49 +00001605 /* Setup up the main text window */
1606 edit = newwin(editwinrows, COLS, 2, 0);
1607
1608 /* And the other windows */
1609 topwin = newwin(2, COLS, 0, 0);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001610 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001611}
1612
Chris Allegretta756f2202000-09-01 13:32:47 +00001613void mouse_init(void)
1614{
1615#ifndef NANO_SMALL
1616#ifdef NCURSES_MOUSE_VERSION
1617 if (ISSET(USE_MOUSE)) {
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +00001618 keypad_on(TRUE);
Chris Allegretta0b88ce02000-09-15 15:46:32 +00001619
Chris Allegretta756f2202000-09-01 13:32:47 +00001620 mousemask(BUTTON1_RELEASED, NULL);
1621 mouseinterval(50);
Chris Allegretta0b88ce02000-09-15 15:46:32 +00001622
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001623 } else {
Chris Allegretta756f2202000-09-01 13:32:47 +00001624 mousemask(0, NULL);
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +00001625 keypad_on(FALSE);
Chris Allegretta756f2202000-09-01 13:32:47 +00001626 }
1627#endif
1628#endif
1629
1630}
1631
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001632int do_tab(void)
1633{
1634 do_char('\t');
1635 return 1;
1636}
1637
Chris Allegrettaff269f82000-12-01 18:46:01 +00001638#if !defined(NANO_SMALL) && !defined(DISABLE_JUSTIFY)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001639int empty_line(const char *data)
1640{
1641 while (*data) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001642 if (!isspace((int) *data))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001643 return 0;
1644
1645 data++;
1646 }
1647
1648 return 1;
1649}
1650
1651int no_spaces(const char *data)
1652{
1653 while (*data) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001654 if (isspace((int) *data))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001655 return 0;
1656
1657 data++;
1658 }
1659
1660 return 1;
1661}
1662
1663void justify_format(char *data)
1664{
1665 int i = 0;
1666 int len = strlen(data);
1667
1668 /* Skip first character regardless and leading whitespace. */
1669 for (i = 1; i < len; i++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001670 if (!isspace((int) data[i]))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001671 break;
1672 }
1673
1674 i++; /* (i) is now at least 2. */
1675
1676 /* No double spaces allowed unless following a period. Tabs -> space. No double tabs. */
1677 for (; i < len; i++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001678 if (isspace((int) data[i]) && isspace((int) data[i - 1])
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001679 && (data[i - 2] != '.')) {
1680 memmove(data + i, data + i + 1, len - i);
1681 len--;
1682 i--;
1683 }
1684 }
1685}
1686#endif
1687
1688int do_justify(void)
1689{
Chris Allegrettaff269f82000-12-01 18:46:01 +00001690#ifdef NANO_SMALL
1691 nano_small_msg();
1692 return 1;
1693#elif defined(DISABLE_JUSTIFY)
1694 nano_disabled_msg();
1695 return 1;
1696#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001697 int slen = 0; /* length of combined lines on one line. */
Chris Allegretta9149e612000-11-27 00:23:41 +00001698 int initial_y, kbinput;
1699 filestruct *initial = NULL, *tmpjust = NULL, *cutbak, *tmptop, *tmpbot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001700
1701 if (empty_line(current->data)) {
1702 /* Justify starting at first non-empty line. */
1703 do {
1704 if (!current->next)
1705 return 1;
1706
1707 current = current->next;
1708 current_y++;
1709 }
1710 while (empty_line(current->data));
1711 } else {
1712 /* Search back for the beginning of the paragraph, where
1713 * Paragraph is 1) A line with leading whitespace
1714 * or 2) A line following an empty line.
1715 */
1716 while (current->prev != NULL) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001717 if (isspace((int) current->data[0]) || !current->data[0])
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001718 break;
1719
1720 current = current->prev;
1721 current_y--;
1722 }
1723
1724 /* First line with leading whitespace may be empty. */
1725 if (empty_line(current->data)) {
1726 if (current->next) {
1727 current = current->next;
1728 current_y++;
1729 } else
1730 return 1;
1731 }
1732 }
1733 initial = current;
1734 initial_y = current_y;
1735
1736 set_modified();
Chris Allegretta9149e612000-11-27 00:23:41 +00001737 cutbak = cutbuffer; /* Got to like cutbak ;) */
1738 cutbuffer = NULL;
1739
1740 tmptop = current;
1741 tmpjust = copy_node(current);
1742 add_to_cutbuffer(tmpjust);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001743 /* Put the whole paragraph into one big line. */
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001744 while (current->next && !isspace((int) current->next->data[0])
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001745 && current->next->data[0]) {
1746 filestruct *tmpnode = current->next;
1747 int len = strlen(current->data);
1748 int len2 = strlen(current->next->data);
1749
Chris Allegretta9149e612000-11-27 00:23:41 +00001750 tmpjust = NULL;
Chris Allegretta9149e612000-11-27 00:23:41 +00001751 tmpjust = copy_node(current->next);
1752 add_to_cutbuffer(tmpjust);
1753
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001754 /* length of both strings plus space between strings and ending \0. */
1755 current->data = nrealloc(current->data, len + len2 + 2);
1756 current->data[len++] = ' ';
1757 current->data[len] = '\0';
1758
1759 strncat(current->data, current->next->data, len2);
1760
1761 unlink_node(tmpnode);
1762 delete_node(tmpnode);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001763 }
1764
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001765 totsize -= strlen(current->data);
1766
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001767 justify_format(current->data);
1768
1769 slen = strlen(current->data);
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001770 totsize += slen;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001771
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001772 if ((strlenpt(current->data) > (fill))
1773 && !no_spaces(current->data)) {
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001774 do {
1775 int i = 0;
1776 int len2 = 0;
1777 filestruct *tmpline = nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001778
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001779 /* Start at fill , unless line isn't that long (but it
1780 * appears at least fill long with tabs.
1781 */
1782 if (slen > fill)
1783 i = fill;
1784 else
1785 i = slen;
1786 for (; i > 0; i--) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001787 if (isspace((int) current->data[i]) &&
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001788 ((strlenpt(current->data) - strlen(current->data + i))
1789 <= fill))
1790 break;
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001791 }
1792 if (!i)
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001793 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001794
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001795 current->data[i] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001796
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001797 len2 = strlen(current->data + i + 1);
1798 tmpline->data = nmalloc(len2 + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001799
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001800 /* Skip the white space in current. */
1801 memcpy(tmpline->data, current->data + i + 1, len2);
1802 tmpline->data[len2] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001803
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001804 current->data = nrealloc(current->data, i + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001805
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001806 tmpline->prev = current;
1807 tmpline->next = current->next;
1808 if (current->next != NULL)
1809 current->next->prev = tmpline;
1810
1811 current->next = tmpline;
1812 current = tmpline;
1813 slen -= i + 1;
1814 current_y++;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001815 } while ((strlenpt(current->data) > (fill))
1816 && !no_spaces(current->data));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001817 }
Chris Allegretta9149e612000-11-27 00:23:41 +00001818 tmpbot = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001819
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001820 if (current->next)
1821 current = current->next;
Adam Rogoyski09f97962000-06-20 02:50:33 +00001822 else
1823 filebot = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001824 current_x = 0;
1825 placewewant = 0;
1826
Adam Rogoyski09f97962000-06-20 02:50:33 +00001827 renumber(initial);
1828 totlines = filebot->lineno;
1829
1830 werase(edit);
1831
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001832 if ((current_y < 0) || (current_y >= editwinrows - 1)
1833 || (initial_y <= 0)) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001834 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001835 center_cursor();
1836 } else {
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001837 fix_editbot();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001838 }
1839
Adam Rogoyski09f97962000-06-20 02:50:33 +00001840 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00001841 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00001842 /* Change the shortcut list to display the unjustify code */
1843 shortcut_init(1);
1844 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00001845 reset_cursor();
1846
Chris Allegretta07798352000-11-27 22:58:23 +00001847 /* Now get a keystroke and see if it's unjustify, if not unget the keytroke
Chris Allegretta9149e612000-11-27 00:23:41 +00001848 and return */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00001849 if ((kbinput = wgetch(edit)) != NANO_UNJUSTIFY_KEY)
Chris Allegretta07798352000-11-27 22:58:23 +00001850 ungetch(kbinput);
Chris Allegretta9149e612000-11-27 00:23:41 +00001851 else {
1852 /* Else restore the justify we just did (ungrateful user!) */
1853 if (tmptop->prev != NULL)
1854 tmptop->prev->next = tmpbot->next;
Chris Allegrettad022eac2000-11-27 02:50:49 +00001855 else
1856 fileage = current;
Chris Allegretta9149e612000-11-27 00:23:41 +00001857 tmpbot->next->prev = tmptop->prev;
1858 current = tmpbot->next;
1859 tmpbot->next = NULL;
1860 do_uncut_text();
Chris Allegrettad022eac2000-11-27 02:50:49 +00001861 if (tmptop->prev == NULL)
1862 edit_refresh();
1863
Chris Allegretta9149e612000-11-27 00:23:41 +00001864 free_filestruct(tmptop);
1865 blank_statusbar_refresh();
1866 }
Chris Allegretta4a9c8582000-11-27 22:59:40 +00001867 shortcut_init(0);
1868 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00001869 free_filestruct(cutbuffer);
1870 cutbuffer = cutbak;
1871
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001872 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001873#endif
1874}
1875
1876
1877void help_init(void)
1878{
1879 int i, sofar = 0;
1880 long allocsize = 1; /* How much space we're gonna need for the help text */
1881 char buf[BUFSIZ];
1882
1883 /* Compute the space needed for the shortcut lists - we add 15 to
1884 have room for the shortcut abbrev and its possible alternate keys */
1885 for (i = 0; i < MAIN_LIST_LEN; i++)
1886 if (main_list[i].help != NULL)
1887 allocsize += strlen(main_list[i].help) + 15;
1888
Chris Allegretta756f2202000-09-01 13:32:47 +00001889 /* And for the toggle list, we also allocate space for extra text. */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001890 for (i = 0; i <= TOGGLE_LEN - 1; i++)
Chris Allegretta756f2202000-09-01 13:32:47 +00001891 if (toggles[i].desc != NULL)
1892 allocsize += strlen(toggles[i].desc) + 30;
1893
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001894 allocsize += strlen(help_text_init);
1895
1896 if (help_text != NULL)
1897 free(help_text);
1898
1899 /* Allocate space for the help text */
1900 help_text = nmalloc(allocsize);
1901
1902 /* Now add the text we want */
1903 strcpy(help_text, help_text_init);
1904
1905 /* Now add our shortcut info */
Chris Allegretta756f2202000-09-01 13:32:47 +00001906 for (i = 0; i < MAIN_LIST_LEN - 1; i++) {
Robert Siemborski6af14312000-07-01 21:34:26 +00001907 sofar = snprintf(buf, BUFSIZ, "^%c ", main_list[i].val + 64);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001908
1909 if (main_list[i].misc1 > KEY_F0 && main_list[i].misc1 <= KEY_F(64))
Robert Siemborski6af14312000-07-01 21:34:26 +00001910 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(F%d) ",
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001911 main_list[i].misc1 - KEY_F0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001912 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001913 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001914
1915 if (main_list[i].altval > 0)
Chris Allegrettae49f1232000-09-02 07:20:39 +00001916 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(M-%c) ",
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001917 main_list[i].altval - 32);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001918 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001919 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001920
Chris Allegretta756f2202000-09-01 13:32:47 +00001921
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001922 if (main_list[i].help != NULL)
Robert Siemborski976847c2000-07-06 03:43:05 +00001923 snprintf(&buf[sofar], BUFSIZ - sofar, "%s", main_list[i].help);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001924
Chris Allegretta756f2202000-09-01 13:32:47 +00001925
1926 strcat(help_text, buf);
1927 strcat(help_text, "\n");
1928 }
1929
1930 /* And the toggles... */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001931 for (i = 0; i <= TOGGLE_LEN - 1; i++) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001932 sofar = snprintf(buf, BUFSIZ,
1933 "M-%c ", toggles[i].val - 32);
Chris Allegretta756f2202000-09-01 13:32:47 +00001934
1935 if (toggles[i].desc != NULL)
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001936 snprintf(&buf[sofar], BUFSIZ - sofar, _("%s enable/disable"),
1937 toggles[i].desc);
Chris Allegretta756f2202000-09-01 13:32:47 +00001938
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001939 strcat(help_text, buf);
Robert Siemborski976847c2000-07-06 03:43:05 +00001940 strcat(help_text, "\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001941 }
1942
1943}
1944
Chris Allegretta756f2202000-09-01 13:32:47 +00001945void do_toggle(int which)
1946{
1947#ifndef NANO_SMALL
Jordi Mallach2dc0f6b2000-09-07 10:48:00 +00001948 char *enabled = _("enabled");
1949 char *disabled = _("disabled");
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00001950
Chris Allegretta2a42af12000-09-12 23:02:49 +00001951 if (ISSET(toggles[which].flag))
Chris Allegretta756f2202000-09-01 13:32:47 +00001952 UNSET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001953 else
Chris Allegretta756f2202000-09-01 13:32:47 +00001954 SET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001955
Chris Allegretta756f2202000-09-01 13:32:47 +00001956 switch (toggles[which].val) {
1957 case TOGGLE_PICOMODE_KEY:
Chris Allegretta07798352000-11-27 22:58:23 +00001958 shortcut_init(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00001959 display_main_list();
1960 break;
1961 case TOGGLE_SUSPEND_KEY:
1962 signal_init();
1963 break;
1964 case TOGGLE_MOUSE_KEY:
1965 mouse_init();
1966 break;
1967 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00001968 wclear(bottomwin);
1969 wrefresh(bottomwin);
1970 window_init();
1971 edit_refresh();
1972 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00001973 break;
1974 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00001975
1976 if (!ISSET(toggles[which].flag)) {
1977 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001978 toggles[which].val == TOGGLE_WRAP_KEY)
Chris Allegretta2a42af12000-09-12 23:02:49 +00001979 statusbar("%s %s", toggles[which].desc, enabled);
1980 else
1981 statusbar("%s %s", toggles[which].desc, disabled);
1982 } else {
1983 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001984 toggles[which].val == TOGGLE_WRAP_KEY)
Chris Allegretta2a42af12000-09-12 23:02:49 +00001985 statusbar("%s %s", toggles[which].desc, disabled);
1986 else
1987 statusbar("%s %s", toggles[which].desc, enabled);
1988 }
Chris Allegretta756f2202000-09-01 13:32:47 +00001989 SET(DISABLE_CURPOS);
1990
Chris Allegretta4c780be2000-09-01 17:59:18 +00001991#else
1992 nano_small_msg();
Chris Allegretta756f2202000-09-01 13:32:47 +00001993#endif
1994}
1995
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001996int main(int argc, char *argv[])
1997{
1998 int optchr;
1999 int kbinput; /* Input from keyboard */
2000 long startline = 0; /* Line to try and start at */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002001 int keyhandled = 0; /* Have we handled the keystroke yet? */
Chris Allegretta16e41682000-09-11 22:33:54 +00002002 int i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002003 char *argv0;
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002004#ifdef _POSIX_VDISABLE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002005 struct termios term;
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002006#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002007
2008#ifdef HAVE_GETOPT_LONG
2009 int option_index = 0;
2010 struct option long_options[] = {
Chris Allegretta805c26d2000-09-06 13:39:17 +00002011#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002012 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00002013#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002014 {"version", 0, 0, 'V'},
2015 {"const", 0, 0, 'c'},
2016 {"suspend", 0, 0, 'z'},
2017 {"nowrap", 0, 0, 'w'},
2018 {"nohelp", 0, 0, 'x'},
2019 {"help", 0, 0, 'h'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00002020#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00002021 {"cut", 0, 0, 'k'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00002022#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002023 {"autoindent", 0, 0, 'i'},
2024 {"tempfile", 0, 0, 't'},
2025 {"speller", 1, 0, 's'},
2026 {"fill", 1, 0, 'r'},
2027 {"mouse", 0, 0, 'm'},
2028 {"pico", 0, 0, 'p'},
2029 {"nofollow", 0, 0, 'l'},
Chris Allegretta4dbcc3c2000-08-04 15:44:29 +00002030 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002031 {0, 0, 0, 0}
2032 };
2033#endif
2034
2035 /* Flag inits... */
2036 SET(FOLLOW_SYMLINKS);
2037
2038#ifndef NANO_SMALL
2039 setlocale(LC_ALL, "");
2040 bindtextdomain(PACKAGE, LOCALEDIR);
2041 textdomain(PACKAGE);
2042#endif
2043
2044#ifdef HAVE_GETOPT_LONG
Chris Allegretta627de192000-07-12 02:09:17 +00002045 while ((optchr = getopt_long(argc, argv, "?T:RVchiklmpr:s:tvwxz",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002046 long_options, &option_index)) != EOF) {
2047#else
Chris Allegretta627de192000-07-12 02:09:17 +00002048 while ((optchr = getopt(argc, argv, "h?T:RVciklmpr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002049#endif
2050
2051 switch (optchr) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00002052 case 'T':
Chris Allegretta99bf73f2000-08-04 00:22:08 +00002053 tabsize = atoi(optarg);
2054 if (tabsize <= 0) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00002055 usage(); /* To stop bogus data for tab width */
2056 finish(1);
2057 }
2058 break;
Chris Allegretta805c26d2000-09-06 13:39:17 +00002059#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00002060 case 'R':
2061 SET(USE_REGEXP);
2062 break;
Chris Allegretta47805612000-07-07 02:35:34 +00002063#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002064 case 'V':
2065 version();
2066 exit(0);
2067 case 'c':
2068 SET(CONSTUPDATE);
2069 break;
2070 case 'h':
2071 case '?':
2072 usage();
2073 exit(0);
2074 case 'i':
2075 SET(AUTOINDENT);
2076 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00002077#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00002078 case 'k':
2079 SET(CUT_TO_END);
2080 break;
Chris Allegretta18bd0292000-07-28 01:18:10 +00002081#else
2082 case 'k':
2083 usage(); /* Oops! You dont really have that option */
2084 finish(1);
Chris Allegrettad19e9912000-07-12 18:14:51 +00002085#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002086 case 'l':
2087 UNSET(FOLLOW_SYMLINKS);
2088 break;
2089 case 'm':
2090 SET(USE_MOUSE);
2091 break;
2092 case 'p':
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00002093 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002094 break;
2095 case 'r':
2096 fill = atoi(optarg);
2097 if (fill <= 0) {
2098 usage(); /* To stop bogus data (like a string) */
2099 finish(1);
2100 }
2101 break;
2102 case 's':
2103 alt_speller = nmalloc(strlen(optarg) + 1);
2104 strcpy(alt_speller, optarg);
2105 break;
2106 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00002107 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002108 break;
2109 case 'v':
2110 SET(VIEW_MODE);
2111 break;
2112 case 'w':
2113 SET(NO_WRAP);
2114 break;
2115 case 'x':
2116 SET(NO_HELP);
2117 break;
2118 case 'z':
2119 SET(SUSPEND);
2120 break;
2121 default:
2122 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002123 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002124 }
2125
2126 }
2127
2128 argv0 = strrchr(argv[0], '/');
2129 if ((argv0 && strstr(argv0, "pico"))
2130 || (!argv0 && strstr(argv[0], "pico")))
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00002131 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002132
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002133 /* See if there's a non-option in argv (first non-option is the
2134 filename, if +LINE is not given) */
2135 if (argc == 1 || argc <= optind)
2136 strcpy(filename, "");
2137 else {
2138 /* Look for the +line flag... */
2139 if (argv[optind][0] == '+') {
2140 startline = atoi(&argv[optind][1]);
2141 optind++;
2142 if (argc == 1 || argc <= optind)
2143 strcpy(filename, "");
2144 else
2145 strncpy(filename, argv[optind], 132);
2146 } else
2147 strncpy(filename, argv[optind], 132);
2148
2149 }
2150
2151
2152 /* First back up the old settings so they can be restored, duh */
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002153 tcgetattr(0, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002154
Chris Allegretta9239d742000-09-06 15:19:18 +00002155#ifdef _POSIX_VDISABLE
Chris Allegretta8f6c0692000-07-19 01:16:18 +00002156 term = oldterm;
2157 term.c_cc[VINTR] = _POSIX_VDISABLE;
2158 term.c_cc[VQUIT] = _POSIX_VDISABLE;
2159 term.c_lflag &= ~IEXTEN;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002160 tcsetattr(0, TCSANOW, &term);
Chris Allegretta9239d742000-09-06 15:19:18 +00002161#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002162
2163 /* now ncurses init stuff... */
2164 initscr();
2165 savetty();
2166 nonl();
2167 cbreak();
2168 noecho();
2169 timeout(0);
2170
2171 /* Set up some global variables */
2172 global_init();
Chris Allegretta07798352000-11-27 22:58:23 +00002173 shortcut_init(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002174 init_help_msg();
2175 help_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00002176 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002177
2178#ifdef DEBUG
2179 fprintf(stderr, _("Main: set up windows\n"));
2180#endif
2181
Chris Allegretta2a42af12000-09-12 23:02:49 +00002182 window_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00002183 mouse_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002184
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002185#ifdef PDCURSES
2186 /* Must have this for the arrow, et al, keys to even work in
2187 PDCurses+cygwin under Windows */
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +00002188 keypad_on(TRUE);
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002189#endif
2190
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002191#ifdef DEBUG
2192 fprintf(stderr, _("Main: bottom win\n"));
2193#endif
2194 /* Set up up bottom of window */
2195 display_main_list();
2196
2197#ifdef DEBUG
2198 fprintf(stderr, _("Main: open file\n"));
2199#endif
2200
2201 titlebar();
Chris Allegretta31c76662000-11-21 06:20:20 +00002202
2203 /* Now we check to see if argv[optind] is non-null to determine if
2204 we're dealing with a new file or not, not argc == 1... */
2205 if (argv[optind] == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002206 new_file();
2207 else
2208 open_file(filename, 0, 0);
2209
2210 if (startline > 0)
2211 do_gotoline(startline);
2212 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00002213 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002214
Robert Siemborski6967eec2000-07-08 14:23:32 +00002215 edit_refresh();
2216 reset_cursor();
2217
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002218 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00002219
2220#ifndef _POSIX_VDISABLE
2221 /* We're going to have to do it the old way, i.e. on cygwin */
2222 raw();
2223#endif
2224
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002225 kbinput = wgetch(edit);
2226 if (kbinput == 27) { /* Grab Alt-key stuff first */
2227 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002228 /* Alt-O, suddenly very important ;) */
Chris Allegretta16e41682000-09-11 22:33:54 +00002229 case 79:
2230 kbinput = wgetch(edit);
2231 if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002232 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00002233#ifdef DEBUG
2234 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002235 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
2236 kbinput, kbinput);
2237 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002238 }
2239#endif
2240 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002241 case 91:
2242
2243 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002244 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00002245 kbinput = wgetch(edit);
2246 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002247 kbinput = KEY_F(kbinput - 48);
2248 wgetch(edit);
2249 } else if (kbinput >= '7' && kbinput <= '9') {
2250 kbinput = KEY_F(kbinput - 49);
2251 wgetch(edit);
2252 } else if (kbinput == 126)
2253 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00002254
2255#ifdef DEBUG
2256 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002257 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
2258 kbinput, kbinput);
2259 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002260 }
2261#endif
2262
2263 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002264 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00002265 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00002266 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002267 case '0':
2268 kbinput = KEY_F(9);
2269 wgetch(edit);
2270 break;
2271 case '1':
2272 kbinput = KEY_F(10);
2273 wgetch(edit);
2274 break;
2275 case '3':
2276 kbinput = KEY_F(11);
2277 wgetch(edit);
2278 break;
2279 case '4':
2280 kbinput = KEY_F(12);
2281 wgetch(edit);
2282 break;
2283 case 126: /* Hack, make insert key do something
2284 usefile, like insert file */
2285 do_insertfile();
2286 keyhandled = 1;
2287 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002288#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002289 default:
2290 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
2291 kbinput, kbinput);
2292 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002293#endif
2294
2295 }
2296 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002297 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00002298 kbinput = NANO_DELETE_KEY;
2299 wgetch(edit);
2300 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002301 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00002302 kbinput = NANO_END_KEY;
2303 wgetch(edit);
2304 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002305 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00002306 kbinput = KEY_PPAGE;
2307 wgetch(edit);
2308 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002309 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00002310 kbinput = KEY_NPAGE;
2311 wgetch(edit);
2312 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002313 case '[': /* Alt-[-[-[A-E], F1-F5 in linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00002314 kbinput = wgetch(edit);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002315 if (kbinput >= 'A' && kbinput <= 'E')
2316 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00002317 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002318 case 'A':
2319 kbinput = KEY_UP;
2320 break;
2321 case 'B':
2322 kbinput = KEY_DOWN;
2323 break;
2324 case 'C':
2325 kbinput = KEY_RIGHT;
2326 break;
2327 case 'D':
2328 kbinput = KEY_LEFT;
2329 break;
2330 case 'H':
2331 kbinput = KEY_HOME;
2332 break;
2333 case 'F':
2334 kbinput = KEY_END;
2335 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002336 default:
2337#ifdef DEBUG
2338 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
2339 kbinput, kbinput);
2340#endif
2341 break;
2342 }
2343 break;
2344 default:
2345
2346 /* Check for the altkey defs.... */
2347 for (i = 0; i <= MAIN_LIST_LEN - 1; i++)
2348 if (kbinput == main_list[i].altval ||
2349 kbinput == main_list[i].altval - 32) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002350 kbinput = main_list[i].val;
2351 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002352 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002353#ifndef NANO_SMALL
2354 /* And for toggle switches */
2355 for (i = 0; i <= TOGGLE_LEN - 1 && !keyhandled; i++)
2356 if (kbinput == toggles[i].val ||
2357 kbinput == toggles[i].val - 32) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002358 do_toggle(i);
2359 keyhandled = 1;
2360 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00002361 }
2362#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002363#ifdef DEBUG
2364 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
2365 kbinput);
2366#endif
2367 break;
2368 }
2369 }
2370 /* Look through the main shortcut list to see if we've hit a
2371 shortcut key */
Chris Allegretta756f2202000-09-01 13:32:47 +00002372 for (i = 0; i < MAIN_LIST_LEN && !keyhandled; i++) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002373 if (kbinput == main_list[i].val ||
2374 (main_list[i].misc1 && kbinput == main_list[i].misc1) ||
2375 (main_list[i].misc2 && kbinput == main_list[i].misc2)) {
2376 if (ISSET(VIEW_MODE) && !main_list[i].viewok)
2377 print_view_warning();
2378 else
2379 main_list[i].func();
2380 keyhandled = 1;
2381 }
2382 }
Chris Allegretta9239d742000-09-06 15:19:18 +00002383#ifndef _POSIX_VDISABLE
2384 /* Since we're in raw mode, we have to catch ^Q and ^S */
2385 if (kbinput == 17 || kbinput == 19)
2386 keyhandled = 1;
2387
2388 /* And catch ^Z by hand when triggered */
2389 if (kbinput == 26) {
2390 if (ISSET(SUSPEND))
2391 do_suspend(0);
2392 keyhandled = 1;
2393 }
2394#endif
2395
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002396 /* Last gasp, stuff that's not in the main lists */
2397 if (!keyhandled)
2398 switch (kbinput) {
2399#ifndef NANO_SMALL
2400#ifdef NCURSES_MOUSE_VERSION
2401 case KEY_MOUSE:
2402 do_mouse();
2403 break;
2404#endif
2405#endif
2406 case 0: /* Erg */
2407 do_next_word();
2408 break;
2409 case 331: /* Stuff that we don't want to do squat */
2410 case -1:
2411 case 410: /* Must ignore this, it gets sent when we resize */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002412#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002413 case 541: /* ???? */
2414 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00002415 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002416 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00002417 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002418#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002419
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002420 break;
2421 default:
2422#ifdef DEBUG
2423 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
2424#endif
2425 /* We no longer stop unhandled sequences so that people with
2426 odd character sets can type... */
2427
2428 if (ISSET(VIEW_MODE)) {
2429 print_view_warning();
2430 break;
2431 }
2432 do_char(kbinput);
2433 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002434 if (ISSET(CONSTUPDATE)) {
2435 if (ISSET(DISABLE_CURPOS))
2436 UNSET(DISABLE_CURPOS);
2437 else
2438 do_cursorpos();
2439 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002440
2441 reset_cursor();
2442 wrefresh(edit);
2443 keyhandled = 0;
2444 }
2445
2446 getchar();
2447 finish(0);
2448
2449}