blob: 6227214064093c85112f8f7e44003c0bfdf2f976 [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
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000502#ifdef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000503void nano_small_msg(void)
504{
505 statusbar("Sorry, this function not available with nano-tiny option");
506}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000507#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000508
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000509#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000510void nano_disabled_msg(void)
511{
512 statusbar("Sorry, support for this function has been disabled");
513}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000514#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000515
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000516/* The user typed a printable character; add it to the edit buffer */
517void do_char(char ch)
518{
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000519 /* magic-line: when a character is inserted on the current magic line,
520 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000521 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000522 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000523 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000524 }
525
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000526 /* More dangerousness fun =) */
527 current->data = nrealloc(current->data, strlen(current->data) + 2);
528 memmove(&current->data[current_x + 1],
529 &current->data[current_x],
530 strlen(current->data) - current_x + 1);
531 current->data[current_x] = ch;
532 do_right();
533
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000534 if (!ISSET(NO_WRAP) && (ch != '\t'))
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000535 check_wrap(current, ch);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000536 set_modified();
537 check_statblank();
538 UNSET(KEEP_CUTBUFFER);
539 totsize++;
540
541}
542
543/* Someone hits return *gasp!* */
544int do_enter(filestruct * inptr)
545{
546 filestruct *new;
547 char *tmp, *spc;
548 int extra = 0;
549
550 new = make_new_node(inptr);
551 tmp = &current->data[current_x];
552 current_x = 0;
553
554 /* Do auto-indenting, like the neolithic Turbo Pascal editor */
555 if (ISSET(AUTOINDENT)) {
556 spc = current->data;
557 if (spc) {
558 while ((*spc == ' ') || (*spc == '\t')) {
559 extra++;
560 spc++;
561 current_x++;
562 }
563 new->data = nmalloc(strlen(tmp) + extra + 1);
564 strncpy(new->data, current->data, extra);
565 strcpy(&new->data[extra], tmp);
566 }
567 } else {
568 new->data = nmalloc(strlen(tmp) + 1);
569 strcpy(new->data, tmp);
570 }
571 *tmp = 0;
572
Chris Allegrettada721be2000-07-31 01:26:42 +0000573 if (inptr->next == NULL) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574 filebot = new;
575 editbot = new;
576 }
Chris Allegretta7975ed82000-07-28 00:58:35 +0000577 splice_node(inptr, new, inptr->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000578
579 totsize++;
580 renumber(current);
581 current = new;
582 align(&current->data);
583
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000584 /* The logic here is as follows:
585 * -> If we are at the bottom of the buffer, we want to recenter
586 * (read: rebuild) the screen and forcably move the cursor.
587 * -> otherwise, we want simply to redraw the screen and update
588 * where we think the cursor is.
589 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590 if (current_y == editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +0000591 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000592 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000593 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000595 edit_refresh();
596 update_cursor();
597 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000598
599 totlines++;
600 set_modified();
601
Chris Allegrettab0ae3932000-06-15 23:39:14 +0000602 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000603 return 1;
604}
605
606int do_enter_void(void)
607{
608 return do_enter(current);
609}
610
611void do_next_word(void)
612{
Chris Allegretta9e2934f2000-12-01 23:49:48 +0000613 filestruct *fileptr, *old;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000614 int i;
615
616 if (current == NULL)
617 return;
618
Chris Allegretta9e2934f2000-12-01 23:49:48 +0000619 old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000620 i = current_x;
621 for (fileptr = current; fileptr != NULL; fileptr = fileptr->next) {
622 if (fileptr == current) {
623 while (isalnum((int) fileptr->data[i])
624 && fileptr->data[i] != 0)
625 i++;
626
627 if (fileptr->data[i] == 0) {
628 i = 0;
629 continue;
630 }
631 }
632 while (!isalnum((int) fileptr->data[i]) && fileptr->data[i] != 0)
633 i++;
634
635 if (fileptr->data[i] != 0)
636 break;
637
638 i = 0;
639 }
640 if (fileptr == NULL)
641 current = filebot;
642 else
643 current = fileptr;
644
645 current_x = i;
646 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +0000647
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000648 if (current->lineno >= editbot->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000649 edit_update(current, CENTER);
Chris Allegretta9e2934f2000-12-01 23:49:48 +0000650 else {
651 /* If we've jumped lines, refresh the old line. We can't just use
652 * current->prev here, because we may have skipped over some blank
653 * lines, in which case the previous line is the wrong one.
654 */
655 if (current != old)
656 update_line(old, 0);
657
658 update_line(current, current_x);
659 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000660
661}
662
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000663void do_wrap(filestruct * inptr, char input_char)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000664{
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000665 int i = 0; /* Index into ->data for line. */
666 int i_tabs = 0; /* Screen position of ->data[i]. */
667 int last_word_end = -1; /* Location of end of last word found. */
668 int current_word_start = -1; /* Location of start of current word. */
669 int current_word_start_t = -1; /* Location of start of current word screen position. */
670 int current_word_end = -1; /* Location of end of current word */
671 int current_word_end_t = -1; /* Location of end of current word screen position. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000672 int len = strlen(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000673
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000674 int down = 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000675 int right = 0;
676 struct filestruct *temp = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000677
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000678 assert(strlenpt(inptr->data) > fill);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000679
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000680 for (i = 0, i_tabs = 0; i < len; i++, i_tabs++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000681 if (!isspace((int) inptr->data[i])) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000682 last_word_end = current_word_end;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000683
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000684 current_word_start = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000685 current_word_start_t = i_tabs;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000686
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000687 while (!isspace((int) inptr->data[i])
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000688 && inptr->data[i]) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000689 i++;
690 i_tabs++;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000691 if (inptr->data[i] < 32)
692 i_tabs++;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000693 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000694
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000695 if (inptr->data[i]) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000696 current_word_end = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000697 current_word_end_t = i_tabs;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000698 } else {
699 current_word_end = i - 1;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000700 current_word_end_t = i_tabs - 1;
701 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000702 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000703
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000704 if (inptr->data[i] == NANO_CONTROL_I) {
Chris Allegretta6d690a32000-08-03 22:51:21 +0000705 if (i_tabs % tabsize != 0);
706 i_tabs += tabsize - (i_tabs % tabsize);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000707 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000708
Adam Rogoyski09f97962000-06-20 02:50:33 +0000709 if (current_word_end_t > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000710 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000711 }
712
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000713 /* There are a few (ever changing) cases of what the line could look like.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000714 * 1) only one word on the line before wrap point.
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000715 * a) one word takes up the whole line with no starting spaces.
716 * - do nothing and return.
717 * b) cursor is on word or before word at wrap point and there are spaces at beginning.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000718 * - word starts new line.
719 * - keep white space on original line up to the cursor.
720 * *) cursor is after word at wrap point
721 * - either it's all white space after word, and this routine isn't called.
722 * - or we are actually in case 2 (2 words).
723 * 2) Two or more words on the line before wrap point.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000724 * a) cursor is at a word or space before wrap point
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000725 * - word at wrap point starts a new line.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000726 * - white space at end of original line is cleared, unless
727 * it is all spaces between previous word and next word which appears after fill.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000728 * b) cursor is at the word at the wrap point.
729 * - word at wrap point starts a new line.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000730 * 1. pressed a space and at first character of wrap point word.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000731 * - white space on original line is kept to where cursor was.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000732 * 2. pressed non space (or space elsewhere).
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000733 * - white space at end of original line is cleared.
734 * c) cursor is past the word at the wrap point.
735 * - word at wrap point starts a new line.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000736 * - white space at end of original line is cleared
737 */
738
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000739 temp = nmalloc(sizeof(filestruct));
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000740
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000741 /* Category 1a: one word taking up the whole line with no beginning spaces. */
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000742 if ((last_word_end == -1) && (!isspace((int) inptr->data[0]))) {
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000743 for (i = current_word_end; i < len; i++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000744 if (!isspace((int) inptr->data[i]) && i < len) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000745 current_word_start = i;
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000746 while (!isspace((int) inptr->data[i]) && (i < len)) {
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000747 i++;
748 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000749 last_word_end = current_word_end;
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000750 current_word_end = i;
751 break;
752 }
753 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000754
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000755 if (last_word_end == -1) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000756 free(temp);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000757 return;
758 }
759 if (current_x >= last_word_end) {
760 right = (current_x - current_word_start) + 1;
761 current_x = last_word_end;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000762 down = 1;
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000763 }
764
765 temp->data = nmalloc(strlen(&inptr->data[current_word_start]) + 1);
766 strcpy(temp->data, &inptr->data[current_word_start]);
767 inptr->data = nrealloc(inptr->data, last_word_end + 2);
768 inptr->data[last_word_end + 1] = 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000769 } else
770 /* Category 1b: one word on the line and word not taking up whole line
771 (i.e. there are spaces at the beginning of the line) */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000772 if (last_word_end == -1) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000773 temp->data = nmalloc(strlen(&inptr->data[current_word_start]) + 1);
774 strcpy(temp->data, &inptr->data[current_word_start]);
775
776 /* Inside word, remove it from original, and move cursor to right spot. */
777 if (current_x >= current_word_start) {
778 right = current_x - current_word_start;
779 current_x = 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000780 down = 1;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000781 }
782
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000783 null_at(inptr->data, current_x);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000784
785 if (ISSET(MARK_ISSET) && (mark_beginbuf == inptr)) {
786 mark_beginbuf = temp;
787 mark_beginx = 0;
788 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000789 }
790
791 /* Category 2: two or more words on the line. */
792 else {
793
794 /* Case 2a: cursor before word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000795 if (current_x < current_word_start) {
796 temp->data =
797 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
798 strcpy(temp->data, &inptr->data[current_word_start]);
799
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000800 if (!isspace((int) input_char)) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000801 i = current_word_start - 1;
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000802 while (isspace((int) inptr->data[i])) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000803 i--;
804 assert(i >= 0);
805 }
806 } else if (current_x <= last_word_end)
807 i = last_word_end - 1;
808 else
809 i = current_x;
810
811 inptr->data = nrealloc(inptr->data, i + 2);
812 inptr->data[i + 1] = 0;
813 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000814
815
816 /* Case 2b: cursor at word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000817 else if ((current_x >= current_word_start)
818 && (current_x <= (current_word_end + 1))) {
819 temp->data =
820 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000821 strcpy(temp->data, &inptr->data[current_word_start]);
822
823 down = 1;
824
825 right = current_x - current_word_start;
826 i = current_word_start - 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000827 if (isspace((int) input_char)
828 && (current_x == current_word_start)) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000829 current_x = current_word_start;
830
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000831 null_at(inptr->data, current_word_start);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000832 } else {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000833
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000834 while (isspace((int) inptr->data[i])) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000835 i--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000836 assert(i >= 0);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000837 }
838 inptr->data = nrealloc(inptr->data, i + 2);
839 inptr->data[i + 1] = 0;
840 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000841 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000842
843
844 /* Case 2c: cursor past word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000845 else {
846 temp->data =
847 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000848 strcpy(temp->data, &inptr->data[current_word_start]);
849
850 down = 1;
851 right = current_x - current_word_start;
852
853 current_x = current_word_start;
854 i = current_word_start - 1;
855
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000856 while (isspace((int) inptr->data[i])) {
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000857 i--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000858 assert(i >= 0);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000859 inptr->data = nrealloc(inptr->data, i + 2);
860 inptr->data[i + 1] = 0;
861 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000862 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000863 }
864
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000865 /* We pre-pend wrapped part to next line. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000866 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000867 /* Plus one for the space which concatenates the two lines together plus 1 for \0. */
868 char *p =
869 nmalloc(strlen(temp->data) + strlen(inptr->next->data) + 2);
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000870 int old_x = current_x, old_y = current_y;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000871
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000872 strcpy(p, temp->data);
873 strcat(p, " ");
874 strcat(p, inptr->next->data);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000875
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000876 free(inptr->next->data);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000877 inptr->next->data = p;
878
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000879 free(temp->data);
880 free(temp);
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000881
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000882 current_x = old_x;
883 current_y = old_y;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000884 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000885 /* Else we start a new line. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000886 else {
887 temp->prev = inptr;
888 temp->next = inptr->next;
889
890 if (inptr->next)
891 inptr->next->prev = temp;
892 inptr->next = temp;
893
894 if (!temp->next)
895 filebot = temp;
896
897 SET(SAMELINEWRAP);
898 }
899
900
901 totlines++;
Robert Siemborskia417ddc2000-07-24 23:18:48 +0000902 /* Everything about it makes me want this line here but it causes
903 * totsize to be high by one for some reason. Sigh. (Rob) */
904 /* totsize++; */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000905
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000906 renumber(inptr);
Chris Allegretta234a34d2000-07-29 04:33:38 +0000907 edit_update(edittop, TOP);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000908
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000909
910 /* Move the cursor to the new line if appropriate. */
911 if (down) {
912 do_right();
913 }
914
915 /* Move the cursor to the correct spot in the line if appropriate. */
916 while (right--) {
917 do_right();
918 }
919
Chris Allegretta234a34d2000-07-29 04:33:38 +0000920 edit_update(edittop, TOP);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000921 reset_cursor();
922 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000923}
924
925/* Check to see if we've just caused the line to wrap to a new line */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000926void check_wrap(filestruct * inptr, char ch)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000927{
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000928 int len = strlenpt(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000929#ifdef DEBUG
930 fprintf(stderr, _("check_wrap called with inptr->data=\"%s\"\n"),
931 inptr->data);
932#endif
933
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000934 if (len <= fill)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000935 return;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000936 else {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000937 int i = actual_x(inptr, fill);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000938
939 /* Do not wrap if there are no words on or after wrap point. */
Adam Rogoyski09f97962000-06-20 02:50:33 +0000940 int char_found = 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000941
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000942 while (isspace((int) inptr->data[i]) && inptr->data[i])
Adam Rogoyski09f97962000-06-20 02:50:33 +0000943 i++;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000944
Adam Rogoyski09f97962000-06-20 02:50:33 +0000945 if (!inptr->data[i])
946 return;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000947
Adam Rogoyski09f97962000-06-20 02:50:33 +0000948 /* String must be at least 1 character long. */
949 for (i = strlen(inptr->data) - 1; i >= 0; i--) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +0000950 if (isspace((int) inptr->data[i])) {
Adam Rogoyski09f97962000-06-20 02:50:33 +0000951 if (!char_found)
952 continue;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000953 char_found = 2; /* 2 for yes do wrap. */
Adam Rogoyski09f97962000-06-20 02:50:33 +0000954 break;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000955 } else
956 char_found = 1; /* 1 for yes found a word, but must check further. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000957 }
Adam Rogoyski09f97962000-06-20 02:50:33 +0000958
959 if (char_found == 2)
960 do_wrap(inptr, ch);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000961 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000962}
963
964/* Stuff we do when we abort from programs and want to clean up the
965 * screen. This doesnt do much right now.
966 */
967void do_early_abort(void)
968{
969 blank_statusbar_refresh();
970}
971
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000972int do_backspace(void)
973{
974 filestruct *previous, *tmp;
975
976 if (current_x != 0) {
977 /* Let's get dangerous */
978 memmove(&current->data[current_x - 1], &current->data[current_x],
979 strlen(current->data) - current_x + 1);
980#ifdef DEBUG
981 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
982#endif
983 align(&current->data);
984 do_left();
985 } else {
986 if (current == fileage)
987 return 0; /* Can't delete past top of file */
988
989 previous = current->prev;
990 current_x = strlen(previous->data);
991 previous->data = nrealloc(previous->data,
992 strlen(previous->data) +
993 strlen(current->data) + 1);
994 strcat(previous->data, current->data);
995
996 tmp = current;
997 unlink_node(current);
998 delete_node(current);
999 if (current == edittop) {
1000 if (previous->next)
1001 current = previous->next;
1002 else
1003 current = previous;
Chris Allegrettada721be2000-07-31 01:26:42 +00001004 page_up_center();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001005 } else {
1006 if (previous->next)
1007 current = previous->next;
1008 else
1009 current = previous;
1010 update_line(current, current_x);
1011 }
1012
1013 /* Ooops, sanity check */
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001014 if (tmp == filebot) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001015 filebot = current;
1016 editbot = current;
Chris Allegretta28a0f892000-07-05 22:47:54 +00001017
1018 /* Recreate the magic line if we're deleting it AND if the
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001019 line we're on now is NOT blank. if it is blank we
1020 can just use IT for the magic line. This is how Pico
1021 appears to do it, in any case */
Chris Allegretta28a0f892000-07-05 22:47:54 +00001022 if (strcmp(current->data, "")) {
1023 new_magicline();
1024 fix_editbot();
Chris Allegretta55373872000-07-06 22:38:37 +00001025 totsize++;
Chris Allegretta28a0f892000-07-05 22:47:54 +00001026 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001027 }
1028
1029 current = previous;
1030 renumber(current);
1031 previous_line();
1032 totlines--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001033#ifdef DEBUG
1034 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1035#endif
1036
1037 }
1038
1039 totsize--;
1040 set_modified();
1041 UNSET(KEEP_CUTBUFFER);
1042 edit_refresh();
1043 return 1;
1044}
1045
1046int do_delete(void)
1047{
1048 filestruct *foo;
1049
1050 if (current_x != strlen(current->data)) {
1051 /* Let's get dangerous */
1052 memmove(&current->data[current_x], &current->data[current_x + 1],
1053 strlen(current->data) - current_x);
1054
1055 align(&current->data);
1056
1057 } else if (current->next != NULL) {
1058 current->data = nrealloc(current->data,
1059 strlen(current->data) +
1060 strlen(current->next->data) + 1);
1061 strcat(current->data, current->next->data);
1062
1063 foo = current->next;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001064 if (filebot == foo) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001065 filebot = current;
1066 editbot = current;
1067 }
1068
1069 unlink_node(foo);
1070 delete_node(foo);
1071 update_line(current, current_x);
1072
Chris Allegretta28a0f892000-07-05 22:47:54 +00001073 /* Please see the comment in do_basckspace if you don't understand
1074 this test */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001075 if (current == filebot && strcmp(current->data, "")) {
Chris Allegretta28a0f892000-07-05 22:47:54 +00001076 new_magicline();
1077 fix_editbot();
Chris Allegretta55373872000-07-06 22:38:37 +00001078 totsize++;
Chris Allegretta28a0f892000-07-05 22:47:54 +00001079 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001080 renumber(current);
1081 totlines--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001082 } else
1083 return 0;
1084
1085 totsize--;
1086 set_modified();
1087 UNSET(KEEP_CUTBUFFER);
1088 edit_refresh();
1089 return 1;
1090}
1091
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001092void wrap_reset(void)
1093{
1094 UNSET(SAMELINEWRAP);
1095}
1096
Chris Allegrettaff269f82000-12-01 18:46:01 +00001097#if !defined(NANO_SMALL) && !defined(DISABLE_SPELL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001098
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001099int do_int_spell_fix(char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001100{
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001101 char *prevanswer = NULL, *save_search = NULL, *save_replace = NULL;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001102 filestruct *begin;
1103 int i = 0, j = 0, beginx, beginx_top;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001104
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001105 /* save where we are */
1106 begin = current;
1107 beginx = current_x + 1;
1108
1109 /* save the current search/replace strings */
1110 search_init_globals();
1111 save_search = mallocstrcpy(save_search, last_search);
1112 save_replace = mallocstrcpy(save_replace, last_replace);
1113
1114 /* set search/replace strings to mis-spelt word */
1115 prevanswer = mallocstrcpy(prevanswer, word);
1116 last_search = mallocstrcpy(last_search, word);
1117 last_replace = mallocstrcpy(last_replace, word);
1118
1119 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001120 current = fileage;
1121 current_x = beginx_top = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001122
1123 search_last_line = FALSE;
1124
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001125 edit_update(fileage, TOP);
1126
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001127 /* make sure word is still mis-spelt (i.e. when multi-errors) */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001128 if (findnextstr(TRUE, fileage, beginx_top, prevanswer) != NULL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001129 {
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001130 do_replace_highlight(TRUE, prevanswer);
1131
1132 /* allow replace word to be corrected */
1133 i = statusq(0, spell_list, SPELL_LIST_LEN, last_replace,
1134 _("Edit a replacement"));
1135
1136 do_replace_highlight(FALSE, prevanswer);
1137
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001138 /* start from the start of this line again */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001139 current = fileage;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001140 current_x = beginx_top;
1141
1142 search_last_line = FALSE;
1143
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001144 j = i;
1145 do_replace_loop(prevanswer, fileage, &beginx_top, TRUE, &j);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001146 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001147
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001148 /* restore the search/replace strings */
1149 last_search = mallocstrcpy(last_search, save_search);
1150 last_replace = mallocstrcpy(last_replace, save_replace);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001151
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001152 /* restore where we were */
1153 current = begin;
1154 current_x = beginx - 1;
1155
1156 edit_update(current, CENTER);
1157
1158 if (i == -1)
1159 return FALSE;
1160
1161 return TRUE;
1162}
1163#endif
1164
Chris Allegrettaff269f82000-12-01 18:46:01 +00001165#if !defined(NANO_SMALL) && !defined(DISABLE_SPELL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001166
1167/* Integrated spell checking using 'spell' program */
Chris Allegretta271e9722000-11-10 18:15:43 +00001168int do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001169{
Chris Allegretta271e9722000-11-10 18:15:43 +00001170 char *read_buff, *read_buff_ptr, *read_buff_word;
1171 long pipe_buff_size;
1172 int in_fd[2], tempfile_fd;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001173 int spell_status;
1174 pid_t pid_spell;
1175 ssize_t bytesread;
1176
Chris Allegretta271e9722000-11-10 18:15:43 +00001177 /* Create a pipe to spell program */
1178
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001179 if (pipe(in_fd) == -1)
1180 return FALSE;
1181
Chris Allegretta271e9722000-11-10 18:15:43 +00001182 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001184 if ( (pid_spell = fork()) == 0) {
1185
1186 /* Child continues, (i.e. future spell process) */
1187
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001188 close(in_fd[0]);
1189
Chris Allegretta271e9722000-11-10 18:15:43 +00001190 /* replace the standard in with the tempfile */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001191
Chris Allegretta271e9722000-11-10 18:15:43 +00001192 if ( (tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) {
1193
1194 close(in_fd[1]);
1195 exit(1);
1196 }
1197
1198 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) {
1199
1200 close(tempfile_fd);
1201 close(in_fd[1]);
1202 exit(1);
1203 }
1204 close(tempfile_fd);
1205
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001206
Chris Allegretta271e9722000-11-10 18:15:43 +00001207 /* send spell's standard out to the pipe */
1208
1209 if (dup2(in_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1210
1211 close(in_fd[1]);
1212 exit(1);
1213 }
1214 close(in_fd[1]);
1215
1216 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001217 execlp("spell", "spell", NULL);
1218
Chris Allegretta271e9722000-11-10 18:15:43 +00001219 /* Should not be reached, if spell is found!!! */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001220
Chris Allegretta271e9722000-11-10 18:15:43 +00001221 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001222 }
1223
1224 /* Parent continues here */
1225
Chris Allegretta271e9722000-11-10 18:15:43 +00001226 close(in_fd[1]);
1227
1228 /* Child process was not forked successfully */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001229
1230 if (pid_spell < 0) {
1231
Chris Allegretta271e9722000-11-10 18:15:43 +00001232 close(in_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001233 return FALSE;
1234 }
1235
Chris Allegretta271e9722000-11-10 18:15:43 +00001236 /* Get system pipe buffer size */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001237
Chris Allegretta271e9722000-11-10 18:15:43 +00001238 if ( (pipe_buff_size = fpathconf(in_fd[0], _PC_PIPE_BUF)) < 1) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001239
Chris Allegretta271e9722000-11-10 18:15:43 +00001240 close(in_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001241 return FALSE;
Chris Allegretta271e9722000-11-10 18:15:43 +00001242 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001243
Chris Allegretta271e9722000-11-10 18:15:43 +00001244 read_buff = nmalloc( pipe_buff_size + 1 );
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001245
Chris Allegretta271e9722000-11-10 18:15:43 +00001246 /* Process the returned spelling errors */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001247
Chris Allegretta271e9722000-11-10 18:15:43 +00001248 while ( (bytesread = read(in_fd[0], read_buff, pipe_buff_size)) > 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001249
Chris Allegretta271e9722000-11-10 18:15:43 +00001250 read_buff[bytesread] = (char) NULL;
1251 read_buff_word = read_buff_ptr = read_buff;
1252
1253 while (*read_buff_ptr != (char) NULL) {
1254
1255 /* Windows version may need to process additional char '\r' */
1256
1257 /* Possible problem here if last word not followed by '\n' */
1258
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001259 if (*read_buff_ptr == '\n') {
Chris Allegretta271e9722000-11-10 18:15:43 +00001260 *read_buff_ptr = (char) NULL;
1261 if (!do_int_spell_fix(read_buff_word)) {
1262
1263 close(in_fd[0]);
1264 free(read_buff);
1265 replace_abort();
1266
1267 return TRUE;
1268 }
1269 read_buff_word = read_buff_ptr;
1270 read_buff_word++;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001271 }
1272
1273 read_buff_ptr++;
1274 }
1275 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001276
1277 close(in_fd[0]);
1278 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001279 replace_abort();
1280
Chris Allegretta271e9722000-11-10 18:15:43 +00001281 /* Process end of spell process */
1282
1283 wait(&spell_status);
1284 if (WIFEXITED(spell_status)) {
1285 if (WEXITSTATUS(spell_status) != 0)
1286 return FALSE;
1287 }
1288 else
1289 return FALSE;
1290
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001291 return TRUE;
1292}
1293#endif
1294
Chris Allegrettaff269f82000-12-01 18:46:01 +00001295#if !defined(NANO_SMALL) && !defined(DISABLE_SPELL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001296
1297/* External spell checking */
Chris Allegretta271e9722000-11-10 18:15:43 +00001298int do_alt_speller(char *file_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001299{
Chris Allegretta271e9722000-11-10 18:15:43 +00001300 int alt_spell_status;
1301 pid_t pid_spell;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001302
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001303 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001304
Chris Allegretta271e9722000-11-10 18:15:43 +00001305 /* Start a new process for the alternate speller */
1306
1307 if ( (pid_spell = fork()) == 0) {
1308
1309 /* Start alternate spell program, we are using the PATH here!?!? */
1310 execlp(alt_speller, alt_speller, file_name, NULL);
1311
1312 /* Should not be reached, if alternate speller is found!!! */
1313
1314 exit(1);
1315 }
1316
1317 /* Could not fork?? */
1318
1319 if (pid_spell < 0)
1320 return FALSE;
1321
1322 /* Wait for alternate speller to complete */
1323
1324 wait(&alt_spell_status);
1325 if (WIFEXITED(alt_spell_status)) {
1326 if (WEXITSTATUS(alt_spell_status) != 0)
1327 return FALSE;
1328 }
1329 else
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001330 return FALSE;
1331
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001332 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001333 free_filestruct(fileage);
1334 global_init();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001335 open_file(file_name, 0, 1);
Chris Allegretta234a34d2000-07-29 04:33:38 +00001336 edit_update(fileage, CENTER);
Chris Allegretta271e9722000-11-10 18:15:43 +00001337 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001338 set_modified();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001339
1340 return TRUE;
1341}
1342#endif
1343
1344int do_spell(void)
1345{
1346
Chris Allegrettaff269f82000-12-01 18:46:01 +00001347#if defined(NANO_SMALL)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001348 nano_small_msg();
1349 return (TRUE);
Chris Allegrettaff269f82000-12-01 18:46:01 +00001350#elif defined(DISABLE_SPELL)
1351 nano_disabled_msg();
1352 return (TRUE);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001353#else
Chris Allegretta271e9722000-11-10 18:15:43 +00001354 char *temp;
1355 int spell_res;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001356
Chris Allegretta271e9722000-11-10 18:15:43 +00001357 if ((temp = tempnam(0, "nano.")) == NULL) {
1358 statusbar(_("Could not create a temporary filename: %s"),
1359 strerror(errno));
1360 return 0;
1361 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001362
Chris Allegretta271e9722000-11-10 18:15:43 +00001363 if (write_file(temp, 1) == -1)
1364 return 0;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001365
Chris Allegretta271e9722000-11-10 18:15:43 +00001366 if (alt_speller)
1367 spell_res = do_alt_speller(temp);
1368 else
1369 spell_res = do_int_speller(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001370
Chris Allegretta271e9722000-11-10 18:15:43 +00001371 remove(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001372
1373 if (spell_res)
1374 statusbar(_("Finished checking spelling"));
1375 else
1376 statusbar(_("Spell checking failed"));
1377
1378 return spell_res;
1379
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001380#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001381}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001382
1383int do_exit(void)
1384{
1385 int i;
1386
1387 if (!ISSET(MODIFIED))
1388 finish(0);
1389
Chris Allegretta30885552000-07-14 01:20:12 +00001390 if (ISSET(TEMP_OPT)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001391 i = 1;
1392 } else {
1393 i =
1394 do_yesno(0, 0,
1395 _
1396 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
1397 }
1398
1399#ifdef DEBUG
1400 dump_buffer(fileage);
1401#endif
1402
1403 if (i == 1) {
1404 if (do_writeout(1) > 0)
1405 finish(0);
1406 } else if (i == 0)
1407 finish(0);
1408 else
1409 statusbar(_("Cancelled"));
1410
1411 display_main_list();
1412 return 1;
1413}
1414
1415#ifndef NANO_SMALL
1416#ifdef NCURSES_MOUSE_VERSION
1417void do_mouse(void)
1418{
1419 MEVENT mevent;
Chris Allegrettae10debd2000-08-22 01:26:42 +00001420 int foo = 0, tab_found = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001421
1422 if (getmouse(&mevent) == ERR)
1423 return;
1424
1425 /* If mouse not in edit window, return (add help selection later). */
1426 if (!wenclose(edit, mevent.y, mevent.x))
1427 return;
1428
1429 /* Subtract out size of topwin. Perhaps we need a constant somewhere? */
1430 mevent.y -= 2;
1431
1432 /* Selecting where the cursor is sets the mark.
1433 * Selecting beyond the line length with the cursor at the end of the
1434 * line sets the mark as well.
1435 */
1436 if ((mevent.y == current_y) &&
1437 ((mevent.x == current_x) || (current_x == strlen(current->data)
1438 && (mevent.x >
1439 strlen(current->data))))) {
1440 if (ISSET(VIEW_MODE)) {
1441 print_view_warning();
1442 return;
1443 }
1444 do_mark();
1445 } else if (mevent.y > current_y) {
1446 while (mevent.y > current_y) {
1447 if (current->next != NULL)
1448 current = current->next;
1449 else
1450 break;
1451 current_y++;
1452 }
1453 } else if (mevent.y < current_y) {
1454 while (mevent.y < current_y) {
1455 if (current->prev != NULL)
1456 current = current->prev;
1457 else
1458 break;
1459 current_y--;
1460 }
1461 }
1462 current_x = mevent.x;
Chris Allegrettae10debd2000-08-22 01:26:42 +00001463 placewewant = current_x;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001464 while (foo < current_x) {
1465 if (current->data[foo] == NANO_CONTROL_I) {
Chris Allegrettae10debd2000-08-22 01:26:42 +00001466 current_x -= tabsize - (foo % tabsize);
1467 tab_found = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001468 } else if (current->data[foo] & 0x80);
1469 else if (current->data[foo] < 32)
Chris Allegrettae10debd2000-08-22 01:26:42 +00001470 current_x--;
1471 foo++;
1472 }
1473 /* This is where tab_found comes in. I can't figure out why,
1474 * but without it any line with a tab will place the cursor
1475 * one character behind. Whatever, this fixes it. */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001476 if (tab_found == 1)
Chris Allegrettae10debd2000-08-22 01:26:42 +00001477 current_x++;
1478
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001479 if (current_x > strlen(current->data))
1480 current_x = strlen(current->data);
1481
1482 update_cursor();
1483 edit_refresh();
1484
1485}
1486#endif
1487#endif
1488
1489/* Handler for SIGHUP */
1490RETSIGTYPE handle_hup(int signal)
1491{
1492 write_file("nano.save", 0);
1493 finish(1);
1494}
1495
Chris Allegretta18f8be02000-09-04 03:20:38 +00001496/* What do we do when we catch the suspend signal */
1497RETSIGTYPE do_suspend(int signal)
1498{
1499
1500 act.sa_handler = SIG_DFL;
1501 sigemptyset(&act.sa_mask);
1502 sigaction(SIGTSTP, &act, NULL);
1503
1504 endwin();
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001505 fprintf(stderr, "\n\n\n\n\nUse \"fg\" to return to nano\n");
Chris Allegretta18f8be02000-09-04 03:20:38 +00001506 raise(SIGTSTP);
1507}
1508
1509/* Restore the suspend handler when we come back into the prog */
1510RETSIGTYPE do_cont(int signal)
1511{
1512
1513 act.sa_handler = do_suspend;
1514 sigemptyset(&act.sa_mask);
1515 sigaction(SIGTSTP, &act, NULL);
1516 initscr();
1517 total_refresh();
1518}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001519
1520void handle_sigwinch(int s)
1521{
1522#ifndef NANO_SMALL
1523 char *tty = NULL;
1524 int fd = 0;
1525 int result = 0;
1526 int i = 0;
1527 struct winsize win;
1528
1529 tty = ttyname(0);
1530 if (!tty)
1531 return;
1532 fd = open(tty, O_RDWR);
1533 if (fd == -1)
1534 return;
1535 result = ioctl(fd, TIOCGWINSZ, &win);
1536 if (result == -1)
1537 return;
1538
1539
1540 COLS = win.ws_col;
1541 LINES = win.ws_row;
1542
1543 center_x = COLS / 2;
1544 center_y = LINES / 2;
1545 editwinrows = LINES - 5 + no_help();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001546 fill = COLS - 8;
1547
1548 free(hblank);
1549 hblank = nmalloc(COLS + 1);
1550
1551 for (i = 0; i <= COLS - 1; i++)
1552 hblank[i] = ' ';
1553 hblank[i] = 0;
1554
1555#ifdef HAVE_NCURSES_H
1556 resizeterm(LINES, COLS);
1557#ifdef HAVE_WRESIZE
1558 if (wresize(topwin, 2, COLS) == ERR)
1559 die(_("Cannot resize top win"));
1560 if (mvwin(topwin, 0, 0) == ERR)
1561 die(_("Cannot move top win"));
1562 if (wresize(edit, editwinrows, COLS) == ERR)
1563 die(_("Cannot resize edit win"));
1564 if (mvwin(edit, 2, 0) == ERR)
1565 die(_("Cannot move edit win"));
1566 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
1567 die(_("Cannot resize bottom win"));
1568 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
1569 die(_("Cannot move bottom win"));
1570#endif /* HAVE_WRESIZE */
1571#endif /* HAVE_NCURSES_H */
1572
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001573 fix_editbot();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001574
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001575 if (current_y > editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001576 edit_update(editbot, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001577 }
1578 erase();
Chris Allegretta97accc62000-06-19 05:45:52 +00001579
1580 /* Do these b/c width may have changed... */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001581 refresh();
Chris Allegretta97accc62000-06-19 05:45:52 +00001582 titlebar();
1583 edit_refresh();
1584 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001585 total_refresh();
1586#endif
1587}
1588
Chris Allegretta756f2202000-09-01 13:32:47 +00001589void signal_init(void)
1590{
Chris Allegretta756f2202000-09-01 13:32:47 +00001591
1592 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
1593 memset(&act, 0, sizeof(struct sigaction));
1594 act.sa_handler = SIG_IGN;
1595 sigaction(SIGINT, &act, NULL);
Chris Allegretta756f2202000-09-01 13:32:47 +00001596
Chris Allegretta18f8be02000-09-04 03:20:38 +00001597 if (!ISSET(SUSPEND)) {
Chris Allegretta756f2202000-09-01 13:32:47 +00001598 sigaction(SIGTSTP, &act, NULL);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001599 } else {
Chris Allegretta18f8be02000-09-04 03:20:38 +00001600 act.sa_handler = do_suspend;
1601 sigaction(SIGTSTP, &act, NULL);
1602
1603 act.sa_handler = do_cont;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001604 sigaction(SIGCONT, &act, NULL);
Chris Allegretta18f8be02000-09-04 03:20:38 +00001605 }
1606
Chris Allegretta756f2202000-09-01 13:32:47 +00001607
1608 /* Trap SIGHUP cuz we want to write the file out. */
1609 act.sa_handler = handle_hup;
1610 sigaction(SIGHUP, &act, NULL);
1611
1612 act.sa_handler = handle_sigwinch;
1613 sigaction(SIGWINCH, &act, NULL);
1614
1615}
1616
Chris Allegretta2a42af12000-09-12 23:02:49 +00001617void window_init(void)
1618{
Chris Allegretta92c9dd22000-09-13 14:03:27 +00001619 editwinrows = LINES - 5 + no_help();
1620
Chris Allegretta2a42af12000-09-12 23:02:49 +00001621 /* Setup up the main text window */
1622 edit = newwin(editwinrows, COLS, 2, 0);
1623
1624 /* And the other windows */
1625 topwin = newwin(2, COLS, 0, 0);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001626 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001627}
1628
Chris Allegretta756f2202000-09-01 13:32:47 +00001629void mouse_init(void)
1630{
1631#ifndef NANO_SMALL
1632#ifdef NCURSES_MOUSE_VERSION
1633 if (ISSET(USE_MOUSE)) {
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +00001634 keypad_on(TRUE);
Chris Allegretta0b88ce02000-09-15 15:46:32 +00001635
Chris Allegretta756f2202000-09-01 13:32:47 +00001636 mousemask(BUTTON1_RELEASED, NULL);
1637 mouseinterval(50);
Chris Allegretta0b88ce02000-09-15 15:46:32 +00001638
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001639 } else {
Chris Allegretta756f2202000-09-01 13:32:47 +00001640 mousemask(0, NULL);
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +00001641 keypad_on(FALSE);
Chris Allegretta756f2202000-09-01 13:32:47 +00001642 }
1643#endif
1644#endif
1645
1646}
1647
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001648int do_tab(void)
1649{
1650 do_char('\t');
1651 return 1;
1652}
1653
Chris Allegrettaff269f82000-12-01 18:46:01 +00001654#if !defined(NANO_SMALL) && !defined(DISABLE_JUSTIFY)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001655int empty_line(const char *data)
1656{
1657 while (*data) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001658 if (!isspace((int) *data))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001659 return 0;
1660
1661 data++;
1662 }
1663
1664 return 1;
1665}
1666
1667int no_spaces(const char *data)
1668{
1669 while (*data) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001670 if (isspace((int) *data))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001671 return 0;
1672
1673 data++;
1674 }
1675
1676 return 1;
1677}
1678
1679void justify_format(char *data)
1680{
1681 int i = 0;
1682 int len = strlen(data);
1683
1684 /* Skip first character regardless and leading whitespace. */
1685 for (i = 1; i < len; i++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001686 if (!isspace((int) data[i]))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001687 break;
1688 }
1689
1690 i++; /* (i) is now at least 2. */
1691
1692 /* No double spaces allowed unless following a period. Tabs -> space. No double tabs. */
1693 for (; i < len; i++) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001694 if (isspace((int) data[i]) && isspace((int) data[i - 1])
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001695 && (data[i - 2] != '.')) {
1696 memmove(data + i, data + i + 1, len - i);
1697 len--;
1698 i--;
1699 }
1700 }
1701}
1702#endif
1703
1704int do_justify(void)
1705{
Chris Allegrettaff269f82000-12-01 18:46:01 +00001706#ifdef NANO_SMALL
1707 nano_small_msg();
1708 return 1;
1709#elif defined(DISABLE_JUSTIFY)
1710 nano_disabled_msg();
1711 return 1;
1712#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001713 int slen = 0; /* length of combined lines on one line. */
Chris Allegretta9149e612000-11-27 00:23:41 +00001714 int initial_y, kbinput;
1715 filestruct *initial = NULL, *tmpjust = NULL, *cutbak, *tmptop, *tmpbot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001716
1717 if (empty_line(current->data)) {
1718 /* Justify starting at first non-empty line. */
1719 do {
1720 if (!current->next)
1721 return 1;
1722
1723 current = current->next;
1724 current_y++;
1725 }
1726 while (empty_line(current->data));
1727 } else {
1728 /* Search back for the beginning of the paragraph, where
1729 * Paragraph is 1) A line with leading whitespace
1730 * or 2) A line following an empty line.
1731 */
1732 while (current->prev != NULL) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001733 if (isspace((int) current->data[0]) || !current->data[0])
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001734 break;
1735
1736 current = current->prev;
1737 current_y--;
1738 }
1739
1740 /* First line with leading whitespace may be empty. */
1741 if (empty_line(current->data)) {
1742 if (current->next) {
1743 current = current->next;
1744 current_y++;
1745 } else
1746 return 1;
1747 }
1748 }
1749 initial = current;
1750 initial_y = current_y;
1751
1752 set_modified();
Chris Allegretta9149e612000-11-27 00:23:41 +00001753 cutbak = cutbuffer; /* Got to like cutbak ;) */
1754 cutbuffer = NULL;
1755
1756 tmptop = current;
1757 tmpjust = copy_node(current);
1758 add_to_cutbuffer(tmpjust);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001759 /* Put the whole paragraph into one big line. */
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001760 while (current->next && !isspace((int) current->next->data[0])
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001761 && current->next->data[0]) {
1762 filestruct *tmpnode = current->next;
1763 int len = strlen(current->data);
1764 int len2 = strlen(current->next->data);
1765
Chris Allegretta9149e612000-11-27 00:23:41 +00001766 tmpjust = NULL;
Chris Allegretta9149e612000-11-27 00:23:41 +00001767 tmpjust = copy_node(current->next);
1768 add_to_cutbuffer(tmpjust);
1769
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001770 /* length of both strings plus space between strings and ending \0. */
1771 current->data = nrealloc(current->data, len + len2 + 2);
1772 current->data[len++] = ' ';
1773 current->data[len] = '\0';
1774
1775 strncat(current->data, current->next->data, len2);
1776
1777 unlink_node(tmpnode);
1778 delete_node(tmpnode);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001779 }
1780
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001781 totsize -= strlen(current->data);
1782
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001783 justify_format(current->data);
1784
1785 slen = strlen(current->data);
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001786 totsize += slen;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001787
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001788 if ((strlenpt(current->data) > (fill))
1789 && !no_spaces(current->data)) {
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001790 do {
1791 int i = 0;
1792 int len2 = 0;
1793 filestruct *tmpline = nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001794
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001795 /* Start at fill , unless line isn't that long (but it
1796 * appears at least fill long with tabs.
1797 */
1798 if (slen > fill)
1799 i = fill;
1800 else
1801 i = slen;
1802 for (; i > 0; i--) {
Chris Allegretta9e7efa32000-10-02 03:42:55 +00001803 if (isspace((int) current->data[i]) &&
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001804 ((strlenpt(current->data) - strlen(current->data + i))
1805 <= fill))
1806 break;
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001807 }
1808 if (!i)
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001809 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001810
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001811 current->data[i] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001812
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001813 len2 = strlen(current->data + i + 1);
1814 tmpline->data = nmalloc(len2 + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001815
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001816 /* Skip the white space in current. */
1817 memcpy(tmpline->data, current->data + i + 1, len2);
1818 tmpline->data[len2] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001819
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001820 current->data = nrealloc(current->data, i + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001821
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001822 tmpline->prev = current;
1823 tmpline->next = current->next;
1824 if (current->next != NULL)
1825 current->next->prev = tmpline;
1826
1827 current->next = tmpline;
1828 current = tmpline;
1829 slen -= i + 1;
1830 current_y++;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001831 } while ((strlenpt(current->data) > (fill))
1832 && !no_spaces(current->data));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001833 }
Chris Allegretta9149e612000-11-27 00:23:41 +00001834 tmpbot = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001835
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001836 if (current->next)
1837 current = current->next;
Adam Rogoyski09f97962000-06-20 02:50:33 +00001838 else
1839 filebot = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001840 current_x = 0;
1841 placewewant = 0;
1842
Adam Rogoyski09f97962000-06-20 02:50:33 +00001843 renumber(initial);
1844 totlines = filebot->lineno;
1845
1846 werase(edit);
1847
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001848 if ((current_y < 0) || (current_y >= editwinrows - 1)
1849 || (initial_y <= 0)) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001850 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001851 center_cursor();
1852 } else {
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001853 fix_editbot();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001854 }
1855
Adam Rogoyski09f97962000-06-20 02:50:33 +00001856 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00001857 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00001858 /* Change the shortcut list to display the unjustify code */
1859 shortcut_init(1);
1860 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00001861 reset_cursor();
1862
Chris Allegretta07798352000-11-27 22:58:23 +00001863 /* Now get a keystroke and see if it's unjustify, if not unget the keytroke
Chris Allegretta9149e612000-11-27 00:23:41 +00001864 and return */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00001865 if ((kbinput = wgetch(edit)) != NANO_UNJUSTIFY_KEY)
Chris Allegretta07798352000-11-27 22:58:23 +00001866 ungetch(kbinput);
Chris Allegretta9149e612000-11-27 00:23:41 +00001867 else {
1868 /* Else restore the justify we just did (ungrateful user!) */
1869 if (tmptop->prev != NULL)
1870 tmptop->prev->next = tmpbot->next;
Chris Allegrettad022eac2000-11-27 02:50:49 +00001871 else
1872 fileage = current;
Chris Allegretta9149e612000-11-27 00:23:41 +00001873 tmpbot->next->prev = tmptop->prev;
1874 current = tmpbot->next;
1875 tmpbot->next = NULL;
1876 do_uncut_text();
Chris Allegrettad022eac2000-11-27 02:50:49 +00001877 if (tmptop->prev == NULL)
1878 edit_refresh();
1879
Chris Allegretta9149e612000-11-27 00:23:41 +00001880 free_filestruct(tmptop);
1881 blank_statusbar_refresh();
1882 }
Chris Allegretta4a9c8582000-11-27 22:59:40 +00001883 shortcut_init(0);
1884 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00001885 free_filestruct(cutbuffer);
1886 cutbuffer = cutbak;
1887
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001888 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001889#endif
1890}
1891
1892
1893void help_init(void)
1894{
1895 int i, sofar = 0;
1896 long allocsize = 1; /* How much space we're gonna need for the help text */
1897 char buf[BUFSIZ];
1898
1899 /* Compute the space needed for the shortcut lists - we add 15 to
1900 have room for the shortcut abbrev and its possible alternate keys */
1901 for (i = 0; i < MAIN_LIST_LEN; i++)
1902 if (main_list[i].help != NULL)
1903 allocsize += strlen(main_list[i].help) + 15;
1904
Chris Allegretta756f2202000-09-01 13:32:47 +00001905 /* And for the toggle list, we also allocate space for extra text. */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001906 for (i = 0; i <= TOGGLE_LEN - 1; i++)
Chris Allegretta756f2202000-09-01 13:32:47 +00001907 if (toggles[i].desc != NULL)
1908 allocsize += strlen(toggles[i].desc) + 30;
1909
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001910 allocsize += strlen(help_text_init);
1911
1912 if (help_text != NULL)
1913 free(help_text);
1914
1915 /* Allocate space for the help text */
1916 help_text = nmalloc(allocsize);
1917
1918 /* Now add the text we want */
1919 strcpy(help_text, help_text_init);
1920
1921 /* Now add our shortcut info */
Chris Allegretta756f2202000-09-01 13:32:47 +00001922 for (i = 0; i < MAIN_LIST_LEN - 1; i++) {
Robert Siemborski6af14312000-07-01 21:34:26 +00001923 sofar = snprintf(buf, BUFSIZ, "^%c ", main_list[i].val + 64);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001924
1925 if (main_list[i].misc1 > KEY_F0 && main_list[i].misc1 <= KEY_F(64))
Robert Siemborski6af14312000-07-01 21:34:26 +00001926 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(F%d) ",
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001927 main_list[i].misc1 - KEY_F0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001928 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001929 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001930
1931 if (main_list[i].altval > 0)
Chris Allegrettae49f1232000-09-02 07:20:39 +00001932 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(M-%c) ",
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001933 main_list[i].altval - 32);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001934 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001935 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001936
Chris Allegretta756f2202000-09-01 13:32:47 +00001937
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001938 if (main_list[i].help != NULL)
Robert Siemborski976847c2000-07-06 03:43:05 +00001939 snprintf(&buf[sofar], BUFSIZ - sofar, "%s", main_list[i].help);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001940
Chris Allegretta756f2202000-09-01 13:32:47 +00001941
1942 strcat(help_text, buf);
1943 strcat(help_text, "\n");
1944 }
1945
1946 /* And the toggles... */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001947 for (i = 0; i <= TOGGLE_LEN - 1; i++) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001948 sofar = snprintf(buf, BUFSIZ,
1949 "M-%c ", toggles[i].val - 32);
Chris Allegretta756f2202000-09-01 13:32:47 +00001950
1951 if (toggles[i].desc != NULL)
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001952 snprintf(&buf[sofar], BUFSIZ - sofar, _("%s enable/disable"),
1953 toggles[i].desc);
Chris Allegretta756f2202000-09-01 13:32:47 +00001954
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001955 strcat(help_text, buf);
Robert Siemborski976847c2000-07-06 03:43:05 +00001956 strcat(help_text, "\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001957 }
1958
1959}
1960
Chris Allegretta756f2202000-09-01 13:32:47 +00001961void do_toggle(int which)
1962{
1963#ifndef NANO_SMALL
Jordi Mallach2dc0f6b2000-09-07 10:48:00 +00001964 char *enabled = _("enabled");
1965 char *disabled = _("disabled");
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00001966
Chris Allegretta2a42af12000-09-12 23:02:49 +00001967 if (ISSET(toggles[which].flag))
Chris Allegretta756f2202000-09-01 13:32:47 +00001968 UNSET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001969 else
Chris Allegretta756f2202000-09-01 13:32:47 +00001970 SET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001971
Chris Allegretta756f2202000-09-01 13:32:47 +00001972 switch (toggles[which].val) {
1973 case TOGGLE_PICOMODE_KEY:
Chris Allegretta07798352000-11-27 22:58:23 +00001974 shortcut_init(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00001975 display_main_list();
1976 break;
1977 case TOGGLE_SUSPEND_KEY:
1978 signal_init();
1979 break;
1980 case TOGGLE_MOUSE_KEY:
1981 mouse_init();
1982 break;
1983 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00001984 wclear(bottomwin);
1985 wrefresh(bottomwin);
1986 window_init();
1987 edit_refresh();
1988 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00001989 break;
1990 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00001991
1992 if (!ISSET(toggles[which].flag)) {
1993 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001994 toggles[which].val == TOGGLE_WRAP_KEY)
Chris Allegretta2a42af12000-09-12 23:02:49 +00001995 statusbar("%s %s", toggles[which].desc, enabled);
1996 else
1997 statusbar("%s %s", toggles[which].desc, disabled);
1998 } else {
1999 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002000 toggles[which].val == TOGGLE_WRAP_KEY)
Chris Allegretta2a42af12000-09-12 23:02:49 +00002001 statusbar("%s %s", toggles[which].desc, disabled);
2002 else
2003 statusbar("%s %s", toggles[which].desc, enabled);
2004 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002005 SET(DISABLE_CURPOS);
2006
Chris Allegretta4c780be2000-09-01 17:59:18 +00002007#else
2008 nano_small_msg();
Chris Allegretta756f2202000-09-01 13:32:47 +00002009#endif
2010}
2011
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002012int main(int argc, char *argv[])
2013{
2014 int optchr;
2015 int kbinput; /* Input from keyboard */
2016 long startline = 0; /* Line to try and start at */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002017 int keyhandled = 0; /* Have we handled the keystroke yet? */
Chris Allegretta16e41682000-09-11 22:33:54 +00002018 int i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002019 char *argv0;
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002020#ifdef _POSIX_VDISABLE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002021 struct termios term;
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002022#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002023
2024#ifdef HAVE_GETOPT_LONG
2025 int option_index = 0;
2026 struct option long_options[] = {
Chris Allegretta805c26d2000-09-06 13:39:17 +00002027#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002028 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00002029#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002030 {"version", 0, 0, 'V'},
2031 {"const", 0, 0, 'c'},
2032 {"suspend", 0, 0, 'z'},
2033 {"nowrap", 0, 0, 'w'},
2034 {"nohelp", 0, 0, 'x'},
2035 {"help", 0, 0, 'h'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00002036#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00002037 {"cut", 0, 0, 'k'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00002038#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002039 {"autoindent", 0, 0, 'i'},
2040 {"tempfile", 0, 0, 't'},
2041 {"speller", 1, 0, 's'},
2042 {"fill", 1, 0, 'r'},
2043 {"mouse", 0, 0, 'm'},
2044 {"pico", 0, 0, 'p'},
2045 {"nofollow", 0, 0, 'l'},
Chris Allegretta4dbcc3c2000-08-04 15:44:29 +00002046 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002047 {0, 0, 0, 0}
2048 };
2049#endif
2050
2051 /* Flag inits... */
2052 SET(FOLLOW_SYMLINKS);
2053
2054#ifndef NANO_SMALL
2055 setlocale(LC_ALL, "");
2056 bindtextdomain(PACKAGE, LOCALEDIR);
2057 textdomain(PACKAGE);
2058#endif
2059
2060#ifdef HAVE_GETOPT_LONG
Chris Allegretta627de192000-07-12 02:09:17 +00002061 while ((optchr = getopt_long(argc, argv, "?T:RVchiklmpr:s:tvwxz",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002062 long_options, &option_index)) != EOF) {
2063#else
Chris Allegretta627de192000-07-12 02:09:17 +00002064 while ((optchr = getopt(argc, argv, "h?T:RVciklmpr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002065#endif
2066
2067 switch (optchr) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00002068 case 'T':
Chris Allegretta99bf73f2000-08-04 00:22:08 +00002069 tabsize = atoi(optarg);
2070 if (tabsize <= 0) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00002071 usage(); /* To stop bogus data for tab width */
2072 finish(1);
2073 }
2074 break;
Chris Allegretta805c26d2000-09-06 13:39:17 +00002075#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00002076 case 'R':
2077 SET(USE_REGEXP);
2078 break;
Chris Allegretta47805612000-07-07 02:35:34 +00002079#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002080 case 'V':
2081 version();
2082 exit(0);
2083 case 'c':
2084 SET(CONSTUPDATE);
2085 break;
2086 case 'h':
2087 case '?':
2088 usage();
2089 exit(0);
2090 case 'i':
2091 SET(AUTOINDENT);
2092 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00002093#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00002094 case 'k':
2095 SET(CUT_TO_END);
2096 break;
Chris Allegretta18bd0292000-07-28 01:18:10 +00002097#else
2098 case 'k':
2099 usage(); /* Oops! You dont really have that option */
2100 finish(1);
Chris Allegrettad19e9912000-07-12 18:14:51 +00002101#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002102 case 'l':
2103 UNSET(FOLLOW_SYMLINKS);
2104 break;
2105 case 'm':
2106 SET(USE_MOUSE);
2107 break;
2108 case 'p':
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00002109 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002110 break;
2111 case 'r':
2112 fill = atoi(optarg);
2113 if (fill <= 0) {
2114 usage(); /* To stop bogus data (like a string) */
2115 finish(1);
2116 }
2117 break;
2118 case 's':
2119 alt_speller = nmalloc(strlen(optarg) + 1);
2120 strcpy(alt_speller, optarg);
2121 break;
2122 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00002123 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002124 break;
2125 case 'v':
2126 SET(VIEW_MODE);
2127 break;
2128 case 'w':
2129 SET(NO_WRAP);
2130 break;
2131 case 'x':
2132 SET(NO_HELP);
2133 break;
2134 case 'z':
2135 SET(SUSPEND);
2136 break;
2137 default:
2138 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002139 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002140 }
2141
2142 }
2143
2144 argv0 = strrchr(argv[0], '/');
2145 if ((argv0 && strstr(argv0, "pico"))
2146 || (!argv0 && strstr(argv[0], "pico")))
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00002147 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002148
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002149 /* See if there's a non-option in argv (first non-option is the
2150 filename, if +LINE is not given) */
2151 if (argc == 1 || argc <= optind)
2152 strcpy(filename, "");
2153 else {
2154 /* Look for the +line flag... */
2155 if (argv[optind][0] == '+') {
2156 startline = atoi(&argv[optind][1]);
2157 optind++;
2158 if (argc == 1 || argc <= optind)
2159 strcpy(filename, "");
2160 else
2161 strncpy(filename, argv[optind], 132);
2162 } else
2163 strncpy(filename, argv[optind], 132);
2164
2165 }
2166
2167
2168 /* First back up the old settings so they can be restored, duh */
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002169 tcgetattr(0, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002170
Chris Allegretta9239d742000-09-06 15:19:18 +00002171#ifdef _POSIX_VDISABLE
Chris Allegretta8f6c0692000-07-19 01:16:18 +00002172 term = oldterm;
2173 term.c_cc[VINTR] = _POSIX_VDISABLE;
2174 term.c_cc[VQUIT] = _POSIX_VDISABLE;
2175 term.c_lflag &= ~IEXTEN;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00002176 tcsetattr(0, TCSANOW, &term);
Chris Allegretta9239d742000-09-06 15:19:18 +00002177#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002178
2179 /* now ncurses init stuff... */
2180 initscr();
2181 savetty();
2182 nonl();
2183 cbreak();
2184 noecho();
2185 timeout(0);
2186
2187 /* Set up some global variables */
2188 global_init();
Chris Allegretta07798352000-11-27 22:58:23 +00002189 shortcut_init(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002190 init_help_msg();
2191 help_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00002192 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002193
2194#ifdef DEBUG
2195 fprintf(stderr, _("Main: set up windows\n"));
2196#endif
2197
Chris Allegretta2a42af12000-09-12 23:02:49 +00002198 window_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00002199 mouse_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002200
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002201#ifdef PDCURSES
2202 /* Must have this for the arrow, et al, keys to even work in
2203 PDCurses+cygwin under Windows */
Chris Allegretta1cc0b7f2000-11-03 01:29:04 +00002204 keypad_on(TRUE);
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002205#endif
2206
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002207#ifdef DEBUG
2208 fprintf(stderr, _("Main: bottom win\n"));
2209#endif
2210 /* Set up up bottom of window */
2211 display_main_list();
2212
2213#ifdef DEBUG
2214 fprintf(stderr, _("Main: open file\n"));
2215#endif
2216
2217 titlebar();
Chris Allegretta31c76662000-11-21 06:20:20 +00002218
2219 /* Now we check to see if argv[optind] is non-null to determine if
2220 we're dealing with a new file or not, not argc == 1... */
2221 if (argv[optind] == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002222 new_file();
2223 else
2224 open_file(filename, 0, 0);
2225
2226 if (startline > 0)
2227 do_gotoline(startline);
2228 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00002229 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002230
Robert Siemborski6967eec2000-07-08 14:23:32 +00002231 edit_refresh();
2232 reset_cursor();
2233
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002234 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00002235
2236#ifndef _POSIX_VDISABLE
2237 /* We're going to have to do it the old way, i.e. on cygwin */
2238 raw();
2239#endif
2240
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002241 kbinput = wgetch(edit);
2242 if (kbinput == 27) { /* Grab Alt-key stuff first */
2243 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002244 /* Alt-O, suddenly very important ;) */
Chris Allegretta16e41682000-09-11 22:33:54 +00002245 case 79:
2246 kbinput = wgetch(edit);
2247 if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002248 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00002249#ifdef DEBUG
2250 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002251 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
2252 kbinput, kbinput);
2253 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002254 }
2255#endif
2256 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002257 case 91:
2258
2259 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002260 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00002261 kbinput = wgetch(edit);
2262 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002263 kbinput = KEY_F(kbinput - 48);
2264 wgetch(edit);
2265 } else if (kbinput >= '7' && kbinput <= '9') {
2266 kbinput = KEY_F(kbinput - 49);
2267 wgetch(edit);
2268 } else if (kbinput == 126)
2269 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00002270
2271#ifdef DEBUG
2272 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002273 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
2274 kbinput, kbinput);
2275 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002276 }
2277#endif
2278
2279 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002280 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00002281 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00002282 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002283 case '0':
2284 kbinput = KEY_F(9);
2285 wgetch(edit);
2286 break;
2287 case '1':
2288 kbinput = KEY_F(10);
2289 wgetch(edit);
2290 break;
2291 case '3':
2292 kbinput = KEY_F(11);
2293 wgetch(edit);
2294 break;
2295 case '4':
2296 kbinput = KEY_F(12);
2297 wgetch(edit);
2298 break;
2299 case 126: /* Hack, make insert key do something
2300 usefile, like insert file */
2301 do_insertfile();
2302 keyhandled = 1;
2303 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002304#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002305 default:
2306 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
2307 kbinput, kbinput);
2308 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00002309#endif
2310
2311 }
2312 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002313 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00002314 kbinput = NANO_DELETE_KEY;
2315 wgetch(edit);
2316 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002317 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00002318 kbinput = NANO_END_KEY;
2319 wgetch(edit);
2320 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002321 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00002322 kbinput = KEY_PPAGE;
2323 wgetch(edit);
2324 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002325 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00002326 kbinput = KEY_NPAGE;
2327 wgetch(edit);
2328 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002329 case '[': /* Alt-[-[-[A-E], F1-F5 in linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00002330 kbinput = wgetch(edit);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002331 if (kbinput >= 'A' && kbinput <= 'E')
2332 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00002333 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002334 case 'A':
2335 kbinput = KEY_UP;
2336 break;
2337 case 'B':
2338 kbinput = KEY_DOWN;
2339 break;
2340 case 'C':
2341 kbinput = KEY_RIGHT;
2342 break;
2343 case 'D':
2344 kbinput = KEY_LEFT;
2345 break;
2346 case 'H':
2347 kbinput = KEY_HOME;
2348 break;
2349 case 'F':
2350 kbinput = KEY_END;
2351 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002352 default:
2353#ifdef DEBUG
2354 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
2355 kbinput, kbinput);
2356#endif
2357 break;
2358 }
2359 break;
2360 default:
2361
2362 /* Check for the altkey defs.... */
2363 for (i = 0; i <= MAIN_LIST_LEN - 1; i++)
2364 if (kbinput == main_list[i].altval ||
2365 kbinput == main_list[i].altval - 32) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002366 kbinput = main_list[i].val;
2367 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002368 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002369#ifndef NANO_SMALL
2370 /* And for toggle switches */
2371 for (i = 0; i <= TOGGLE_LEN - 1 && !keyhandled; i++)
2372 if (kbinput == toggles[i].val ||
2373 kbinput == toggles[i].val - 32) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002374 do_toggle(i);
2375 keyhandled = 1;
2376 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00002377 }
2378#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002379#ifdef DEBUG
2380 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
2381 kbinput);
2382#endif
2383 break;
2384 }
2385 }
2386 /* Look through the main shortcut list to see if we've hit a
2387 shortcut key */
Chris Allegretta756f2202000-09-01 13:32:47 +00002388 for (i = 0; i < MAIN_LIST_LEN && !keyhandled; i++) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002389 if (kbinput == main_list[i].val ||
2390 (main_list[i].misc1 && kbinput == main_list[i].misc1) ||
2391 (main_list[i].misc2 && kbinput == main_list[i].misc2)) {
2392 if (ISSET(VIEW_MODE) && !main_list[i].viewok)
2393 print_view_warning();
2394 else
2395 main_list[i].func();
2396 keyhandled = 1;
2397 }
2398 }
Chris Allegretta9239d742000-09-06 15:19:18 +00002399#ifndef _POSIX_VDISABLE
2400 /* Since we're in raw mode, we have to catch ^Q and ^S */
2401 if (kbinput == 17 || kbinput == 19)
2402 keyhandled = 1;
2403
2404 /* And catch ^Z by hand when triggered */
2405 if (kbinput == 26) {
2406 if (ISSET(SUSPEND))
2407 do_suspend(0);
2408 keyhandled = 1;
2409 }
2410#endif
2411
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002412 /* Last gasp, stuff that's not in the main lists */
2413 if (!keyhandled)
2414 switch (kbinput) {
2415#ifndef NANO_SMALL
2416#ifdef NCURSES_MOUSE_VERSION
2417 case KEY_MOUSE:
2418 do_mouse();
2419 break;
2420#endif
2421#endif
2422 case 0: /* Erg */
2423 do_next_word();
2424 break;
2425 case 331: /* Stuff that we don't want to do squat */
2426 case -1:
2427 case 410: /* Must ignore this, it gets sent when we resize */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002428#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002429 case 541: /* ???? */
2430 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00002431 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002432 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00002433 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00002434#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002435
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002436 break;
2437 default:
2438#ifdef DEBUG
2439 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
2440#endif
2441 /* We no longer stop unhandled sequences so that people with
2442 odd character sets can type... */
2443
2444 if (ISSET(VIEW_MODE)) {
2445 print_view_warning();
2446 break;
2447 }
2448 do_char(kbinput);
2449 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002450 if (ISSET(CONSTUPDATE)) {
2451 if (ISSET(DISABLE_CURPOS))
2452 UNSET(DISABLE_CURPOS);
2453 else
2454 do_cursorpos();
2455 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002456
2457 reset_cursor();
2458 wrefresh(edit);
2459 keyhandled = 0;
2460 }
2461
2462 getchar();
2463 finish(0);
2464
2465}