blob: 8ede9cad544d9e14bc94ec09e76a8d37bcf411cc [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{
1345 /* Setup up the main text window */
1346 edit = newwin(editwinrows, COLS, 2, 0);
1347
1348 /* And the other windows */
1349 topwin = newwin(2, COLS, 0, 0);
1350 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);\
1351
1352}
1353
Chris Allegretta756f2202000-09-01 13:32:47 +00001354void mouse_init(void)
1355{
1356#ifndef NANO_SMALL
1357#ifdef NCURSES_MOUSE_VERSION
1358 if (ISSET(USE_MOUSE)) {
1359 mousemask(BUTTON1_RELEASED, NULL);
1360 mouseinterval(50);
1361 }
1362 else {
1363 mousemask(0, NULL);
1364 }
1365#endif
1366#endif
1367
1368}
1369
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001370int do_tab(void)
1371{
1372 do_char('\t');
1373 return 1;
1374}
1375
1376#ifndef NANO_SMALL
1377int empty_line(const char *data)
1378{
1379 while (*data) {
1380 if (!isspace(*data))
1381 return 0;
1382
1383 data++;
1384 }
1385
1386 return 1;
1387}
1388
1389int no_spaces(const char *data)
1390{
1391 while (*data) {
1392 if (isspace(*data))
1393 return 0;
1394
1395 data++;
1396 }
1397
1398 return 1;
1399}
1400
1401void justify_format(char *data)
1402{
1403 int i = 0;
1404 int len = strlen(data);
1405
1406 /* Skip first character regardless and leading whitespace. */
1407 for (i = 1; i < len; i++) {
1408 if (!isspace(data[i]))
1409 break;
1410 }
1411
1412 i++; /* (i) is now at least 2. */
1413
1414 /* No double spaces allowed unless following a period. Tabs -> space. No double tabs. */
1415 for (; i < len; i++) {
1416 if (isspace(data[i]) && isspace(data[i - 1])
1417 && (data[i - 2] != '.')) {
1418 memmove(data + i, data + i + 1, len - i);
1419 len--;
1420 i--;
1421 }
1422 }
1423}
1424#endif
1425
1426int do_justify(void)
1427{
1428#ifndef NANO_SMALL
1429 int slen = 0; /* length of combined lines on one line. */
1430 int initial_y;
1431 filestruct *initial = NULL;
1432
1433 if (empty_line(current->data)) {
1434 /* Justify starting at first non-empty line. */
1435 do {
1436 if (!current->next)
1437 return 1;
1438
1439 current = current->next;
1440 current_y++;
1441 }
1442 while (empty_line(current->data));
1443 } else {
1444 /* Search back for the beginning of the paragraph, where
1445 * Paragraph is 1) A line with leading whitespace
1446 * or 2) A line following an empty line.
1447 */
1448 while (current->prev != NULL) {
1449 if (isspace(current->data[0]) || !current->data[0])
1450 break;
1451
1452 current = current->prev;
1453 current_y--;
1454 }
1455
1456 /* First line with leading whitespace may be empty. */
1457 if (empty_line(current->data)) {
1458 if (current->next) {
1459 current = current->next;
1460 current_y++;
1461 } else
1462 return 1;
1463 }
1464 }
1465 initial = current;
1466 initial_y = current_y;
1467
1468 set_modified();
1469 /* Put the whole paragraph into one big line. */
1470 while (current->next && !isspace(current->next->data[0])
1471 && current->next->data[0]) {
1472 filestruct *tmpnode = current->next;
1473 int len = strlen(current->data);
1474 int len2 = strlen(current->next->data);
1475
1476 /* length of both strings plus space between strings and ending \0. */
1477 current->data = nrealloc(current->data, len + len2 + 2);
1478 current->data[len++] = ' ';
1479 current->data[len] = '\0';
1480
1481 strncat(current->data, current->next->data, len2);
1482
1483 unlink_node(tmpnode);
1484 delete_node(tmpnode);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001485 }
1486
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001487 totsize -= strlen(current->data);
1488
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001489 justify_format(current->data);
1490
1491 slen = strlen(current->data);
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001492 totsize += slen;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001493
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001494 if((strlenpt(current->data) > (fill))
1495 && !no_spaces(current->data)) {
1496 do {
1497 int i = 0;
1498 int len2 = 0;
1499 filestruct *tmpline = nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001500
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001501 /* Start at fill , unless line isn't that long (but it
1502 * appears at least fill long with tabs.
1503 */
1504 if (slen > fill)
1505 i = fill;
1506 else
1507 i = slen;
1508 for (; i > 0; i--) {
1509 if (isspace(current->data[i]) &&
1510 ((strlenpt(current->data) - strlen(current->data +i)) <=
1511 fill)) break;
1512 }
1513 if (!i)
1514 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001515
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001516 current->data[i] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001517
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001518 len2 = strlen(current->data + i + 1);
1519 tmpline->data = nmalloc(len2 + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001520
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001521 /* Skip the white space in current. */
1522 memcpy(tmpline->data, current->data + i + 1, len2);
1523 tmpline->data[len2] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001524
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001525 current->data = nrealloc(current->data, i + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001526
Robert Siemborskia417ddc2000-07-24 23:18:48 +00001527 tmpline->prev = current;
1528 tmpline->next = current->next;
1529 if (current->next != NULL)
1530 current->next->prev = tmpline;
1531
1532 current->next = tmpline;
1533 current = tmpline;
1534 slen -= i + 1;
1535 current_y++;
1536 } while ((strlenpt(current->data) > (fill))
1537 && !no_spaces(current->data));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001538 }
1539
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001540 if (current->next)
1541 current = current->next;
Adam Rogoyski09f97962000-06-20 02:50:33 +00001542 else
1543 filebot = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001544 current_x = 0;
1545 placewewant = 0;
1546
Adam Rogoyski09f97962000-06-20 02:50:33 +00001547 renumber(initial);
1548 totlines = filebot->lineno;
1549
1550 werase(edit);
1551
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001552 if ((current_y < 0) || (current_y >= editwinrows - 1)
1553 || (initial_y <= 0)) {
Chris Allegretta234a34d2000-07-29 04:33:38 +00001554 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001555 center_cursor();
1556 } else {
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001557 fix_editbot();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001558 }
1559
Adam Rogoyski09f97962000-06-20 02:50:33 +00001560 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001561 statusbar("Justify Complete");
1562 return 1;
1563#else
1564 nano_small_msg();
1565 return 1;
1566#endif
1567}
1568
1569
1570void help_init(void)
1571{
1572 int i, sofar = 0;
1573 long allocsize = 1; /* How much space we're gonna need for the help text */
1574 char buf[BUFSIZ];
1575
1576 /* Compute the space needed for the shortcut lists - we add 15 to
1577 have room for the shortcut abbrev and its possible alternate keys */
1578 for (i = 0; i < MAIN_LIST_LEN; i++)
1579 if (main_list[i].help != NULL)
1580 allocsize += strlen(main_list[i].help) + 15;
1581
Chris Allegretta756f2202000-09-01 13:32:47 +00001582 /* And for the toggle list, we also allocate space for extra text. */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001583 for (i = 0; i <= TOGGLE_LEN - 1; i++)
Chris Allegretta756f2202000-09-01 13:32:47 +00001584 if (toggles[i].desc != NULL)
1585 allocsize += strlen(toggles[i].desc) + 30;
1586
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001587 allocsize += strlen(help_text_init);
1588
1589 if (help_text != NULL)
1590 free(help_text);
1591
1592 /* Allocate space for the help text */
1593 help_text = nmalloc(allocsize);
1594
1595 /* Now add the text we want */
1596 strcpy(help_text, help_text_init);
1597
1598 /* Now add our shortcut info */
Chris Allegretta756f2202000-09-01 13:32:47 +00001599 for (i = 0; i < MAIN_LIST_LEN - 1; i++) {
Robert Siemborski6af14312000-07-01 21:34:26 +00001600 sofar = snprintf(buf, BUFSIZ, "^%c ", main_list[i].val + 64);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001601
1602 if (main_list[i].misc1 > KEY_F0 && main_list[i].misc1 <= KEY_F(64))
Robert Siemborski6af14312000-07-01 21:34:26 +00001603 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(F%d) ",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001604 main_list[i].misc1 - KEY_F0);
1605 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001606 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001607
1608 if (main_list[i].altval > 0)
Chris Allegrettae49f1232000-09-02 07:20:39 +00001609 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, "(M-%c) ",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001610 main_list[i].altval - 32);
1611 else
Robert Siemborski6af14312000-07-01 21:34:26 +00001612 sofar += snprintf(&buf[sofar], BUFSIZ - sofar, " ");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001613
Chris Allegretta756f2202000-09-01 13:32:47 +00001614
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001615 if (main_list[i].help != NULL)
Robert Siemborski976847c2000-07-06 03:43:05 +00001616 snprintf(&buf[sofar], BUFSIZ - sofar, "%s", main_list[i].help);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001617
Chris Allegretta756f2202000-09-01 13:32:47 +00001618
1619 strcat(help_text, buf);
1620 strcat(help_text, "\n");
1621 }
1622
1623 /* And the toggles... */
Chris Allegretta423cbfd2000-09-04 16:21:29 +00001624 for (i = 0; i <= TOGGLE_LEN - 1; i++) {
Chris Allegretta756f2202000-09-01 13:32:47 +00001625 sofar = snprintf(buf, BUFSIZ,
Chris Allegrettae49f1232000-09-02 07:20:39 +00001626 "M-%c ", toggles[i].val - 32 );
Chris Allegretta756f2202000-09-01 13:32:47 +00001627
1628 if (toggles[i].desc != NULL)
Jordi Mallach2dc0f6b2000-09-07 10:48:00 +00001629 snprintf(&buf[sofar], BUFSIZ - sofar, _("%s enable/disable"),
Chris Allegretta756f2202000-09-01 13:32:47 +00001630 toggles[i].desc);
1631
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001632 strcat(help_text, buf);
Robert Siemborski976847c2000-07-06 03:43:05 +00001633 strcat(help_text, "\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001634 }
1635
1636}
1637
Chris Allegretta756f2202000-09-01 13:32:47 +00001638void do_toggle(int which)
1639{
1640#ifndef NANO_SMALL
Jordi Mallach2dc0f6b2000-09-07 10:48:00 +00001641 char *enabled = _("enabled");
1642 char *disabled = _("disabled");
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00001643
Chris Allegretta2a42af12000-09-12 23:02:49 +00001644 if (ISSET(toggles[which].flag))
Chris Allegretta756f2202000-09-01 13:32:47 +00001645 UNSET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001646 else
Chris Allegretta756f2202000-09-01 13:32:47 +00001647 SET(toggles[which].flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00001648
Chris Allegretta756f2202000-09-01 13:32:47 +00001649 switch (toggles[which].val) {
1650 case TOGGLE_PICOMODE_KEY:
1651 shortcut_init();
1652 display_main_list();
1653 break;
1654 case TOGGLE_SUSPEND_KEY:
1655 signal_init();
1656 break;
1657 case TOGGLE_MOUSE_KEY:
1658 mouse_init();
1659 break;
1660 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00001661 wclear(bottomwin);
1662 wrefresh(bottomwin);
1663 window_init();
1664 edit_refresh();
1665 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00001666 break;
1667 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00001668
1669 if (!ISSET(toggles[which].flag)) {
1670 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
1671 toggles[which].val == TOGGLE_WRAP_KEY)
1672 statusbar("%s %s", toggles[which].desc, enabled);
1673 else
1674 statusbar("%s %s", toggles[which].desc, disabled);
1675 } else {
1676 if (toggles[which].val == TOGGLE_NOHELP_KEY ||
1677 toggles[which].val == TOGGLE_WRAP_KEY)
1678 statusbar("%s %s", toggles[which].desc, disabled);
1679 else
1680 statusbar("%s %s", toggles[which].desc, enabled);
1681 }
Chris Allegretta756f2202000-09-01 13:32:47 +00001682 SET(DISABLE_CURPOS);
1683
Chris Allegretta4c780be2000-09-01 17:59:18 +00001684#else
1685 nano_small_msg();
Chris Allegretta756f2202000-09-01 13:32:47 +00001686#endif
1687}
1688
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001689int main(int argc, char *argv[])
1690{
1691 int optchr;
1692 int kbinput; /* Input from keyboard */
1693 long startline = 0; /* Line to try and start at */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001694 int keyhandled = 0; /* Have we handled the keystroke yet? */
Chris Allegretta16e41682000-09-11 22:33:54 +00001695 int i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001696 char *argv0;
1697 struct termios term;
1698
1699#ifdef HAVE_GETOPT_LONG
1700 int option_index = 0;
1701 struct option long_options[] = {
Chris Allegretta805c26d2000-09-06 13:39:17 +00001702#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00001703 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00001704#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001705 {"version", 0, 0, 'V'},
1706 {"const", 0, 0, 'c'},
1707 {"suspend", 0, 0, 'z'},
1708 {"nowrap", 0, 0, 'w'},
1709 {"nohelp", 0, 0, 'x'},
1710 {"help", 0, 0, 'h'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00001711#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00001712 {"cut", 0, 0, 'k'},
Chris Allegrettad19e9912000-07-12 18:14:51 +00001713#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001714 {"autoindent", 0, 0, 'i'},
1715 {"tempfile", 0, 0, 't'},
1716 {"speller", 1, 0, 's'},
1717 {"fill", 1, 0, 'r'},
1718 {"mouse", 0, 0, 'm'},
1719 {"pico", 0, 0, 'p'},
1720 {"nofollow", 0, 0, 'l'},
Chris Allegretta4dbcc3c2000-08-04 15:44:29 +00001721 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001722 {0, 0, 0, 0}
1723 };
1724#endif
1725
1726 /* Flag inits... */
1727 SET(FOLLOW_SYMLINKS);
1728
1729#ifndef NANO_SMALL
1730 setlocale(LC_ALL, "");
1731 bindtextdomain(PACKAGE, LOCALEDIR);
1732 textdomain(PACKAGE);
1733#endif
1734
1735#ifdef HAVE_GETOPT_LONG
Chris Allegretta627de192000-07-12 02:09:17 +00001736 while ((optchr = getopt_long(argc, argv, "?T:RVchiklmpr:s:tvwxz",
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001737 long_options, &option_index)) != EOF) {
1738#else
Chris Allegretta627de192000-07-12 02:09:17 +00001739 while ((optchr = getopt(argc, argv, "h?T:RVciklmpr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001740#endif
1741
1742 switch (optchr) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00001743 case 'T':
Chris Allegretta99bf73f2000-08-04 00:22:08 +00001744 tabsize = atoi(optarg);
1745 if (tabsize <= 0) {
Chris Allegretta6724a7e2000-06-19 23:19:07 +00001746 usage(); /* To stop bogus data for tab width */
1747 finish(1);
1748 }
1749 break;
Chris Allegretta805c26d2000-09-06 13:39:17 +00001750#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00001751 case 'R':
1752 SET(USE_REGEXP);
1753 break;
Chris Allegretta47805612000-07-07 02:35:34 +00001754#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001755 case 'V':
1756 version();
1757 exit(0);
1758 case 'c':
1759 SET(CONSTUPDATE);
1760 break;
1761 case 'h':
1762 case '?':
1763 usage();
1764 exit(0);
1765 case 'i':
1766 SET(AUTOINDENT);
1767 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00001768#ifndef NANO_SMALL
Chris Allegretta627de192000-07-12 02:09:17 +00001769 case 'k':
1770 SET(CUT_TO_END);
1771 break;
Chris Allegretta18bd0292000-07-28 01:18:10 +00001772#else
1773 case 'k':
1774 usage(); /* Oops! You dont really have that option */
1775 finish(1);
Chris Allegrettad19e9912000-07-12 18:14:51 +00001776#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001777 case 'l':
1778 UNSET(FOLLOW_SYMLINKS);
1779 break;
1780 case 'm':
1781 SET(USE_MOUSE);
1782 break;
1783 case 'p':
1784 SET(PICO_MSGS);
1785 break;
1786 case 'r':
1787 fill = atoi(optarg);
1788 if (fill <= 0) {
1789 usage(); /* To stop bogus data (like a string) */
1790 finish(1);
1791 }
1792 break;
1793 case 's':
1794 alt_speller = nmalloc(strlen(optarg) + 1);
1795 strcpy(alt_speller, optarg);
1796 break;
1797 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00001798 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001799 break;
1800 case 'v':
1801 SET(VIEW_MODE);
1802 break;
1803 case 'w':
1804 SET(NO_WRAP);
1805 break;
1806 case 'x':
1807 SET(NO_HELP);
1808 break;
1809 case 'z':
1810 SET(SUSPEND);
1811 break;
1812 default:
1813 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001814 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001815 }
1816
1817 }
1818
1819 argv0 = strrchr(argv[0], '/');
1820 if ((argv0 && strstr(argv0, "pico"))
1821 || (!argv0 && strstr(argv[0], "pico")))
1822 SET(PICO_MSGS);
1823
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001824 /* See if there's a non-option in argv (first non-option is the
1825 filename, if +LINE is not given) */
1826 if (argc == 1 || argc <= optind)
1827 strcpy(filename, "");
1828 else {
1829 /* Look for the +line flag... */
1830 if (argv[optind][0] == '+') {
1831 startline = atoi(&argv[optind][1]);
1832 optind++;
1833 if (argc == 1 || argc <= optind)
1834 strcpy(filename, "");
1835 else
1836 strncpy(filename, argv[optind], 132);
1837 } else
1838 strncpy(filename, argv[optind], 132);
1839
1840 }
1841
1842
1843 /* First back up the old settings so they can be restored, duh */
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001844 tcgetattr(0, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001845
Chris Allegretta9239d742000-09-06 15:19:18 +00001846#ifdef _POSIX_VDISABLE
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001847 term = oldterm;
1848 term.c_cc[VINTR] = _POSIX_VDISABLE;
1849 term.c_cc[VQUIT] = _POSIX_VDISABLE;
1850 term.c_lflag &= ~IEXTEN;
Chris Allegretta4da1fc62000-06-21 03:00:43 +00001851 tcsetattr(0, TCSANOW, &term);
Chris Allegretta9239d742000-09-06 15:19:18 +00001852#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001853
1854 /* now ncurses init stuff... */
1855 initscr();
1856 savetty();
1857 nonl();
1858 cbreak();
1859 noecho();
1860 timeout(0);
1861
1862 /* Set up some global variables */
1863 global_init();
1864 shortcut_init();
1865 init_help_msg();
1866 help_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00001867 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001868
1869#ifdef DEBUG
1870 fprintf(stderr, _("Main: set up windows\n"));
1871#endif
1872
Chris Allegretta2a42af12000-09-12 23:02:49 +00001873 window_init();
Chris Allegretta756f2202000-09-01 13:32:47 +00001874 mouse_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001875
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001876#ifdef DEBUG
1877 fprintf(stderr, _("Main: bottom win\n"));
1878#endif
1879 /* Set up up bottom of window */
1880 display_main_list();
1881
1882#ifdef DEBUG
1883 fprintf(stderr, _("Main: open file\n"));
1884#endif
1885
1886 titlebar();
1887 if (argc == 1)
1888 new_file();
1889 else
1890 open_file(filename, 0, 0);
1891
1892 if (startline > 0)
1893 do_gotoline(startline);
1894 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00001895 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001896
Robert Siemborski6967eec2000-07-08 14:23:32 +00001897 edit_refresh();
1898 reset_cursor();
1899
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001900 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00001901
1902#ifndef _POSIX_VDISABLE
1903 /* We're going to have to do it the old way, i.e. on cygwin */
1904 raw();
1905#endif
1906
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001907 kbinput = wgetch(edit);
1908 if (kbinput == 27) { /* Grab Alt-key stuff first */
1909 switch (kbinput = wgetch(edit)) {
Chris Allegretta16e41682000-09-11 22:33:54 +00001910 /* Alt-O, suddenly very important ;) */
1911 case 79:
1912 kbinput = wgetch(edit);
1913 if (kbinput <= 'S' && kbinput >= 'P')
1914 kbinput = KEY_F(kbinput - 79);
1915#ifdef DEBUG
1916 else {
1917 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
1918 kbinput, kbinput);
1919 break;
1920 }
1921#endif
1922 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001923 case 91:
1924
1925 switch (kbinput = wgetch(edit)) {
Chris Allegretta16e41682000-09-11 22:33:54 +00001926 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
1927 kbinput = wgetch(edit);
1928 if (kbinput >= '1' && kbinput <= '5') {
1929 kbinput = KEY_F(kbinput - 48);
1930 wgetch(edit);
1931 }
1932 else if (kbinput >= '7' && kbinput <= '9') {
1933 kbinput = KEY_F(kbinput - 49);
1934 wgetch(edit);
1935 }
1936 else if (kbinput == 126)
1937 kbinput = KEY_HOME;
1938
1939#ifdef DEBUG
1940 else {
1941 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
1942 kbinput, kbinput);
1943 break;
1944 }
1945#endif
1946
1947 break;
1948 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
1949 kbinput = wgetch(edit);
1950 wgetch(edit);
1951 switch (kbinput) {
1952 case '0':
1953 kbinput = KEY_F(9);
1954 break;
1955 case '1':
1956 kbinput = KEY_F(10);
1957 break;
1958 case '3':
1959 kbinput = KEY_F(11);
1960 break;
1961 case '4':
1962 kbinput = KEY_F(12);
1963 break;
1964#ifdef DEBUG
1965 default:
1966 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
1967 kbinput, kbinput);
1968 break;
1969#endif
1970
1971 }
1972 break;
1973 case '3': /* Alt-[-3 = Delete? */
1974 kbinput = NANO_DELETE_KEY;
1975 wgetch(edit);
1976 break;
1977 case '4': /* Alt-[-4 = End? */
1978 kbinput = NANO_END_KEY;
1979 wgetch(edit);
1980 break;
1981 case '5': /* Alt-[-5 = Page Up */
1982 kbinput = KEY_PPAGE;
1983 wgetch(edit);
1984 break;
1985 case '6': /* Alt-[-6 = Page Down */
1986 kbinput = KEY_NPAGE;
1987 wgetch(edit);
1988 break;
1989 case '[': /* Alt-[-[-[A-E], F1-F5 in linux console */
1990 kbinput = wgetch(edit);
1991 if (kbinput >= 'A' && kbinput <= 'E')
1992 kbinput = KEY_F(kbinput - 64);
1993 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001994 case 'A':
1995 kbinput = KEY_UP;
1996 break;
1997 case 'B':
1998 kbinput = KEY_DOWN;
1999 break;
2000 case 'C':
2001 kbinput = KEY_RIGHT;
2002 break;
2003 case 'D':
2004 kbinput = KEY_LEFT;
2005 break;
2006 case 'H':
2007 kbinput = KEY_HOME;
2008 break;
2009 case 'F':
2010 kbinput = KEY_END;
2011 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002012 default:
2013#ifdef DEBUG
2014 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
2015 kbinput, kbinput);
2016#endif
2017 break;
2018 }
2019 break;
2020 default:
2021
2022 /* Check for the altkey defs.... */
2023 for (i = 0; i <= MAIN_LIST_LEN - 1; i++)
2024 if (kbinput == main_list[i].altval ||
2025 kbinput == main_list[i].altval - 32) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002026 kbinput = main_list[i].val;
2027 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002028 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002029#ifndef NANO_SMALL
2030 /* And for toggle switches */
2031 for (i = 0; i <= TOGGLE_LEN - 1 && !keyhandled; i++)
2032 if (kbinput == toggles[i].val ||
2033 kbinput == toggles[i].val - 32) {
2034 do_toggle(i);
2035 keyhandled = 1;
2036 break;
2037 }
2038#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002039#ifdef DEBUG
2040 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
2041 kbinput);
2042#endif
2043 break;
2044 }
2045 }
2046 /* Look through the main shortcut list to see if we've hit a
2047 shortcut key */
Chris Allegretta756f2202000-09-01 13:32:47 +00002048 for (i = 0; i < MAIN_LIST_LEN && !keyhandled; i++) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002049 if (kbinput == main_list[i].val ||
2050 (main_list[i].misc1 && kbinput == main_list[i].misc1) ||
2051 (main_list[i].misc2 && kbinput == main_list[i].misc2)) {
2052 if (ISSET(VIEW_MODE) && !main_list[i].viewok)
2053 print_view_warning();
2054 else
2055 main_list[i].func();
2056 keyhandled = 1;
2057 }
2058 }
Chris Allegretta9239d742000-09-06 15:19:18 +00002059#ifndef _POSIX_VDISABLE
2060 /* Since we're in raw mode, we have to catch ^Q and ^S */
2061 if (kbinput == 17 || kbinput == 19)
2062 keyhandled = 1;
2063
2064 /* And catch ^Z by hand when triggered */
2065 if (kbinput == 26) {
2066 if (ISSET(SUSPEND))
2067 do_suspend(0);
2068 keyhandled = 1;
2069 }
2070#endif
2071
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002072 /* Last gasp, stuff that's not in the main lists */
2073 if (!keyhandled)
2074 switch (kbinput) {
2075#ifndef NANO_SMALL
2076#ifdef NCURSES_MOUSE_VERSION
2077 case KEY_MOUSE:
2078 do_mouse();
2079 break;
2080#endif
2081#endif
2082 case 0: /* Erg */
2083 do_next_word();
2084 break;
2085 case 331: /* Stuff that we don't want to do squat */
2086 case -1:
2087 case 410: /* Must ignore this, it gets sent when we resize */
2088 break;
2089 default:
2090#ifdef DEBUG
2091 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
2092#endif
2093 /* We no longer stop unhandled sequences so that people with
2094 odd character sets can type... */
2095
2096 if (ISSET(VIEW_MODE)) {
2097 print_view_warning();
2098 break;
2099 }
2100 do_char(kbinput);
2101 }
Chris Allegretta756f2202000-09-01 13:32:47 +00002102 if (ISSET(CONSTUPDATE)) {
2103 if (ISSET(DISABLE_CURPOS))
2104 UNSET(DISABLE_CURPOS);
2105 else
2106 do_cursorpos();
2107 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002108
2109 reset_cursor();
2110 wrefresh(edit);
2111 keyhandled = 0;
2112 }
2113
2114 getchar();
2115 finish(0);
2116
2117}