blob: d20c4f1e29b78d68eccfbc6f86584e5cbd36118c [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>
32#include <errno.h>
33#include <ctype.h>
34#include <locale.h>
35#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000036#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000037
38#include "config.h"
39#include "proto.h"
40#include "nano.h"
41
42#ifndef NANO_SMALL
43#include <libintl.h>
44#define _(string) gettext(string)
45#else
46#define _(string) (string)
47#endif
48
49#ifdef HAVE_TERMIOS_H
50#include <termios.h>
51#endif
52
53#ifdef HAVE_TERMIO_H
54#include <termio.h>
55#endif
56
57#ifdef HAVE_GETOPT_H
58#include <getopt.h>
59#endif
60
61/* Former globals, now static */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000062int fill = 0; /* Fill - where to wrap lines, basically */
63static char *alt_speller; /* Alternative spell command */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000064struct termios oldterm; /* The user's original term settings */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000065static char *help_text_init = "";
66 /* Initial message, not including shortcuts */
Chris Allegretta18f8be02000-09-04 03:20:38 +000067static struct sigaction act; /* For all out fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000068
69/* What we do when we're all set to exit */
70RETSIGTYPE finish(int sigage)
71{
72 if (!ISSET(NO_HELP)) {
73 mvwaddstr(bottomwin, 1, 0, hblank);
74 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000075 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000076 mvwaddstr(bottomwin, 0, 0, hblank);
77
78 wrefresh(bottomwin);
79 endwin();
80
81 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000082 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083
84 exit(sigage);
85}
86
87/* Die (gracefully?) */
88void die(char *msg, ...)
89{
90 va_list ap;
91
92 va_start(ap, msg);
93 vfprintf(stderr, msg, ap);
94 va_end(ap);
95
96 /* if we can't save we have REAL bad problems,
Robert Siemborskifcf32bf2000-07-17 03:04:54 +000097 * but we might as well TRY. */
98 if(filename[0] == '\0') {
99 write_file("nano.save", 0);
100 } else {
101 char buf[BUFSIZ];
102 strncpy(buf,filename,BUFSIZ);
103 strncat(buf,".save",BUFSIZ - strlen(buf));
104 write_file(buf, 0);
105 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000106 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000107 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000108
109 clear();
110 refresh();
111 resetty();
112 endwin();
113
114 fprintf(stderr, msg);
115 fprintf(stderr, _("\nBuffer written to 'nano.save'\n"));
116
117 exit(1); /* We have a problem: exit w/ errorlevel(1) */
118}
119
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000120void print_view_warning(void)
121{
122 statusbar(_("Key illegal in VIEW mode"));
123}
124
125/* Initialize global variables - no better way for now */
126void global_init(void)
127{
128 int i;
129
130 center_x = COLS / 2;
131 center_y = LINES / 2;
132 current_x = 0;
133 current_y = 0;
134 editwinrows = LINES - 5 + no_help();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000135 fileage = NULL;
136 cutbuffer = NULL;
137 current = NULL;
138 edittop = NULL;
139 editbot = NULL;
140 totlines = 0;
141 placewewant = 0;
142 if (!fill)
143 fill = COLS - 8;
144 hblank = nmalloc(COLS + 1);
145
146 /* Thanks BG for this bit... */
147 for (i = 0; i <= COLS - 1; i++)
148 hblank[i] = ' ';
149 hblank[i] = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000150}
151
152void init_help_msg(void)
153{
154
155#ifndef NANO_SMALL
156
157 help_text_init =
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000158 _(" nano help text\n\n "
159 "The nano editor is designed to emulate the functionality and "
160 "ease-of-use of the UW Pico text editor. There are four main "
161 "sections of the editor: The top line shows the program "
162 "version, the current filename being edited, and whether "
163 "or not the file has been modified. Next is the main editor "
164 "window showing the file being edited. The status line is "
165 "the third line from the bottom and shows important messages. "
166 "The bottom two lines show the most commonly used shortcuts "
167 "in the editor.\n\n "
168 "The notation for shortcuts is as follows: Control-key "
Chris Allegrettae49f1232000-09-02 07:20:39 +0000169 "sequences are notated with a caret (^) symbol and are entered "
Chris Allegrettad56bd792000-09-02 07:27:10 +0000170 "with the Control (Ctrl) key. Escape-key sequences are notated "
171 "with the Meta (M) symbol and can be entered using either the "
172 "Esc, Alt or Meta key depending on your keyboard setup. The "
173 "following keystrokes are available in the main editor window. "
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000174 "Optional keys are shown in parentheses:\n\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000175#endif
176
177}
178
179/* Make a copy of a node to a pointer (space will be malloc()ed) */
180filestruct *copy_node(filestruct * src)
181{
182 filestruct *dst;
183
184 dst = nmalloc(sizeof(filestruct));
185 dst->data = nmalloc(strlen(src->data) + 1);
186
187 dst->next = src->next;
188 dst->prev = src->prev;
189
190 strcpy(dst->data, src->data);
191 dst->lineno = src->lineno;
192
193 return dst;
194}
195
196/* Unlink a node from the rest of the struct */
197void unlink_node(filestruct * fileptr)
198{
199 if (fileptr->prev != NULL)
200 fileptr->prev->next = fileptr->next;
201
202 if (fileptr->next != NULL)
203 fileptr->next->prev = fileptr->prev;
204}
205
206void delete_node(filestruct * fileptr)
207{
208 if (fileptr->data != NULL)
209 free(fileptr->data);
210 free(fileptr);
211}
212
213/* Okay, now let's duplicate a whole struct! */
214filestruct *copy_filestruct(filestruct * src)
215{
216 filestruct *dst, *tmp, *head, *prev;
217
218 head = copy_node(src);
219 dst = head; /* Else we barf on copying just one line */
220 head->prev = NULL;
221 tmp = src->next;
222 prev = head;
223
224 while (tmp != NULL) {
225 dst = copy_node(tmp);
226 dst->prev = prev;
227 prev->next = dst;
228
229 prev = dst;
230 tmp = tmp->next;
231 }
232
233 dst->next = NULL;
234 return head;
235}
236
237/* Free() a single node */
238int free_node(filestruct * src)
239{
240 if (src == NULL)
241 return 0;
242
243 if (src->next != NULL)
244 free(src->data);
245 free(src);
246 return 1;
247}
248
249int free_filestruct(filestruct * src)
250{
251 filestruct *fileptr = src;
252
253 if (src == NULL)
254 return 0;
255
256 while (fileptr->next != NULL) {
257 fileptr = fileptr->next;
258 free_node(fileptr->prev);
259
260#ifdef DEBUG
261 fprintf(stderr, _("free_node(): free'd a node, YAY!\n"));
262#endif
263 }
264 free_node(fileptr);
265#ifdef DEBUG
266 fprintf(stderr, _("free_node(): free'd last node.\n"));
267#endif
268
269 return 1;
270}
271
272int renumber_all(void)
273{
274 filestruct *temp;
275 long i = 1;
276
277 for (temp = fileage; temp != NULL; temp = temp->next) {
278 temp->lineno = i++;
279 }
280
281 return 0;
282}
283
284int renumber(filestruct * fileptr)
285{
286 filestruct *temp;
287
288 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage) {
289 renumber_all();
290 return 0;
291 }
292 for (temp = fileptr; temp != NULL; temp = temp->next) {
293 temp->lineno = temp->prev->lineno + 1;
294 }
295
296 return 0;
297}
298
299/* Fix the memory allocation for a string */
300void align(char **strp)
301{
302 /* There was a serious bug here: the new address was never
303 stored anywhere... */
304
305 *strp = nrealloc(*strp, strlen(*strp) + 1);
306}
307
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000308/* Null a string at a certain index and align it */
309void null_at(char *data, int index)
310{
311 data[index] = 0;
312 align(&data);
313}
314
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000315void usage(void)
316{
317#ifdef HAVE_GETOPT_LONG
318 printf(_("Usage: nano [GNU long option] [option] +LINE <file>\n\n"));
319 printf(_("Option Long option Meaning\n"));
Chris Allegretta6724a7e2000-06-19 23:19:07 +0000320 printf(_
321 (" -T --tabsize=[num] Set width of a tab to num\n"));
Chris Allegretta805c26d2000-09-06 13:39:17 +0000322#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000323 printf(_
324 (" -R --regexp Use regular expressions for search\n"));
Chris Allegretta47805612000-07-07 02:35:34 +0000325#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000326 printf
327 (_
328 (" -V --version Print version information and exit\n"));
329 printf(_
330 (" -c --const Constantly show cursor position\n"));
331 printf(_
332 (" -h --help Show this message\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000333#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000334 printf(_
Chris Allegretta627de192000-07-12 02:09:17 +0000335 (" -k --cut Let ^K cut from cursor to end of line\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000336#endif
Chris Allegretta627de192000-07-12 02:09:17 +0000337 printf(_
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000338 (" -i --autoindent Automatically indent new lines\n"));
339 printf(_
340 (" -l --nofollow Don't follow symbolic links, overwrite.\n"));
341#ifndef NANO_SMALL
342#ifdef NCURSES_MOUSE_VERSION
343 printf(_(" -m --mouse Enable mouse\n"));
344#endif
345#endif
346 printf
347 (_
348 (" -r [#cols] --fill=[#cols] Set fill cols to (wrap lines at) #cols\n"));
349 printf(_
350 (" -p --pico Make bottom 2 lines more Pico-like\n"));
351 printf(_
352 (" -s [prog] --speller=[prog] Enable alternate speller\n"));
353 printf(_
354 (" -t --tempfile Auto save on exit, don't prompt\n"));
355 printf(_
356 (" -v --view View (read only) mode\n"));
357 printf(_
358 (" -w --nowrap Don't wrap long lines\n"));
359 printf(_
360 (" -x --nohelp Don't show help window\n"));
361 printf(_
362 (" -z --suspend Enable suspend\n"));
363 printf(_
364 (" +LINE Start at line number LINE\n"));
365#else
366 printf(_("Usage: nano [option] +LINE <file>\n\n"));
367 printf(_("Option Meaning\n"));
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000368 printf(_(" -T [num] Set width of a tab to num\n"));
Chris Allegretta9fc8d432000-07-07 01:49:52 +0000369 printf(_(" -R Use regular expressions for search\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000370 printf(_(" -V Print version information and exit\n"));
371 printf(_(" -c Constantly show cursor position\n"));
372 printf(_(" -h Show this message\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000373#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +0000374 printf(_(" -k Let ^K cut from cursor to end of line\n"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000375#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000376 printf(_(" -i Automatically indent new lines\n"));
377 printf(_
378 (" -l Don't follow symbolic links, overwrite.\n"));
379#ifndef NANO_SMALL
380#ifdef NCURSES_MOUSE_VERSION
381 printf(_(" -m Enable mouse\n"));
382#endif
383#endif
384 printf(_
385 (" -r [#cols] Set fill cols to (wrap lines at) #cols\n"));
386 printf(_(" -s [prog] Enable alternate speller\n"));
387 printf(_(" -p Make bottom 2 lines more Pico-like\n"));
388 printf(_(" -t Auto save on exit, don't prompt\n"));
389 printf(_(" -v View (read only) mode\n"));
390 printf(_(" -w Don't wrap long lines\n"));
391 printf(_(" -x Don't show help window\n"));
392 printf(_(" -z Enable suspend\n"));
393 printf(_(" +LINE Start at line number LINE\n"));
394#endif
395 exit(0);
396}
397
398void version(void)
399{
400 printf(_(" nano version %s by Chris Allegretta (compiled %s, %s)\n"),
401 VERSION, __TIME__, __DATE__);
402 printf(_(" Email: nano@asty.org Web: http://www.asty.org/nano\n"));
403}
404
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000405filestruct *make_new_node(filestruct * prevnode)
406{
407 filestruct *newnode;
408
409 newnode = nmalloc(sizeof(filestruct));
410 newnode->data = NULL;
411
412 newnode->prev = prevnode;
413 newnode->next = NULL;
414
415 if (prevnode != NULL)
416 newnode->lineno = prevnode->lineno + 1;
417
418 return newnode;
419}
420
Chris Allegretta7975ed82000-07-28 00:58:35 +0000421/* Splice a node into an existing filestruct */
422void splice_node(filestruct *begin, filestruct *new, filestruct *end)
423{
424 new->next = end;
425 new->prev = begin;
426 begin->next = new;
427 if (end != NULL)
428 end->prev = new;
429}
430
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000431int do_mark()
432{
433#ifdef NANO_SMALL
434 nano_small_msg();
435#else
436 if (!ISSET(MARK_ISSET)) {
437 statusbar(_("Mark Set"));
438 SET(MARK_ISSET);
439 mark_beginbuf = current;
440 mark_beginx = current_x;
441 } else {
442 statusbar(_("Mark UNset"));
443 UNSET(MARK_ISSET);
444 mark_beginbuf = NULL;
445 mark_beginx = 0;
446
447 edit_refresh();
448 }
449#endif
450 return 1;
451}
452
453int no_help(void)
454{
455 if ISSET
456 (NO_HELP)
457 return 2;
458 else
459 return 0;
460}
461
462void nano_small_msg(void)
463{
464 statusbar("Sorry, this function not available with nano-tiny option");
465}
466
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000467/* The user typed a printable character; add it to the edit buffer */
468void do_char(char ch)
469{
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000470 /* magic-line: when a character is inserted on the current magic line,
471 * it means we need a new one! */
472 if(filebot == current && current->data[0] == '\0') {
473 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000474 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000475 }
476
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000477 /* More dangerousness fun =) */
478 current->data = nrealloc(current->data, strlen(current->data) + 2);
479 memmove(&current->data[current_x + 1],
480 &current->data[current_x],
481 strlen(current->data) - current_x + 1);
482 current->data[current_x] = ch;
483 do_right();
484
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000485 if (!ISSET(NO_WRAP) && (ch != '\t'))
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000486 check_wrap(current, ch);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000487 set_modified();
488 check_statblank();
489 UNSET(KEEP_CUTBUFFER);
490 totsize++;
491
492}
493
494/* Someone hits return *gasp!* */
495int do_enter(filestruct * inptr)
496{
497 filestruct *new;
498 char *tmp, *spc;
499 int extra = 0;
500
501 new = make_new_node(inptr);
502 tmp = &current->data[current_x];
503 current_x = 0;
504
505 /* Do auto-indenting, like the neolithic Turbo Pascal editor */
506 if (ISSET(AUTOINDENT)) {
507 spc = current->data;
508 if (spc) {
509 while ((*spc == ' ') || (*spc == '\t')) {
510 extra++;
511 spc++;
512 current_x++;
513 }
514 new->data = nmalloc(strlen(tmp) + extra + 1);
515 strncpy(new->data, current->data, extra);
516 strcpy(&new->data[extra], tmp);
517 }
518 } else {
519 new->data = nmalloc(strlen(tmp) + 1);
520 strcpy(new->data, tmp);
521 }
522 *tmp = 0;
523
Chris Allegrettada721be2000-07-31 01:26:42 +0000524 if (inptr->next == NULL) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000525 filebot = new;
526 editbot = new;
527 }
Chris Allegretta7975ed82000-07-28 00:58:35 +0000528 splice_node(inptr, new, inptr->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529
530 totsize++;
531 renumber(current);
532 current = new;
533 align(&current->data);
534
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000535 /* The logic here is as follows:
536 * -> If we are at the bottom of the buffer, we want to recenter
537 * (read: rebuild) the screen and forcably move the cursor.
538 * -> otherwise, we want simply to redraw the screen and update
539 * where we think the cursor is.
540 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000541 if (current_y == editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +0000542 edit_update(current, CENTER);
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000543 reset_cursor();
544 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000545 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +0000546 edit_refresh();
547 update_cursor();
548 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000549
550 totlines++;
551 set_modified();
552
Chris Allegrettab0ae3932000-06-15 23:39:14 +0000553 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000554 return 1;
555}
556
557int do_enter_void(void)
558{
559 return do_enter(current);
560}
561
562void do_next_word(void)
563{
564 filestruct *fileptr;
565 int i;
566
567 if (current == NULL)
568 return;
569
570 i = current_x;
571 for (fileptr = current; fileptr != NULL; fileptr = fileptr->next) {
572 if (fileptr == current) {
573 while (isalnum((int) fileptr->data[i])
574 && fileptr->data[i] != 0)
575 i++;
576
577 if (fileptr->data[i] == 0) {
578 i = 0;
579 continue;
580 }
581 }
582 while (!isalnum((int) fileptr->data[i]) && fileptr->data[i] != 0)
583 i++;
584
585 if (fileptr->data[i] != 0)
586 break;
587
588 i = 0;
589 }
590 if (fileptr == NULL)
591 current = filebot;
592 else
593 current = fileptr;
594
595 current_x = i;
596 placewewant = xplustabs();
597 if (current->lineno >= editbot->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000598 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000599
600}
601
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000602void do_wrap(filestruct * inptr, char input_char)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000603{
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000604 int i = 0; /* Index into ->data for line. */
605 int i_tabs = 0; /* Screen position of ->data[i]. */
606 int last_word_end = -1; /* Location of end of last word found. */
607 int current_word_start = -1; /* Location of start of current word. */
608 int current_word_start_t = -1; /* Location of start of current word screen position. */
609 int current_word_end = -1; /* Location of end of current word */
610 int current_word_end_t = -1; /* Location of end of current word screen position. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000611 int len = strlen(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000612
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000613 int down = 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000614 int right = 0;
615 struct filestruct *temp = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000616
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000617 assert(strlenpt(inptr->data) > fill);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000618
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000619 for (i = 0, i_tabs = 0; i < len; i++, i_tabs++) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000620 if (!isspace(inptr->data[i])) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000621 last_word_end = current_word_end;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000622
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000623 current_word_start = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000624 current_word_start_t = i_tabs;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000625
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000626 while (!isspace(inptr->data[i]) && inptr->data[i]) {
627 i++;
628 i_tabs++;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000629 if (inptr->data[i] < 32)
630 i_tabs++;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000631 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000632
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000633 if (inptr->data[i]) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000634 current_word_end = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000635 current_word_end_t = i_tabs;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000636 } else {
637 current_word_end = i - 1;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000638 current_word_end_t = i_tabs - 1;
639 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000640 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000641
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000642 if (inptr->data[i] == NANO_CONTROL_I) {
Chris Allegretta6d690a32000-08-03 22:51:21 +0000643 if (i_tabs % tabsize != 0);
644 i_tabs += tabsize - (i_tabs % tabsize);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000645 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000646
Adam Rogoyski09f97962000-06-20 02:50:33 +0000647 if (current_word_end_t > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000648 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000649 }
650
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000651 /* There are a few (ever changing) cases of what the line could look like.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000652 * 1) only one word on the line before wrap point.
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000653 * a) one word takes up the whole line with no starting spaces.
654 * - do nothing and return.
655 * b) cursor is on word or before word at wrap point and there are spaces at beginning.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000656 * - word starts new line.
657 * - keep white space on original line up to the cursor.
658 * *) cursor is after word at wrap point
659 * - either it's all white space after word, and this routine isn't called.
660 * - or we are actually in case 2 (2 words).
661 * 2) Two or more words on the line before wrap point.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000662 * a) cursor is at a word or space before wrap point
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000663 * - word at wrap point starts a new line.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000664 * - white space at end of original line is cleared, unless
665 * it is all spaces between previous word and next word which appears after fill.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000666 * b) cursor is at the word at the wrap point.
667 * - word at wrap point starts a new line.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000668 * 1. pressed a space and at first character of wrap point word.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000669 * - white space on original line is kept to where cursor was.
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000670 * 2. pressed non space (or space elsewhere).
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000671 * - white space at end of original line is cleared.
672 * c) cursor is past the word at the wrap point.
673 * - word at wrap point starts a new line.
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000674 * - white space at end of original line is cleared
675 */
676
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000677 temp = nmalloc(sizeof(filestruct));
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000678
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000679 /* Category 1a: one word taking up the whole line with no beginning spaces. */
680 if ((last_word_end == -1) && (!isspace(inptr->data[0]))) {
681 for (i = current_word_end; i < len; i++) {
682 if (!isspace(inptr->data[i]) && i < len) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000683 current_word_start = i;
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000684 while (!isspace(inptr->data[i]) && (i < len)) {
685 i++;
686 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000687 last_word_end = current_word_end;
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000688 current_word_end = i;
689 break;
690 }
691 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000692
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000693 if (last_word_end == -1) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000694 free(temp);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000695 return;
696 }
697 if (current_x >= last_word_end) {
698 right = (current_x - current_word_start) + 1;
699 current_x = last_word_end;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000700 down = 1;
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000701 }
702
703 temp->data = nmalloc(strlen(&inptr->data[current_word_start]) + 1);
704 strcpy(temp->data, &inptr->data[current_word_start]);
705 inptr->data = nrealloc(inptr->data, last_word_end + 2);
706 inptr->data[last_word_end + 1] = 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000707 } else
708 /* Category 1b: one word on the line and word not taking up whole line
709 (i.e. there are spaces at the beginning of the line) */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000710 if (last_word_end == -1) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000711 temp->data = nmalloc(strlen(&inptr->data[current_word_start]) + 1);
712 strcpy(temp->data, &inptr->data[current_word_start]);
713
714 /* Inside word, remove it from original, and move cursor to right spot. */
715 if (current_x >= current_word_start) {
716 right = current_x - current_word_start;
717 current_x = 0;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000718 down = 1;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000719 }
720
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000721 null_at(inptr->data, current_x);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000722
723 if (ISSET(MARK_ISSET) && (mark_beginbuf == inptr)) {
724 mark_beginbuf = temp;
725 mark_beginx = 0;
726 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000727 }
728
729 /* Category 2: two or more words on the line. */
730 else {
731
732 /* Case 2a: cursor before word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000733 if (current_x < current_word_start) {
734 temp->data =
735 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
736 strcpy(temp->data, &inptr->data[current_word_start]);
737
738 if (!isspace(input_char)) {
739 i = current_word_start - 1;
740 while (isspace(inptr->data[i])) {
741 i--;
742 assert(i >= 0);
743 }
744 } else if (current_x <= last_word_end)
745 i = last_word_end - 1;
746 else
747 i = current_x;
748
749 inptr->data = nrealloc(inptr->data, i + 2);
750 inptr->data[i + 1] = 0;
751 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000752
753
754 /* Case 2b: cursor at word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000755 else if ((current_x >= current_word_start)
756 && (current_x <= (current_word_end + 1))) {
757 temp->data =
758 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000759 strcpy(temp->data, &inptr->data[current_word_start]);
760
761 down = 1;
762
763 right = current_x - current_word_start;
764 i = current_word_start - 1;
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000765 if (isspace(input_char) && (current_x == current_word_start)) {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000766 current_x = current_word_start;
767
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000768 null_at(inptr->data, current_word_start);
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000769 } else {
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000770
771 while (isspace(inptr->data[i])) {
772 i--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000773 assert(i >= 0);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000774 }
775 inptr->data = nrealloc(inptr->data, i + 2);
776 inptr->data[i + 1] = 0;
777 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000778 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000779
780
781 /* Case 2c: cursor past word at wrap point. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000782 else {
783 temp->data =
784 nmalloc(strlen(&inptr->data[current_word_start]) + 1);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000785 strcpy(temp->data, &inptr->data[current_word_start]);
786
787 down = 1;
788 right = current_x - current_word_start;
789
790 current_x = current_word_start;
791 i = current_word_start - 1;
792
Adam Rogoyski3d449b42000-06-19 17:30:14 +0000793 while (isspace(inptr->data[i])) {
794 i--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000795 assert(i >= 0);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000796 inptr->data = nrealloc(inptr->data, i + 2);
797 inptr->data[i + 1] = 0;
798 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000799 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000800 }
801
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000802 /* We pre-pend wrapped part to next line. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000803 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000804 /* Plus one for the space which concatenates the two lines together plus 1 for \0. */
805 char *p =
806 nmalloc(strlen(temp->data) + strlen(inptr->next->data) + 2);
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000807 int old_x = current_x, old_y = current_y;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000808
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000809 strcpy(p, temp->data);
810 strcat(p, " ");
811 strcat(p, inptr->next->data);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000812
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000813 free(inptr->next->data);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000814 inptr->next->data = p;
815
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000816 free(temp->data);
817 free(temp);
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000818
Adam Rogoyski9aeb9da2000-06-16 01:19:31 +0000819 current_x = old_x;
820 current_y = old_y;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000821 }
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000822 /* Else we start a new line. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000823 else {
824 temp->prev = inptr;
825 temp->next = inptr->next;
826
827 if (inptr->next)
828 inptr->next->prev = temp;
829 inptr->next = temp;
830
831 if (!temp->next)
832 filebot = temp;
833
834 SET(SAMELINEWRAP);
835 }
836
837
838 totlines++;
Robert Siemborskia417ddc2000-07-24 23:18:48 +0000839 /* Everything about it makes me want this line here but it causes
840 * totsize to be high by one for some reason. Sigh. (Rob) */
841 /* totsize++; */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000842
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000843 renumber(inptr);
Chris Allegretta234a34d2000-07-29 04:33:38 +0000844 edit_update(edittop, TOP);
Adam Rogoyski0223d6f2000-06-17 20:36:35 +0000845
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000846
847 /* Move the cursor to the new line if appropriate. */
848 if (down) {
849 do_right();
850 }
851
852 /* Move the cursor to the correct spot in the line if appropriate. */
853 while (right--) {
854 do_right();
855 }
856
Chris Allegretta234a34d2000-07-29 04:33:38 +0000857 edit_update(edittop, TOP);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000858 reset_cursor();
859 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000860}
861
862/* Check to see if we've just caused the line to wrap to a new line */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000863void check_wrap(filestruct * inptr, char ch)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000864{
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000865 int len = strlenpt(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000866#ifdef DEBUG
867 fprintf(stderr, _("check_wrap called with inptr->data=\"%s\"\n"),
868 inptr->data);
869#endif
870
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000871 if (len <= fill)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000872 return;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000873 else {
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000874 int i = actual_x(inptr, fill);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000875
876 /* Do not wrap if there are no words on or after wrap point. */
Adam Rogoyski09f97962000-06-20 02:50:33 +0000877 int char_found = 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000878
Adam Rogoyski09f97962000-06-20 02:50:33 +0000879 while (isspace(inptr->data[i]) && inptr->data[i])
880 i++;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000881
Adam Rogoyski09f97962000-06-20 02:50:33 +0000882 if (!inptr->data[i])
883 return;
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000884
Adam Rogoyski09f97962000-06-20 02:50:33 +0000885 /* String must be at least 1 character long. */
886 for (i = strlen(inptr->data) - 1; i >= 0; i--) {
887 if (isspace(inptr->data[i])) {
888 if (!char_found)
889 continue;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000890 char_found = 2; /* 2 for yes do wrap. */
Adam Rogoyski09f97962000-06-20 02:50:33 +0000891 break;
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000892 } else
893 char_found = 1; /* 1 for yes found a word, but must check further. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000894 }
Adam Rogoyski09f97962000-06-20 02:50:33 +0000895
896 if (char_found == 2)
897 do_wrap(inptr, ch);
Adam Rogoyski77f36de2000-06-07 03:56:54 +0000898 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000899}
900
901/* Stuff we do when we abort from programs and want to clean up the
902 * screen. This doesnt do much right now.
903 */
904void do_early_abort(void)
905{
906 blank_statusbar_refresh();
907}
908
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000909int do_backspace(void)
910{
911 filestruct *previous, *tmp;
912
913 if (current_x != 0) {
914 /* Let's get dangerous */
915 memmove(&current->data[current_x - 1], &current->data[current_x],
916 strlen(current->data) - current_x + 1);
917#ifdef DEBUG
918 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
919#endif
920 align(&current->data);
921 do_left();
922 } else {
923 if (current == fileage)
924 return 0; /* Can't delete past top of file */
925
926 previous = current->prev;
927 current_x = strlen(previous->data);
928 previous->data = nrealloc(previous->data,
929 strlen(previous->data) +
930 strlen(current->data) + 1);
931 strcat(previous->data, current->data);
932
933 tmp = current;
934 unlink_node(current);
935 delete_node(current);
936 if (current == edittop) {
937 if (previous->next)
938 current = previous->next;
939 else
940 current = previous;
Chris Allegrettada721be2000-07-31 01:26:42 +0000941 page_up_center();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000942 } else {
943 if (previous->next)
944 current = previous->next;
945 else
946 current = previous;
947 update_line(current, current_x);
948 }
949
950 /* Ooops, sanity check */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000951 if (tmp == filebot) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000952 filebot = current;
953 editbot = current;
Chris Allegretta28a0f892000-07-05 22:47:54 +0000954
955 /* Recreate the magic line if we're deleting it AND if the
956 line we're on now is NOT blank. if it is blank we
957 can just use IT for the magic line. This is how Pico
958 appears to do it, in any case */
959 if (strcmp(current->data, "")) {
960 new_magicline();
961 fix_editbot();
Chris Allegretta55373872000-07-06 22:38:37 +0000962 totsize++;
Chris Allegretta28a0f892000-07-05 22:47:54 +0000963 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000964 }
965
966 current = previous;
967 renumber(current);
968 previous_line();
969 totlines--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000970#ifdef DEBUG
971 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
972#endif
973
974 }
975
976 totsize--;
977 set_modified();
978 UNSET(KEEP_CUTBUFFER);
979 edit_refresh();
980 return 1;
981}
982
983int do_delete(void)
984{
985 filestruct *foo;
986
987 if (current_x != strlen(current->data)) {
988 /* Let's get dangerous */
989 memmove(&current->data[current_x], &current->data[current_x + 1],
990 strlen(current->data) - current_x);
991
992 align(&current->data);
993
994 } else if (current->next != NULL) {
995 current->data = nrealloc(current->data,
996 strlen(current->data) +
997 strlen(current->next->data) + 1);
998 strcat(current->data, current->next->data);
999
1000 foo = current->next;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001001 if (filebot == foo) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001002 filebot = current;
1003 editbot = current;
1004 }
1005
1006 unlink_node(foo);
1007 delete_node(foo);
1008 update_line(current, current_x);
1009
Chris Allegretta28a0f892000-07-05 22:47:54 +00001010 /* Please see the comment in do_basckspace if you don't understand
1011 this test */
1012 if (current == filebot && strcmp(current->data, ""))
1013 {
1014 new_magicline();
1015 fix_editbot();
Chris Allegretta55373872000-07-06 22:38:37 +00001016 totsize++;
Chris Allegretta28a0f892000-07-05 22:47:54 +00001017 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001018 renumber(current);
1019 totlines--;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001020 } else
1021 return 0;
1022
1023 totsize--;
1024 set_modified();
1025 UNSET(KEEP_CUTBUFFER);
1026 edit_refresh();
1027 return 1;
1028}
1029
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001030void wrap_reset(void)
1031{
1032 UNSET(SAMELINEWRAP);
1033}
1034
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001035/* Stuff we want to do when we exit the spell program one of its many ways */
1036void exit_spell(char *tmpfilename, char *foo)
1037{
1038 free(foo);
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001039
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001040 if (remove(tmpfilename) == -1)
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001041 statusbar(_("Error deleting tempfile, ack!"));
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001042 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001043}
1044
1045/*
1046 * This is Chris' very ugly spell function. Someone please make this
1047 * better =-)
1048 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001049int do_spell(void)
1050{
Chris Allegretta67105eb2000-07-03 03:18:32 +00001051#ifdef NANO_SMALL
1052 nano_small_msg();
1053 return 1;
1054#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001055 char *temp, *foo;
Robert Siemborski6af14312000-07-01 21:34:26 +00001056 int i, size;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001057
1058 if ((temp = tempnam(0, "nano.")) == NULL) {
1059 statusbar(_("Could not create a temporary filename: %s"),
1060 strerror(errno));
1061 return 0;
1062 }
1063 if (write_file(temp, 1) == -1)
1064 return 0;
1065
1066 if (alt_speller) {
Robert Siemborski6af14312000-07-01 21:34:26 +00001067 size = strlen(temp) + strlen(alt_speller) + 2;
1068 foo = nmalloc(size);
1069 snprintf(foo, size, "%s %s", alt_speller, temp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001070 } else {
1071
1072 /* For now, we only try ispell because we're not capable of
1073 handling the normal spell program (yet...) */
Robert Siemborski6af14312000-07-01 21:34:26 +00001074 size = strlen(temp) + 8;
1075 foo = nmalloc(size);
1076 snprintf(foo, size, "ispell %s", temp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001077 }
1078
1079 endwin();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001080 if (alt_speller) {
1081 if ((i = system(foo)) == -1 || i == 32512) {
1082 statusbar(_("Could not invoke spell program \"%s\""),
1083 alt_speller);
1084 exit_spell(temp, foo);
1085 return 0;
1086 }
1087 } else if ((i = system(foo)) == -1 || i == 32512) { /* Why 32512? I dont know! */
1088 statusbar(_("Could not invoke \"ispell\""));
1089 exit_spell(temp, foo);
1090 return 0;
1091 }
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001092/* initscr(); */
1093 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001094
1095 free_filestruct(fileage);
1096 global_init();
1097 open_file(temp, 0, 1);
Chris Allegretta234a34d2000-07-29 04:33:38 +00001098 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001099 set_modified();
1100 exit_spell(temp, foo);
1101 statusbar(_("Finished checking spelling"));
1102 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001103#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001104}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001105
1106int do_exit(void)
1107{
1108 int i;
1109
1110 if (!ISSET(MODIFIED))
1111 finish(0);
1112
Chris Allegretta30885552000-07-14 01:20:12 +00001113 if (ISSET(TEMP_OPT)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001114 i = 1;
1115 } else {
1116 i =
1117 do_yesno(0, 0,
1118 _
1119 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
1120 }
1121
1122#ifdef DEBUG
1123 dump_buffer(fileage);
1124#endif
1125
1126 if (i == 1) {
1127 if (do_writeout(1) > 0)
1128 finish(0);
1129 } else if (i == 0)
1130 finish(0);
1131 else
1132 statusbar(_("Cancelled"));
1133
1134 display_main_list();
1135 return 1;
1136}
1137
1138#ifndef NANO_SMALL
1139#ifdef NCURSES_MOUSE_VERSION
1140void do_mouse(void)
1141{
1142 MEVENT mevent;
Chris Allegrettae10debd2000-08-22 01:26:42 +00001143 int foo = 0, tab_found = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001144
1145 if (getmouse(&mevent) == ERR)
1146 return;
1147
1148 /* If mouse not in edit window, return (add help selection later). */
1149 if (!wenclose(edit, mevent.y, mevent.x))
1150 return;
1151
1152 /* Subtract out size of topwin. Perhaps we need a constant somewhere? */
1153 mevent.y -= 2;
1154
1155 /* Selecting where the cursor is sets the mark.
1156 * Selecting beyond the line length with the cursor at the end of the
1157 * line sets the mark as well.
1158 */
1159 if ((mevent.y == current_y) &&
1160 ((mevent.x == current_x) || (current_x == strlen(current->data)
1161 && (mevent.x >
1162 strlen(current->data))))) {
1163 if (ISSET(VIEW_MODE)) {
1164 print_view_warning();
1165 return;
1166 }
1167 do_mark();
1168 } else if (mevent.y > current_y) {
1169 while (mevent.y > current_y) {
1170 if (current->next != NULL)
1171 current = current->next;
1172 else
1173 break;
1174 current_y++;
1175 }
1176 } else if (mevent.y < current_y) {
1177 while (mevent.y < current_y) {
1178 if (current->prev != NULL)
1179 current = current->prev;
1180 else
1181 break;
1182 current_y--;
1183 }
1184 }
1185 current_x = mevent.x;
Chris Allegrettae10debd2000-08-22 01:26:42 +00001186 placewewant = current_x;
1187 while(foo < current_x) {
1188 if(current->data[foo] == NANO_CONTROL_I) {
1189 current_x -= tabsize - (foo % tabsize);
1190 tab_found = 1;
1191 } else if(current->data[foo] & 0x80)
1192 ;
1193 else if(current->data[foo] < 32)
1194 current_x--;
1195 foo++;
1196 }
1197 /* This is where tab_found comes in. I can't figure out why,
1198 * but without it any line with a tab will place the cursor
1199 * one character behind. Whatever, this fixes it. */
1200 if(tab_found == 1)
1201 current_x++;
1202
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001203 if (current_x > strlen(current->data))
1204 current_x = strlen(current->data);
1205
1206 update_cursor();
1207 edit_refresh();
1208
1209}
1210#endif
1211#endif
1212
1213/* Handler for SIGHUP */
1214RETSIGTYPE handle_hup(int signal)
1215{
1216 write_file("nano.save", 0);
1217 finish(1);
1218}
1219
Chris Allegretta18f8be02000-09-04 03:20:38 +00001220/* What do we do when we catch the suspend signal */
1221RETSIGTYPE do_suspend(int signal)
1222{
1223
1224 act.sa_handler = SIG_DFL;
1225 sigemptyset(&act.sa_mask);
1226 sigaction(SIGTSTP, &act, NULL);
1227
1228 endwin();
Chris Allegretta5577aec2000-09-04 03:53:04 +00001229 fprintf(stderr,"\n\n\n\n\nUse \"fg\" to return to nano\n");
Chris Allegretta18f8be02000-09-04 03:20:38 +00001230 raise(SIGTSTP);
1231}
1232
1233/* Restore the suspend handler when we come back into the prog */
1234RETSIGTYPE do_cont(int signal)
1235{
1236
1237 act.sa_handler = do_suspend;
1238 sigemptyset(&act.sa_mask);
1239 sigaction(SIGTSTP, &act, NULL);
1240 initscr();
1241 total_refresh();
1242}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001243
1244void handle_sigwinch(int s)
1245{
1246#ifndef NANO_SMALL
1247 char *tty = NULL;
1248 int fd = 0;
1249 int result = 0;
1250 int i = 0;
1251 struct winsize win;
1252
1253 tty = ttyname(0);
1254 if (!tty)
1255 return;
1256 fd = open(tty, O_RDWR);
1257 if (fd == -1)
1258 return;
1259 result = ioctl(fd, TIOCGWINSZ, &win);
1260 if (result == -1)
1261 return;
1262
1263
1264 COLS = win.ws_col;
1265 LINES = win.ws_row;
1266
1267 center_x = COLS / 2;
1268 center_y = LINES / 2;
1269 editwinrows = LINES - 5 + no_help();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001270 fill = COLS - 8;
1271
1272 free(hblank);
1273 hblank = nmalloc(COLS + 1);
1274
1275 for (i = 0; i <= COLS - 1; i++)
1276 hblank[i] = ' ';
1277 hblank[i] = 0;
1278
1279#ifdef HAVE_NCURSES_H
1280 resizeterm(LINES, COLS);
1281#ifdef HAVE_WRESIZE
1282 if (wresize(topwin, 2, COLS) == ERR)
1283 die(_("Cannot resize top win"));
1284 if (mvwin(topwin, 0, 0) == ERR)
1285 die(_("Cannot move top win"));
1286 if (wresize(edit, editwinrows, COLS) == ERR)
1287 die(_("Cannot resize edit win"));
1288 if (mvwin(edit, 2, 0) == ERR)
1289 die(_("Cannot move edit win"));
1290 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
1291 die(_("Cannot resize bottom win"));
1292 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
1293 die(_("Cannot move bottom win"));
1294#endif /* HAVE_WRESIZE */
1295#endif /* HAVE_NCURSES_H */
1296
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001297 fix_editbot();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001298
Chris Allegrettabceb1b22000-06-19 04:22:15 +00001299 if (current_y > editwinrows - 1) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001300 edit_update(editbot, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001301 }
1302 erase();
Chris Allegretta97accc62000-06-19 05:45:52 +00001303
1304 /* Do these b/c width may have changed... */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001305 refresh();
Chris Allegretta97accc62000-06-19 05:45:52 +00001306 titlebar();
1307 edit_refresh();
1308 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001309 total_refresh();
1310#endif
1311}
1312
Chris Allegretta756f2202000-09-01 13:32:47 +00001313void signal_init(void)
1314{
Chris Allegretta756f2202000-09-01 13:32:47 +00001315
1316 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
1317 memset(&act, 0, sizeof(struct sigaction));
1318 act.sa_handler = SIG_IGN;
1319 sigaction(SIGINT, &act, NULL);
Chris Allegretta756f2202000-09-01 13:32:47 +00001320
Chris Allegretta18f8be02000-09-04 03:20:38 +00001321 if (!ISSET(SUSPEND)) {
Chris Allegretta756f2202000-09-01 13:32:47 +00001322 sigaction(SIGTSTP, &act, NULL);
Chris Allegretta18f8be02000-09-04 03:20:38 +00001323 }
1324 else
1325 {
1326 act.sa_handler = do_suspend;
1327 sigaction(SIGTSTP, &act, NULL);
1328
1329 act.sa_handler = do_cont;
1330 sigaction (SIGCONT, &act, NULL);
1331 }
1332
Chris Allegretta756f2202000-09-01 13:32:47 +00001333
1334 /* Trap SIGHUP cuz we want to write the file out. */
1335 act.sa_handler = handle_hup;
1336 sigaction(SIGHUP, &act, NULL);
1337
1338 act.sa_handler = handle_sigwinch;
1339 sigaction(SIGWINCH, &act, NULL);
1340
1341}
1342
Chris Allegretta2a42af12000-09-12 23:02:49 +00001343void window_init(void)
1344{
Chris Allegretta92c9dd22000-09-13 14:03:27 +00001345 editwinrows = LINES - 5 + no_help();
1346
Chris Allegretta2a42af12000-09-12 23:02:49 +00001347 /* Setup up the main text window */
1348 edit = newwin(editwinrows, COLS, 2, 0);
1349
1350 /* And the other windows */
1351 topwin = newwin(2, COLS, 0, 0);
1352 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);\
1353
1354}
1355
Chris Allegretta756f2202000-09-01 13:32:47 +00001356void mouse_init(void)
1357{
1358#ifndef NANO_SMALL
1359#ifdef NCURSES_MOUSE_VERSION
1360 if (ISSET(USE_MOUSE)) {
1361 mousemask(BUTTON1_RELEASED, NULL);
1362 mouseinterval(50);
1363 }
1364 else {
1365 mousemask(0, NULL);
1366 }
1367#endif
1368#endif
1369
1370}
1371
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001372int do_tab(void)
1373{
1374 do_char('\t');
1375 return 1;
1376}
1377
1378#ifndef NANO_SMALL
1379int empty_line(const char *data)
1380{
1381 while (*data) {
1382 if (!isspace(*data))
1383 return 0;
1384
1385 data++;
1386 }
1387
1388 return 1;
1389}
1390
1391int no_spaces(const char *data)
1392{
1393 while (*data) {
1394 if (isspace(*data))
1395 return 0;
1396
1397 data++;
1398 }
1399
1400 return 1;
1401}
1402
1403void justify_format(char *data)
1404{
1405 int i = 0;
1406 int len = strlen(data);
1407
1408 /* Skip first character regardless and leading whitespace. */
1409 for (i = 1; i < len; i++) {
1410 if (!isspace(data[i]))
1411 break;
1412 }
1413
1414 i++; /* (i) is now at least 2. */
1415
1416 /* No double spaces allowed unless following a period. Tabs -> space. No double tabs. */
1417 for (; i < len; i++) {
1418 if (isspace(data[i]) && isspace(data[i - 1])
1419 && (data[i - 2] != '.')) {
1420 memmove(data + i, data + i + 1, len - i);
1421 len--;
1422 i--;
1423 }
1424 }
1425}
1426#endif
1427
1428int do_justify(void)
1429{
1430#ifndef NANO_SMALL
1431 int slen = 0; /* length of combined lines on one line. */
1432 int initial_y;
1433 filestruct *initial = NULL;
1434
1435 if (empty_line(current->data)) {
1436 /* Justify starting at first non-empty line. */
1437 do {
1438 if (!current->next)
1439 return 1;
1440
1441 current = current->next;
1442 current_y++;
1443 }
1444 while (empty_line(current->data));
1445 } else {
1446 /* Search back for the beginning of the paragraph, where
1447 * Paragraph is 1) A line with leading whitespace
1448 * or 2) A line following an empty line.
1449 */
1450 while (current->prev != NULL) {
1451 if (isspace(current->data[0]) || !current->data[0])
1452 break;
1453
1454 current = current->prev;
1455 current_y--;
1456 }
1457
1458 /* First line with leading whitespace may be empty. */
1459 if (empty_line(current->data)) {
1460 if (current->next) {
1461 current = current->next;
1462 current_y++;
1463 } else
1464 return 1;
1465 }
1466 }
1467 initial = current;
1468 initial_y = current_y;
1469
1470 set_modified();
1471 /* Put the whole paragraph into one big line. */
1472 while (current->next && !isspace(current->next->data[0])
1473 && current->next->data[0]) {
1474 filestruct *tmpnode = current->next;
1475 int len = strlen(current->data);
1476 int len2 = strlen(current->next->data);
1477
1478 /* length of both strings plus space between strings and ending \0. */
1479 current->data = nrealloc(current->data, len + len2 + 2);
1480 current->data[len++] = ' ';
1481 current->data[len] = '\0';
1482
1483 strncat(current->data, current->next->data, len2);
1484
1485 unlink_node(tmpnode);
1486 delete_node(tmpnode);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001487 }
1488
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001489 totsize -= strlen(current->data);
1490
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001491 justify_format(current->data);
1492
1493 slen = strlen(current->data);
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001494 totsize += slen;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001495
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001496 if((strlenpt(current->data) > (fill))
1497 && !no_spaces(current->data)) {
1498 do {
1499 int i = 0;
1500 int len2 = 0;
1501 filestruct *tmpline = nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001502
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001503 /* Start at fill , unless line isn't that long (but it
1504 * appears at least fill long with tabs.
1505 */
1506 if (slen > fill)
1507 i = fill;
1508 else
1509 i = slen;
1510 for (; i > 0; i--) {
1511 if (isspace(current->data[i]) &&
1512 ((strlenpt(current->data) - strlen(current->data +i)) <=
1513 fill)) break;
1514 }
1515 if (!i)
1516 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001517
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001518 current->data[i] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001519
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001520 len2 = strlen(current->data + i + 1);
1521 tmpline->data = nmalloc(len2 + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001522
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001523 /* Skip the white space in current. */
1524 memcpy(tmpline->data, current->data + i + 1, len2);
1525 tmpline->data[len2] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001526
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001527 current->data = nrealloc(current->data, i + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001528
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001529 tmpline->prev = current;
1530 tmpline->next = current->next;
1531 if (current->next != NULL)
1532 current->next->prev = tmpline;
1533
1534 current->next = tmpline;
1535 current = tmpline;
1536 slen -= i + 1;
1537 current_y++;
1538 } while ((strlenpt(current->data) > (fill))
1539 && !no_spaces(current->data));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001540 }
1541
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001542 if (current->next)
1543 current = current->next;
Adam Rogoyski09f97962000-06-20 02:50:33 +00001544 else
1545 filebot = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001546 current_x = 0;
1547 placewewant = 0;
1548
Adam Rogoyski09f97962000-06-20 02:50:33 +00001549 renumber(initial);
1550 totlines = filebot->lineno;
1551
1552 werase(edit);
1553
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001554 if ((current_y < 0) || (current_y >= editwinrows - 1)
1555 || (initial_y <= 0)) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001556 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001557 center_cursor();
1558 } else {
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001559 fix_editbot();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001560 }
1561
Adam Rogoyski09f97962000-06-20 02:50:33 +00001562 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001563 statusbar("Justify Complete");
1564 return 1;
1565#else
1566 nano_small_msg();
1567 return 1;
1568#endif
1569}
1570
1571
1572void help_init(void)
1573{
1574 int i, sofar = 0;
1575 long allocsize = 1; /* How much space we're gonna need for the help text */
1576 char buf[BUFSIZ];
1577
1578 /* Compute the space needed for the shortcut lists - we add 15 to
1579 have room for the shortcut abbrev and its possible alternate keys */
1580 for (i = 0; i < MAIN_LIST_LEN; i++)
1581 if (main_list[i].help != NULL)
1582 allocsize += strlen(main_list[i].help) + 15;
1583
Chris Allegretta756f2202000-09-01 13:32:47 +00001584 /* And for the toggle list, we also allocate space for extra text. */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001585 for (i = 0; i <= TOGGLE_LEN - 1; i++)
Chris Allegretta756f2202000-09-01 13:32:47 +00001586 if (toggles[i].desc != NULL)
1587 allocsize += strlen(toggles[i].desc) + 30;
1588
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001589 allocsize += strlen(help_text_init);
1590
1591 if (help_text != NULL)
1592 free(help_text);
1593
1594 /* Allocate space for the help text */
1595 help_text = nmalloc(allocsize);
1596
1597 /* Now add the text we want */
1598 strcpy(help_text, help_text_init);
1599
1600 /* Now add our shortcut info */
Chris Allegretta756f2202000-09-01 13:32:47 +00001601 for (i = 0; i < MAIN_LIST_LEN - 1; i++) {
Robert Siemborski6af14312000-07-01 21:34:26 +00001602 sofar = snprintf(buf, BUFSIZ, "^%c ", main_list[i].val + 64);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001603
1604 if (main_list[i].misc1 > KEY_F0 && main_list[i].misc1 <= KEY_F(64))
Robert Siemborski6af14312000-07-01 21:34:26 +00001605 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(F%d) ",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001606 main_list[i].misc1 - KEY_F0);
1607 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001608 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001609
1610 if (main_list[i].altval > 0)
Chris Allegrettae49f1232000-09-02 07:20:39 +00001611 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(M-%c) ",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001612 main_list[i].altval - 32);
1613 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001614 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001615
Chris Allegretta756f2202000-09-01 13:32:47 +00001616
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001617 if (main_list[i].help != NULL)
Robert Siemborski976847c2000-07-06 03:43:05 +00001618 snprintf(&buf[sofar], BUFSIZ - sofar, "%s", main_list[i].help);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001619
Chris Allegretta756f2202000-09-01 13:32:47 +00001620
1621 strcat(help_text, buf);
1622 strcat(help_text, "\n");
1623 }
1624
1625 /* And the toggles... */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001626 for (i = 0; i <= TOGGLE_LEN - 1; i++) {
Chris Allegretta756f2202000-09-01 13:32:47 +00001627 sofar = snprintf(buf, BUFSIZ,
Chris Allegrettae49f1232000-09-02 07:20:39 +00001628 "M-%c ", toggles[i].val - 32 );
Chris Allegretta756f2202000-09-01 13:32:47 +00001629
1630 if (toggles[i].desc != NULL)
Jordi Mallach2dc0f6b2000-09-07 10:48:00 +00001631 snprintf(&buf[sofar], BUFSIZ - sofar, _("%s enable/disable"),
Chris Allegretta756f2202000-09-01 13:32:47 +00001632 toggles[i].desc);
1633
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001634 strcat(help_text, buf);
Robert Siemborski976847c2000-07-06 03:43:05 +00001635 strcat(help_text, "\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001636 }
1637
1638}
1639
Chris Allegretta756f2202000-09-01 13:32:47 +00001640void do_toggle(int which)
1641{
1642#ifndef NANO_SMALL
Jordi Mallach2dc0f6b2000-09-07 10:48:00 +00001643 char *enabled = _("enabled");
1644 char *disabled = _("disabled");
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00001645
Chris Allegretta2a42af12000-09-12 23:02:49 +00001646 if (ISSET(toggles[which].flag))
Chris Allegretta756f2202000-09-01 13:32:47 +00001647 UNSET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001648 else
Chris Allegretta756f2202000-09-01 13:32:47 +00001649 SET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001650
Chris Allegretta756f2202000-09-01 13:32:47 +00001651 switch (toggles[which].val) {
1652 case TOGGLE_PICOMODE_KEY:
1653 shortcut_init();
1654 display_main_list();
1655 break;
1656 case TOGGLE_SUSPEND_KEY:
1657 signal_init();
1658 break;
1659 case TOGGLE_MOUSE_KEY:
1660 mouse_init();
1661 break;
1662 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00001663 wclear(bottomwin);
1664 wrefresh(bottomwin);
1665 window_init();
1666 edit_refresh();
1667 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00001668 break;
1669 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00001670
1671 if (!ISSET(toggles[which].flag)) {
1672 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
1673 toggles[which].val == TOGGLE_WRAP_KEY)
1674 statusbar("%s %s", toggles[which].desc, enabled);
1675 else
1676 statusbar("%s %s", toggles[which].desc, disabled);
1677 } else {
1678 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
1679 toggles[which].val == TOGGLE_WRAP_KEY)
1680 statusbar("%s %s", toggles[which].desc, disabled);
1681 else
1682 statusbar("%s %s", toggles[which].desc, enabled);
1683 }
Chris Allegretta756f2202000-09-01 13:32:47 +00001684 SET(DISABLE_CURPOS);
1685
Chris Allegretta4c780be2000-09-01 17:59:18 +00001686#else
1687 nano_small_msg();
Chris Allegretta756f2202000-09-01 13:32:47 +00001688#endif
1689}
1690
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001691int main(int argc, char *argv[])
1692{
1693 int optchr;
1694 int kbinput; /* Input from keyboard */
1695 long startline = 0; /* Line to try and start at */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001696 int keyhandled = 0; /* Have we handled the keystroke yet? */
Chris Allegretta16e41682000-09-11 22:33:54 +00001697 int i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001698 char *argv0;
1699 struct termios term;
1700
1701#ifdef HAVE_GETOPT_LONG
1702 int option_index = 0;
1703 struct option long_options[] = {
Chris Allegretta805c26d2000-09-06 13:39:17 +00001704#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00001705 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00001706#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001707 {"version", 0, 0, 'V'},
1708 {"const", 0, 0, 'c'},
1709 {"suspend", 0, 0, 'z'},
1710 {"nowrap", 0, 0, 'w'},
1711 {"nohelp", 0, 0, 'x'},
1712 {"help", 0, 0, 'h'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00001713#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00001714 {"cut", 0, 0, 'k'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00001715#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001716 {"autoindent", 0, 0, 'i'},
1717 {"tempfile", 0, 0, 't'},
1718 {"speller", 1, 0, 's'},
1719 {"fill", 1, 0, 'r'},
1720 {"mouse", 0, 0, 'm'},
1721 {"pico", 0, 0, 'p'},
1722 {"nofollow", 0, 0, 'l'},
Chris Allegretta4dbcc3c2000-08-04 15:44:29 +00001723 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001724 {0, 0, 0, 0}
1725 };
1726#endif
1727
1728 /* Flag inits... */
1729 SET(FOLLOW_SYMLINKS);
1730
1731#ifndef NANO_SMALL
1732 setlocale(LC_ALL, "");
1733 bindtextdomain(PACKAGE, LOCALEDIR);
1734 textdomain(PACKAGE);
1735#endif
1736
1737#ifdef HAVE_GETOPT_LONG
Chris Allegretta627de192000-07-12 02:09:17 +00001738 while ((optchr = getopt_long(argc, argv, "?T:RVchiklmpr:s:tvwxz",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001739 long_options, &option_index)) != EOF) {
1740#else
Chris Allegretta627de192000-07-12 02:09:17 +00001741 while ((optchr = getopt(argc, argv, "h?T:RVciklmpr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001742#endif
1743
1744 switch (optchr) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00001745 case 'T':
Chris Allegretta99bf73f2000-08-04 00:22:08 +00001746 tabsize = atoi(optarg);
1747 if (tabsize <= 0) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00001748 usage(); /* To stop bogus data for tab width */
1749 finish(1);
1750 }
1751 break;
Chris Allegretta805c26d2000-09-06 13:39:17 +00001752#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00001753 case 'R':
1754 SET(USE_REGEXP);
1755 break;
Chris Allegretta47805612000-07-07 02:35:34 +00001756#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001757 case 'V':
1758 version();
1759 exit(0);
1760 case 'c':
1761 SET(CONSTUPDATE);
1762 break;
1763 case 'h':
1764 case '?':
1765 usage();
1766 exit(0);
1767 case 'i':
1768 SET(AUTOINDENT);
1769 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00001770#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00001771 case 'k':
1772 SET(CUT_TO_END);
1773 break;
Chris Allegretta18bd0292000-07-28 01:18:10 +00001774#else
1775 case 'k':
1776 usage(); /* Oops! You dont really have that option */
1777 finish(1);
Chris Allegrettad19e9912000-07-12 18:14:51 +00001778#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001779 case 'l':
1780 UNSET(FOLLOW_SYMLINKS);
1781 break;
1782 case 'm':
1783 SET(USE_MOUSE);
1784 break;
1785 case 'p':
1786 SET(PICO_MSGS);
1787 break;
1788 case 'r':
1789 fill = atoi(optarg);
1790 if (fill <= 0) {
1791 usage(); /* To stop bogus data (like a string) */
1792 finish(1);
1793 }
1794 break;
1795 case 's':
1796 alt_speller = nmalloc(strlen(optarg) + 1);
1797 strcpy(alt_speller, optarg);
1798 break;
1799 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00001800 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001801 break;
1802 case 'v':
1803 SET(VIEW_MODE);
1804 break;
1805 case 'w':
1806 SET(NO_WRAP);
1807 break;
1808 case 'x':
1809 SET(NO_HELP);
1810 break;
1811 case 'z':
1812 SET(SUSPEND);
1813 break;
1814 default:
1815 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001816 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001817 }
1818
1819 }
1820
1821 argv0 = strrchr(argv[0], '/');
1822 if ((argv0 && strstr(argv0, "pico"))
1823 || (!argv0 && strstr(argv[0], "pico")))
1824 SET(PICO_MSGS);
1825
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001826 /* See if there's a non-option in argv (first non-option is the
1827 filename, if +LINE is not given) */
1828 if (argc == 1 || argc <= optind)
1829 strcpy(filename, "");
1830 else {
1831 /* Look for the +line flag... */
1832 if (argv[optind][0] == '+') {
1833 startline = atoi(&argv[optind][1]);
1834 optind++;
1835 if (argc == 1 || argc <= optind)
1836 strcpy(filename, "");
1837 else
1838 strncpy(filename, argv[optind], 132);
1839 } else
1840 strncpy(filename, argv[optind], 132);
1841
1842 }
1843
1844
1845 /* First back up the old settings so they can be restored, duh */
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001846 tcgetattr(0, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001847
Chris Allegretta9239d742000-09-06 15:19:18 +00001848#ifdef _POSIX_VDISABLE
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001849 term = oldterm;
1850 term.c_cc[VINTR] = _POSIX_VDISABLE;
1851 term.c_cc[VQUIT] = _POSIX_VDISABLE;
1852 term.c_lflag &= ~IEXTEN;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001853 tcsetattr(0, TCSANOW, &term);
Chris Allegretta9239d742000-09-06 15:19:18 +00001854#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001855
1856 /* now ncurses init stuff... */
1857 initscr();
1858 savetty();
1859 nonl();
1860 cbreak();
1861 noecho();
1862 timeout(0);
1863
1864 /* Set up some global variables */
1865 global_init();
1866 shortcut_init();
1867 init_help_msg();
1868 help_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00001869 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001870
1871#ifdef DEBUG
1872 fprintf(stderr, _("Main: set up windows\n"));
1873#endif
1874
Chris Allegretta2a42af12000-09-12 23:02:49 +00001875 window_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00001876 mouse_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001877
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001878#ifdef DEBUG
1879 fprintf(stderr, _("Main: bottom win\n"));
1880#endif
1881 /* Set up up bottom of window */
1882 display_main_list();
1883
1884#ifdef DEBUG
1885 fprintf(stderr, _("Main: open file\n"));
1886#endif
1887
1888 titlebar();
1889 if (argc == 1)
1890 new_file();
1891 else
1892 open_file(filename, 0, 0);
1893
1894 if (startline > 0)
1895 do_gotoline(startline);
1896 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00001897 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001898
Robert Siemborski6967eec2000-07-08 14:23:32 +00001899 edit_refresh();
1900 reset_cursor();
1901
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001902 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00001903
1904#ifndef _POSIX_VDISABLE
1905 /* We're going to have to do it the old way, i.e. on cygwin */
1906 raw();
1907#endif
1908
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001909 kbinput = wgetch(edit);
1910 if (kbinput == 27) { /* Grab Alt-key stuff first */
1911 switch (kbinput = wgetch(edit)) {
Chris Allegretta16e41682000-09-11 22:33:54 +00001912 /* Alt-O, suddenly very important ;) */
1913 case 79:
1914 kbinput = wgetch(edit);
1915 if (kbinput <= 'S' && kbinput >= 'P')
1916 kbinput = KEY_F(kbinput - 79);
1917#ifdef DEBUG
1918 else {
1919 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
1920 kbinput, kbinput);
1921 break;
1922 }
1923#endif
1924 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001925 case 91:
1926
1927 switch (kbinput = wgetch(edit)) {
Chris Allegretta16e41682000-09-11 22:33:54 +00001928 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
1929 kbinput = wgetch(edit);
1930 if (kbinput >= '1' && kbinput <= '5') {
1931 kbinput = KEY_F(kbinput - 48);
1932 wgetch(edit);
1933 }
1934 else if (kbinput >= '7' && kbinput <= '9') {
1935 kbinput = KEY_F(kbinput - 49);
1936 wgetch(edit);
1937 }
1938 else if (kbinput == 126)
1939 kbinput = KEY_HOME;
1940
1941#ifdef DEBUG
1942 else {
1943 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
1944 kbinput, kbinput);
1945 break;
1946 }
1947#endif
1948
1949 break;
1950 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
1951 kbinput = wgetch(edit);
1952 wgetch(edit);
1953 switch (kbinput) {
1954 case '0':
1955 kbinput = KEY_F(9);
1956 break;
1957 case '1':
1958 kbinput = KEY_F(10);
1959 break;
1960 case '3':
1961 kbinput = KEY_F(11);
1962 break;
1963 case '4':
1964 kbinput = KEY_F(12);
1965 break;
1966#ifdef DEBUG
1967 default:
1968 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
1969 kbinput, kbinput);
1970 break;
1971#endif
1972
1973 }
1974 break;
1975 case '3': /* Alt-[-3 = Delete? */
1976 kbinput = NANO_DELETE_KEY;
1977 wgetch(edit);
1978 break;
1979 case '4': /* Alt-[-4 = End? */
1980 kbinput = NANO_END_KEY;
1981 wgetch(edit);
1982 break;
1983 case '5': /* Alt-[-5 = Page Up */
1984 kbinput = KEY_PPAGE;
1985 wgetch(edit);
1986 break;
1987 case '6': /* Alt-[-6 = Page Down */
1988 kbinput = KEY_NPAGE;
1989 wgetch(edit);
1990 break;
1991 case '[': /* Alt-[-[-[A-E], F1-F5 in linux console */
1992 kbinput = wgetch(edit);
1993 if (kbinput >= 'A' && kbinput <= 'E')
1994 kbinput = KEY_F(kbinput - 64);
1995 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001996 case 'A':
1997 kbinput = KEY_UP;
1998 break;
1999 case 'B':
2000 kbinput = KEY_DOWN;
2001 break;
2002 case 'C':
2003 kbinput = KEY_RIGHT;
2004 break;
2005 case 'D':
2006 kbinput = KEY_LEFT;
2007 break;
2008 case 'H':
2009 kbinput = KEY_HOME;
2010 break;
2011 case 'F':
2012 kbinput = KEY_END;
2013 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002014 default:
2015#ifdef DEBUG
2016 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
2017 kbinput, kbinput);
2018#endif
2019 break;
2020 }
2021 break;
2022 default:
2023
2024 /* Check for the altkey defs.... */
2025 for (i = 0; i <= MAIN_LIST_LEN - 1; i++)
2026 if (kbinput == main_list[i].altval ||
2027 kbinput == main_list[i].altval - 32) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002028 kbinput = main_list[i].val;
2029 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002030 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002031#ifndef NANO_SMALL
2032 /* And for toggle switches */
2033 for (i = 0; i <= TOGGLE_LEN - 1 && !keyhandled; i++)
2034 if (kbinput == toggles[i].val ||
2035 kbinput == toggles[i].val - 32) {
2036 do_toggle(i);
2037 keyhandled = 1;
2038 break;
2039 }
2040#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002041#ifdef DEBUG
2042 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
2043 kbinput);
2044#endif
2045 break;
2046 }
2047 }
2048 /* Look through the main shortcut list to see if we've hit a
2049 shortcut key */
Chris Allegretta756f2202000-09-01 13:32:47 +00002050 for (i = 0; i < MAIN_LIST_LEN && !keyhandled; i++) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002051 if (kbinput == main_list[i].val ||
2052 (main_list[i].misc1 && kbinput == main_list[i].misc1) ||
2053 (main_list[i].misc2 && kbinput == main_list[i].misc2)) {
2054 if (ISSET(VIEW_MODE) && !main_list[i].viewok)
2055 print_view_warning();
2056 else
2057 main_list[i].func();
2058 keyhandled = 1;
2059 }
2060 }
Chris Allegretta9239d742000-09-06 15:19:18 +00002061#ifndef _POSIX_VDISABLE
2062 /* Since we're in raw mode, we have to catch ^Q and ^S */
2063 if (kbinput == 17 || kbinput == 19)
2064 keyhandled = 1;
2065
2066 /* And catch ^Z by hand when triggered */
2067 if (kbinput == 26) {
2068 if (ISSET(SUSPEND))
2069 do_suspend(0);
2070 keyhandled = 1;
2071 }
2072#endif
2073
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002074 /* Last gasp, stuff that's not in the main lists */
2075 if (!keyhandled)
2076 switch (kbinput) {
2077#ifndef NANO_SMALL
2078#ifdef NCURSES_MOUSE_VERSION
2079 case KEY_MOUSE:
2080 do_mouse();
2081 break;
2082#endif
2083#endif
2084 case 0: /* Erg */
2085 do_next_word();
2086 break;
2087 case 331: /* Stuff that we don't want to do squat */
2088 case -1:
2089 case 410: /* Must ignore this, it gets sent when we resize */
2090 break;
2091 default:
2092#ifdef DEBUG
2093 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
2094#endif
2095 /* We no longer stop unhandled sequences so that people with
2096 odd character sets can type... */
2097
2098 if (ISSET(VIEW_MODE)) {
2099 print_view_warning();
2100 break;
2101 }
2102 do_char(kbinput);
2103 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002104 if (ISSET(CONSTUPDATE)) {
2105 if (ISSET(DISABLE_CURPOS))
2106 UNSET(DISABLE_CURPOS);
2107 else
2108 do_cursorpos();
2109 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002110
2111 reset_cursor();
2112 wrefresh(edit);
2113 keyhandled = 0;
2114 }
2115
2116 getchar();
2117 finish(0);
2118
2119}