blob: 67fc1595976932e86b703d65ab466e57aae45f86 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
Chris Allegrettad757e252003-01-15 19:33:27 +00005 * Copyright (C) 1999-2003 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * 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 *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * 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
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
Chris Allegretta08020882001-01-29 23:37:54 +000028#include <setjmp.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000029#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000035#include <sys/types.h>
36#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000037#include <errno.h>
38#include <ctype.h>
39#include <locale.h>
40#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000041#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#include "proto.h"
43#include "nano.h"
44
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000045#ifdef HAVE_TERMIOS_H
46#include <termios.h>
47#endif
48
49#ifdef HAVE_TERMIO_H
50#include <termio.h>
51#endif
52
53#ifdef HAVE_GETOPT_H
54#include <getopt.h>
55#endif
56
Chris Allegretta6fe61492001-05-21 12:56:25 +000057#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000058static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000060#ifndef DISABLE_WRAPPING
61static int same_line_wrap = 0; /* Whether wrapped text should be
62 prepended to the next line */
63#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000064
Chris Allegretta6df90f52002-07-19 01:08:59 +000065static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000066static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000067
Chris Allegretta08020882001-01-29 23:37:54 +000068static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
69
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000071RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000072{
73 if (!ISSET(NO_HELP)) {
74 mvwaddstr(bottomwin, 1, 0, hblank);
75 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000076 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000077 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000078
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000079 wrefresh(bottomwin);
80 endwin();
81
82 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000083 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000084
Chris Allegrettad8451932003-03-11 03:50:40 +000085#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
86 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
87 save_history();
88#endif
89
Chris Allegretta6232d662002-05-12 19:52:15 +000090#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000091 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000092#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000093
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094 exit(sigage);
95}
96
97/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +000098void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099{
100 va_list ap;
101
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000102 endwin();
103 curses_ended = TRUE;
104
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000106 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000107
Chris Allegretta6df90f52002-07-19 01:08:59 +0000108 va_start(ap, msg);
109 vfprintf(stderr, msg, ap);
110 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000111
Chris Allegretta32da4562002-01-02 15:12:21 +0000112 /* save the currently loaded file if it's been modified */
113 if (ISSET(MODIFIED))
114 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000115
Chris Allegretta355fbe52001-07-14 19:32:47 +0000116#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000117 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000118 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000119 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000120
121 tmp = open_files;
122
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000123 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000124 open_files = open_files->prev;
125
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000126 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000127
128 /* if we already saved the file above (i. e. if it was the
129 currently loaded file), don't save it again */
130 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000131 /* make sure open_files->fileage and fileage, and
132 open_files->filebot and filebot, are in sync; they
133 might not be if lines have been cut from the top or
134 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000135 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000136 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000137 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000138 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000139 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000140 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000141 open_files = open_files->next;
142 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143 }
144#endif
145
Chris Allegretta6df90f52002-07-19 01:08:59 +0000146 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147}
148
Chris Allegretta6df90f52002-07-19 01:08:59 +0000149void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000151 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000152 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153
Chris Allegretta6df90f52002-07-19 01:08:59 +0000154 /* If we can't save, we have REAL bad problems, but we might as well
155 TRY. */
156 if (die_filename[0] == '\0')
157 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000158 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000160
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000161 strcpy(buf, die_filename);
162 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000163 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000164 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000165 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 if (ret[0] != '\0')
167 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000168
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000169 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000171 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000173
174 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000175}
176
Chris Allegrettae61e8302001-01-14 05:18:27 +0000177/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000179void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000180{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000181 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000182}
183
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000184void print_view_warning(void)
185{
186 statusbar(_("Key illegal in VIEW mode"));
187}
188
Chris Allegretta56214c62001-09-27 02:46:53 +0000189/* Initialize global variables - no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000190 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000191void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000193 current_x = 0;
194 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000195
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000196 editwinrows = LINES - 5 + no_help();
197 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000198 die_too_small();
199
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000200 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000201 if (!save_cutbuffer)
202 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000203 current = NULL;
204 edittop = NULL;
205 editbot = NULL;
206 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000207 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000209
Chris Allegretta6fe61492001-05-21 12:56:25 +0000210#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000211 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000212 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000213 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000214 if (fill < 0)
215 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000216#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000217
Chris Allegretta88b09152001-05-17 11:35:43 +0000218 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000219 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000220 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000221}
222
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000223void window_init(void)
224{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000225 editwinrows = LINES - 5 + no_help();
226 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000227 die_too_small();
228
Chris Allegretta1a128af2003-01-26 04:15:56 +0000229 if (edit != NULL)
230 delwin(edit);
231 if (topwin != NULL)
232 delwin(topwin);
233 if (bottomwin != NULL)
234 delwin(bottomwin);
235
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000236 /* Set up the main text window. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000237 edit = newwin(editwinrows, COLS, 2, 0);
238
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000239 /* And the other windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000240 topwin = newwin(2, COLS, 0, 0);
241 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
242
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000243 /* This is so the keypad still works after a Meta-X, for example. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000244 keypad(edit, TRUE);
245 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246}
247
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000248#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249void mouse_init(void)
250{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252 mousemask(BUTTON1_RELEASED, NULL);
253 mouseinterval(50);
254 } else
255 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000257#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258
259#ifndef DISABLE_HELP
260/* This function allocates help_text, and stores the help string in it.
261 * help_text should be NULL initially. */
262void help_init(void)
263{
Chris Allegretta908f7702003-01-15 11:18:58 +0000264 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000265 char *ptr = NULL;
266#ifndef NANO_SMALL
267 const toggle *t;
268#endif
269 const shortcut *s;
270
271 /* First set up the initial help text for the current function */
272 if (currshortcut == whereis_list || currshortcut == replace_list
273 || currshortcut == replace_list_2)
274 ptr = _("Search Command Help Text\n\n "
275 "Enter the words or characters you would like to search "
276 "for, then hit enter. If there is a match for the text you "
277 "entered, the screen will be updated to the location of the "
278 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000279 "The previous search string will be shown in brackets after "
280 "the Search: prompt. Hitting Enter without entering any text "
281 "will perform the previous search.\n\n The following function "
282 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000283 else if (currshortcut == goto_list)
284 ptr = _("Go To Line Help Text\n\n "
285 "Enter the line number that you wish to go to and hit "
286 "Enter. If there are fewer lines of text than the "
287 "number you entered, you will be brought to the last line "
288 "of the file.\n\n The following function keys are "
289 "available in Go To Line mode:\n\n");
290 else if (currshortcut == insertfile_list)
291 ptr = _("Insert File Help Text\n\n "
292 "Type in the name of a file to be inserted into the current "
293 "file buffer at the current cursor location.\n\n "
294 "If you have compiled nano with multiple file buffer "
295 "support, and enable multiple buffers with the -F "
296 "or --multibuffer command line flags, the Meta-F toggle, or "
297 "a nanorc file, inserting a file will cause it to be "
298 "loaded into a separate buffer (use Meta-< and > to switch "
299 "between file buffers).\n\n If you need another blank "
300 "buffer, do not enter any filename, or type in a "
301 "nonexistent filename at the prompt and press "
302 "Enter.\n\n The following function keys are "
303 "available in Insert File mode:\n\n");
304 else if (currshortcut == writefile_list)
305 ptr = _("Write File Help Text\n\n "
306 "Type the name that you wish to save the current file "
307 "as and hit Enter to save the file.\n\n If you have "
308 "selected text with Ctrl-^, you will be prompted to "
309 "save only the selected portion to a separate file. To "
310 "reduce the chance of overwriting the current file with "
311 "just a portion of it, the current filename is not the "
312 "default in this mode.\n\n The following function keys "
313 "are available in Write File mode:\n\n");
314#ifndef DISABLE_BROWSER
315 else if (currshortcut == browser_list)
316 ptr = _("File Browser Help Text\n\n "
317 "The file browser is used to visually browse the "
318 "directory structure to select a file for reading "
319 "or writing. You may use the arrow keys or Page Up/"
320 "Down to browse through the files, and S or Enter to "
321 "choose the selected file or enter the selected "
322 "directory. To move up one level, select the directory "
323 "called \"..\" at the top of the file list.\n\n The "
324 "following function keys are available in the file "
325 "browser:\n\n");
326 else if (currshortcut == gotodir_list)
327 ptr = _("Browser Go To Directory Help Text\n\n "
328 "Enter the name of the directory you would like to "
329 "browse to.\n\n If tab completion has not been disabled, "
330 "you can use the TAB key to (attempt to) automatically "
331 "complete the directory name.\n\n The following function "
332 "keys are available in Browser Go To Directory mode:\n\n");
333#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000334#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000335 else if (currshortcut == spell_list)
336 ptr = _("Spell Check Help Text\n\n "
337 "The spell checker checks the spelling of all text "
338 "in the current file. When an unknown word is "
339 "encountered, it is highlighted and a replacement can "
340 "be edited. It will then prompt to replace every "
341 "instance of the given misspelled word in the "
342 "current file.\n\n The following other functions are "
343 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000344#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000345#ifndef NANO_SMALL
346 else if (currshortcut == extcmd_list)
347 ptr = _("External Command Help Text\n\n "
348 "This menu allows you to insert the output of a command "
349 "run by the shell into the current buffer (or a new "
350 "buffer in multibuffer mode).\n\n The following keys are "
351 "available in this mode:\n\n");
352#endif
353 else /* Default to the main help list */
354 ptr = _(" nano help text\n\n "
355 "The nano editor is designed to emulate the functionality and "
356 "ease-of-use of the UW Pico text editor. There are four main "
357 "sections of the editor: The top line shows the program "
358 "version, the current filename being edited, and whether "
359 "or not the file has been modified. Next is the main editor "
360 "window showing the file being edited. The status line is "
361 "the third line from the bottom and shows important messages. "
362 "The bottom two lines show the most commonly used shortcuts "
363 "in the editor.\n\n "
364 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000365 "sequences are notated with a caret (^) symbol and can be "
366 "entered either by using the Control (Ctrl) key or pressing the "
367 "Esc key twice. Escape-key sequences are notated with the Meta "
368 "(M) symbol and can be entered using either the Esc, Alt or "
369 "Meta key depending on your keyboard setup. Also, pressing Esc "
370 "twice and then typing a three-digit number from 000 to 255 "
371 "will enter the character with the corresponding ASCII code. "
372 "The following keystrokes are available in the main editor "
373 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000374
Chris Allegretta908f7702003-01-15 11:18:58 +0000375 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000376
377 /* The space needed for the shortcut lists, at most COLS characters,
378 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000379 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000380
381#ifndef NANO_SMALL
382 /* If we're on the main list, we also count the toggle help text.
383 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
384 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000385 if (currshortcut == main_list) {
386 size_t endislen = strlen(_("enable/disable"));
387
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000388 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000389 allocsize += 8 + strlen(t->desc) + endislen;
390 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000391#endif /* !NANO_SMALL */
392
393 /* help_text has been freed and set to NULL unless the user resized
394 * while in the help screen. */
395 free(help_text);
396
397 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000398 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000399
400 /* Now add the text we want */
401 strcpy(help_text, ptr);
402 ptr = help_text + strlen(help_text);
403
404 /* Now add our shortcut info */
405 for (s = currshortcut; s != NULL; s = s->next) {
406 /* true if the character in s->altval is shown in first column */
407 int meta_shortcut = 0;
408
409 if (s->val > 0 && s->val < 32)
410 ptr += sprintf(ptr, "^%c", s->val + 64);
411#ifndef NANO_SMALL
412 else if (s->val == NANO_CONTROL_SPACE)
413 ptr += sprintf(ptr, "^%.6s", _("Space"));
414 else if (s->altval == NANO_ALT_SPACE) {
415 meta_shortcut = 1;
416 ptr += sprintf(ptr, "M-%.5s", _("Space"));
Chris Allegretta7662c862003-01-13 01:35:15 +0000417 } else if (s->val == KEY_UP)
418 ptr += sprintf(ptr, "%.2s", _("Up"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000419#endif
420 else if (s->altval > 0) {
421 meta_shortcut = 1;
422 ptr += sprintf(ptr, "M-%c", s->altval -
423 (('A' <= s->altval && s->altval <= 'Z') ||
424 'a' <= s->altval ? 32 : 0));
425 }
426 /* Hack */
427 else if (s->val >= 'a') {
428 meta_shortcut = 1;
429 ptr += sprintf(ptr, "M-%c", s->val - 32);
430 }
431
432 *(ptr++) = '\t';
433
434 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
435 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
436
437 *(ptr++) = '\t';
438
439 if (!meta_shortcut && s->altval > 0)
440 ptr += sprintf(ptr, "(M-%c)", s->altval -
441 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
442 ? 32 : 0));
443
444 *(ptr++) = '\t';
445
446 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000447 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000448 }
449
450#ifndef NANO_SMALL
451 /* And the toggles... */
452 if (currshortcut == main_list)
453 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000454 assert(t->desc != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000455 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", t->val - 32, t->desc,
456 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000457 }
458#endif /* !NANO_SMALL */
459
460 /* If all went well, we didn't overwrite the allocated space for
461 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000462 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000463}
464#endif
465
466/* Create a new filestruct node. Note that we specifically do not set
467 * prevnode->next equal to the new line. */
468filestruct *make_new_node(filestruct *prevnode)
469{
470 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
471
472 newnode->data = NULL;
473 newnode->prev = prevnode;
474 newnode->next = NULL;
475 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
476
477 return newnode;
478}
479
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000480/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000481filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000482{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000483 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000484
Chris Allegretta6df90f52002-07-19 01:08:59 +0000485 assert(src != NULL);
486
Chris Allegretta88b09152001-05-17 11:35:43 +0000487 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000488 dst->next = src->next;
489 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000490 strcpy(dst->data, src->data);
491 dst->lineno = src->lineno;
492
493 return dst;
494}
495
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000496/* Splice a node into an existing filestruct. */
497void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
498{
499 if (newnode != NULL) {
500 newnode->next = end;
501 newnode->prev = begin;
502 }
503 if (begin != NULL)
504 begin->next = newnode;
505 if (end != NULL)
506 end->prev = newnode;
507}
508
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000509/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000510void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000511{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000512 assert(fileptr != NULL);
513
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000514 if (fileptr->prev != NULL)
515 fileptr->prev->next = fileptr->next;
516
517 if (fileptr->next != NULL)
518 fileptr->next->prev = fileptr->prev;
519}
520
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000521/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000524 if (fileptr != NULL) {
525 if (fileptr->data != NULL)
526 free(fileptr->data);
527 free(fileptr);
528 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529}
530
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000531/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000532filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000533{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000534 filestruct *head; /* copy of src, top of the copied list */
535 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000536
Chris Allegretta6df90f52002-07-19 01:08:59 +0000537 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000538
Chris Allegretta6df90f52002-07-19 01:08:59 +0000539 prev = copy_node(src);
540 prev->prev = NULL;
541 head = prev;
542 src = src->next;
543 while (src != NULL) {
544 prev->next = copy_node(src);
545 prev->next->prev = prev;
546 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000549 }
550
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000552 return head;
553}
554
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000555/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000556void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000557{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000558 if (src != NULL) {
559 while (src->next != NULL) {
560 src = src->next;
561 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000563 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000564#endif
565 }
566 delete_node(src);
567#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000568 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000569#endif
570 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571}
572
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574{
575 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000576 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578 assert(fileage == NULL || fileage != fileage->next);
579 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581}
582
Chris Allegretta6df90f52002-07-19 01:08:59 +0000583void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000584{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000585 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000587 else {
588 int lineno = fileptr->prev->lineno;
589
590 assert(fileptr != fileptr->next);
591 for (; fileptr != NULL; fileptr = fileptr->next)
592 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000593 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594}
595
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000596/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000597 * strings to translate and takes out the parts that shouldn't be
598 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000599void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000600 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000601{
602 printf(" %s\t", shortflag);
603 if (strlen(shortflag) < 8)
604 printf("\t");
605
606#ifdef HAVE_GETOPT_LONG
607 printf("%s\t", longflag);
608 if (strlen(longflag) < 8)
609 printf("\t\t");
610 else if (strlen(longflag) < 16)
611 printf("\t");
612#endif
613
614 printf("%s\n", desc);
615}
616
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000617void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000618{
619#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000620 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
621 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000622#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000623 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
624 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000625#endif /* HAVE_GETOPT_LONG */
626
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000627 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000628 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000629#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000630 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000631 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000632#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000633#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000634 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000635#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000636#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000637#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000638 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000639#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000640 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
641#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000642#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000643 print1opt("-M", "--mac", _("Write file in Mac format"));
644 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000645#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000646#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000647 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000648#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000649#ifdef HAVE_REGEX_H
650 print1opt("-R", "--regexp", _("Do regular expression searches"));
651#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000652#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000653 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000654#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000655 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000656 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000657#ifdef ENABLE_COLOR
658 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
659#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000660 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000661#ifndef NANO_SMALL
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000662 print1opt("-d", "--rebinddelete", _("Fix Backspace if it acts like Delete"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000663 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
664 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000665#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000666 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000667#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000668 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000669#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000670#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000671 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000672#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000673 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000674#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000675 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000676#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000677#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000678 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000679#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000680 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
681 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000682#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000683 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000684#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000685 print1opt("-x", "--nohelp", _("Don't show help window"));
686 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000687
688 /* this is a special case */
689 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000690
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000691 exit(0);
692}
693
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000694void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000695{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000696 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000697 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000698 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000699 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000700 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000701
Chris Allegrettae6600372003-01-17 03:39:41 +0000702#ifndef ENABLE_NLS
703 printf(" --disable-nls");
704#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000705#ifdef DEBUG
706 printf(" --enable-debug");
707#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000708#ifdef NANO_EXTRA
709 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000710#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000711#ifdef NANO_SMALL
712 printf(" --enable-tiny");
713#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000714#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000715 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000716#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000717#ifdef DISABLE_HELP
718 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000719#endif
720#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000721 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000722#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000723#if defined(DISABLE_MOUSE) || !defined(NCURSES_MOUSE_VERSION)
Chris Allegretta84de5522001-04-12 14:51:48 +0000724 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000725#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000726#ifdef DISABLE_OPERATINGDIR
727 printf(" --disable-operatingdir");
728#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000729#ifdef DISABLE_SPELLER
730 printf(" --disable-speller");
731#endif
732#ifdef DISABLE_TABCOMP
733 printf(" --disable-tabcomp");
734#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000735#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000736#ifdef DISABLE_WRAPPING
737 printf(" --disable-wrapping");
738#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000739#ifdef DISABLE_ROOTWRAP
740 printf(" --disable-wrapping-as-root");
741#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000742#ifdef ENABLE_COLOR
743 printf(" --enable-color");
744#endif
745#ifdef ENABLE_MULTIBUFFER
746 printf(" --enable-multibuffer");
747#endif
748#ifdef ENABLE_NANORC
749 printf(" --enable-nanorc");
750#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000751#ifdef USE_SLANG
752 printf(" --with-slang");
753#endif
754 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000755}
756
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000757/* Stuff we do when we abort from programs and want to clean up the
758 * screen. This doesn't do much right now. */
759void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000760{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000761 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000762}
763
764int no_help(void)
765{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000766 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000767}
768
Chris Allegrettad865da12002-07-29 23:46:38 +0000769#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000770void nano_disabled_msg(void)
771{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000772 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000773}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000774#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000775
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000776#ifndef NANO_SMALL
777static int pid; /* This is the PID of the newly forked process
778 * below. It must be global since the signal
779 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000780RETSIGTYPE cancel_fork(int signal)
781{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000782 if (kill(pid, SIGKILL) == -1)
783 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000784}
785
786int open_pipe(const char *command)
787{
788 int fd[2];
789 FILE *f;
790 struct sigaction oldaction, newaction;
791 /* original and temporary handlers for SIGINT */
792#ifdef _POSIX_VDISABLE
793 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000794#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000795 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000796 /* cancel_sigs == 1 means that sigaction() failed without changing
797 * the signal handlers. cancel_sigs == 2 means the signal handler
798 * was changed, but the tcsetattr didn't succeed.
799 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000800 * I use this variable since it is important to put things back when
801 * we finish, even if we get errors. */
802
803 /* Make our pipes. */
804
805 if (pipe(fd) == -1) {
806 statusbar(_("Could not pipe"));
807 return 1;
808 }
809
810 /* Fork a child. */
811
812 if ((pid = fork()) == 0) {
813 close(fd[0]);
814 dup2(fd[1], fileno(stdout));
815 dup2(fd[1], fileno(stderr));
816 /* If execl() returns at all, there was an error. */
817
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000818 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000819 exit(0);
820 }
821
822 /* Else continue as parent. */
823
824 close(fd[1]);
825
826 if (pid == -1) {
827 close(fd[0]);
828 statusbar(_("Could not fork"));
829 return 1;
830 }
831
832 /* Before we start reading the forked command's output, we set
833 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000834 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000835 cancel_sigs = 1;
836 nperror("sigaction");
837 } else {
838 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000839 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000840 cancel_sigs = 1;
841 nperror("sigaction");
842 }
843 }
844 /* Note that now oldaction is the previous SIGINT signal handler,
845 * to be restored later. */
846
847 /* See if the platform supports disabling individual control
848 * characters. */
849#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000850 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000851 cancel_sigs = 2;
852 nperror("tcgetattr");
853 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000854 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000855 newterm = term;
856 /* Grab oldterm's VINTR key :-) */
857 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
858 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
859 cancel_sigs = 2;
860 nperror("tcsetattr");
861 }
862 }
863#endif /* _POSIX_VDISABLE */
864
865 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000866 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000867 nperror("fdopen");
868
869 read_file(f, "stdin", 0);
870 /* if multibuffer mode is on, we could be here in view mode; if so,
871 don't set the modification flag */
872 if (!ISSET(VIEW_MODE))
873 set_modified();
874
875 if (wait(NULL) == -1)
876 nperror("wait");
877
878#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000879 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000880 nperror("tcsetattr");
881#endif /* _POSIX_VDISABLE */
882
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000883 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000884 nperror("sigaction");
885
886 return 0;
887}
888#endif /* NANO_SMALL */
889
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000890#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000891void do_mouse(void)
892{
893 MEVENT mevent;
894 int currslen;
895 const shortcut *s = currshortcut;
896
897 if (getmouse(&mevent) == ERR)
898 return;
899
900 /* If mouse not in edit or bottom window, return */
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000901 if (wenclose(edit, mevent.y, mevent.x) && currshortcut == main_list) {
902 int sameline;
903 /* Did they click on the line with the cursor? If they
904 clicked on the cursor, we set the mark. */
905 size_t xcur;
906 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000907
908 /* Subtract out size of topwin. Perhaps we need a constant
909 * somewhere? */
910 mevent.y -= 2;
911
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000912 sameline = mevent.y == current_y;
913
914 /* Move to where the click occurred. */
915 for(; current_y < mevent.y && current->next != NULL; current_y++)
916 current = current->next;
917 for(; current_y > mevent.y && current->prev != NULL; current_y--)
918 current = current->prev;
919
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000920 xcur = actual_x(current->data, get_page_start(xplustabs()) + mevent.x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000921
922 /* Selecting where the cursor is toggles the mark. As does
923 selecting beyond the line length with the cursor at the end of
924 the line. */
925 if (sameline && xcur == current_x) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000926 if (ISSET(VIEW_MODE)) {
927 print_view_warning();
928 return;
929 }
930 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000931 }
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000932
933 current_x = xcur;
934 placewewant = xplustabs();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000935 edit_refresh();
936 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
937 int i, k;
938
939 if (currshortcut == main_list)
940 currslen = MAIN_VISIBLE;
941 else
942 currslen = length_of_list(currshortcut);
943
944 if (currslen < 2)
945 k = COLS / 6;
946 else
947 k = COLS / ((currslen + (currslen %2)) / 2);
948
949 /* Determine what shortcut list was clicked */
950 mevent.y -= (editwinrows + 3);
951
952 if (mevent.y < 0) /* They clicked on the statusbar */
953 return;
954
955 /* Don't select stuff beyond list length */
956 if (mevent.x / k >= currslen)
957 return;
958
959 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
960 s = s->next;
961
962 /* And ungetch that value */
963 ungetch(s->val);
964
965 /* And if it's an alt-key sequence, we should probably send alt
966 too ;-) */
967 if (s->val >= 'a' && s->val <= 'z')
968 ungetch(27);
969 }
970}
971#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000972
Chris Allegretta6df90f52002-07-19 01:08:59 +0000973/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000974void do_char(char ch)
975{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976 size_t current_len = strlen(current->data);
977#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
978 int refresh = 0;
979 /* Do we have to run edit_refresh(), or can we get away with
980 * update_line()? */
981#endif
982
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000983 /* magic-line: when a character is inserted on the current magic line,
984 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000985 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000986 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000987 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000988 }
989
Chris Allegretta6df90f52002-07-19 01:08:59 +0000990 /* more dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000991 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000992 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000993 memmove(&current->data[current_x + 1],
994 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +0000995 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000996 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000997 totsize++;
998 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000999
Chris Allegretta6df90f52002-07-19 01:08:59 +00001000#ifndef NANO_SMALL
1001 /* note that current_x has not yet been incremented */
1002 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001003 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001004#endif
1005
Chris Allegretta6df90f52002-07-19 01:08:59 +00001006 do_right();
1007
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001008#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001009 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001010 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001011#endif
1012
Chris Allegretta6df90f52002-07-19 01:08:59 +00001013#ifdef ENABLE_COLOR
1014 refresh = 1;
1015#endif
1016
1017#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1018 if (refresh)
1019 edit_refresh();
1020#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001021}
1022
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001023int do_backspace(void)
1024{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001025 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001026 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001027 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001028 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029 return 1;
1030}
1031
1032int do_delete(void)
1033{
1034 int refresh = 0;
1035
1036 /* blbf -> blank line before filebot (see below) */
1037 int blbf = 0;
1038
1039 if (current->next == filebot && current->data[0] == '\0')
1040 blbf = 1;
1041
1042 placewewant = xplustabs();
1043
1044 if (current_x != strlen(current->data)) {
1045 /* Let's get dangerous */
1046 memmove(&current->data[current_x], &current->data[current_x + 1],
1047 strlen(current->data) - current_x);
1048
1049 align(&current->data);
1050#ifdef ENABLE_COLOR
1051 refresh = 1;
1052#endif
1053 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1054 /* We can delete the line before filebot only if it is blank: it
1055 becomes the new magic line then. */
1056
1057 filestruct *foo;
1058
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001059 current->data = charealloc(current->data,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001060 strlen(current->data) +
1061 strlen(current->next->data) + 1);
1062 strcat(current->data, current->next->data);
1063
1064 foo = current->next;
1065 if (filebot == foo) {
1066 filebot = current;
1067 editbot = current;
1068 }
1069
1070 unlink_node(foo);
1071 delete_node(foo);
1072 renumber(current);
1073 totlines--;
1074 refresh = 1;
1075 } else
1076 return 0;
1077
1078 totsize--;
1079 set_modified();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001080 update_line(current, current_x);
1081 if (refresh)
1082 edit_refresh();
1083 return 1;
1084}
1085
1086int do_tab(void)
1087{
1088 do_char('\t');
1089 return 1;
1090}
1091
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001092/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001093int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001094{
Chris Allegrettae3167732001-03-18 16:59:34 +00001095 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001096 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001097
Chris Allegretta6df90f52002-07-19 01:08:59 +00001098 newnode = make_new_node(current);
1099 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001100 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001101
Chris Allegrettaff989832001-09-17 13:48:00 +00001102#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001103 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001104 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001105 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001106 const char *spc = current->data;
1107
1108 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001109 extra++;
1110 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001111 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001112 /* If current_x < extra, then we are breaking the line in the
1113 * indentation. Autoindenting should add only current_x
1114 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001115 if (current_x < extra)
1116 extra = current_x;
1117 else
1118 current_x = extra;
1119 totsize += extra;
1120
1121 newnode->data = charalloc(strlen(tmp) + extra + 1);
1122 strncpy(newnode->data, current->data, extra);
1123 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001124 } else
1125#endif
1126 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001127 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001128 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001129 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001130 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001131 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001132
Chris Allegretta6df90f52002-07-19 01:08:59 +00001133 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001134 filebot = newnode;
1135 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001136 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001137 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001138
1139 totsize++;
1140 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001141 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001142 align(&current->data);
1143
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001144 /* The logic here is as follows:
1145 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001146 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001147 * -> otherwise, we want simply to redraw the screen and update
1148 * where we think the cursor is.
1149 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001150 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001151#ifndef NANO_SMALL
1152 if (ISSET(SMOOTHSCROLL))
1153 edit_update(current, NONE);
1154 else
1155#endif
1156 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001157 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001158 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001159 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001160 edit_refresh();
1161 update_cursor();
1162 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001163
1164 totlines++;
1165 set_modified();
1166
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001167 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168 return 1;
1169}
1170
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001171#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001172int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001174 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178 /* Skip letters in this word first. */
1179 while (current->data[current_x] != '\0' &&
1180 isalnum((int)current->data[current_x]))
1181 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182
Chris Allegretta6df90f52002-07-19 01:08:59 +00001183 for (; current != NULL; current = current->next) {
1184 while (current->data[current_x] != '\0' &&
1185 !isalnum((int)current->data[current_x]))
1186 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187
Chris Allegretta6df90f52002-07-19 01:08:59 +00001188 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189 break;
1190
Chris Allegretta6df90f52002-07-19 01:08:59 +00001191 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001192 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001193 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001194 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001195
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001196 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001197
Chris Allegrettad865da12002-07-29 23:46:38 +00001198 if (current->lineno >= editbot->lineno) {
1199 /* If we're on the last line, don't center the screen. */
1200 if (current->lineno == filebot->lineno)
1201 edit_refresh();
1202 else
1203 edit_update(current, CENTER);
1204 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001205 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001206 /* If we've jumped lines, refresh the old line. We can't just
1207 use current->prev here, because we may have skipped over some
1208 blank lines, in which case the previous line is the wrong
1209 one. */
1210 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001211 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001212 /* If the mark was set, then the lines between old and
1213 current have to be updated too. */
1214 if (ISSET(MARK_ISSET)) {
1215 while (old->next != current) {
1216 old = old->next;
1217 update_line(old, 0);
1218 }
1219 }
1220 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001221 update_line(current, current_x);
1222 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001223 return 0;
1224}
1225
Chris Allegretta6df90f52002-07-19 01:08:59 +00001226/* The same thing for backwards. */
1227int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001228{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001229 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001230
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001231 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001232
Chris Allegretta6df90f52002-07-19 01:08:59 +00001233 /* Skip letters in this word first. */
1234 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1235 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001236
Chris Allegretta6df90f52002-07-19 01:08:59 +00001237 for (; current != NULL; current = current->prev) {
1238 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1239 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001240
Chris Allegretta6df90f52002-07-19 01:08:59 +00001241 if (current_x >= 0)
1242 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001243
Chris Allegretta6df90f52002-07-19 01:08:59 +00001244 if (current->prev != NULL)
1245 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001246 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001247
Chris Allegretta6df90f52002-07-19 01:08:59 +00001248 if (current != NULL) {
1249 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1250 current_x--;
1251 } else {
1252 current = fileage;
1253 current_x = 0;
1254 }
1255
Chris Allegretta76e291b2001-10-14 19:05:10 +00001256 placewewant = xplustabs();
1257
Chris Allegrettad865da12002-07-29 23:46:38 +00001258 if (current->lineno <= edittop->lineno) {
1259 /* If we're on the first line, don't center the screen. */
1260 if (current->lineno == fileage->lineno)
1261 edit_refresh();
1262 else
1263 edit_update(current, CENTER);
1264 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001265 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001266 /* If we've jumped lines, refresh the old line. We can't just
1267 use current->prev here, because we may have skipped over some
1268 blank lines, in which case the previous line is the wrong
1269 one. */
1270 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001271 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001272 /* If the mark was set, then the lines between old and
1273 current have to be updated too. */
1274 if (ISSET(MARK_ISSET)) {
1275 while (old->prev != current) {
1276 old = old->prev;
1277 update_line(old, 0);
1278 }
1279 }
1280 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001281 update_line(current, current_x);
1282 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001283 return 0;
1284}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001285#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001286
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001287int do_mark(void)
1288{
1289#ifdef NANO_SMALL
1290 nano_disabled_msg();
1291#else
1292 if (!ISSET(MARK_ISSET)) {
1293 statusbar(_("Mark Set"));
1294 SET(MARK_ISSET);
1295 mark_beginbuf = current;
1296 mark_beginx = current_x;
1297 } else {
1298 statusbar(_("Mark UNset"));
1299 UNSET(MARK_ISSET);
1300 edit_refresh();
1301 }
1302#endif
1303 return 1;
1304}
1305
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001306#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001307void wrap_reset(void)
1308{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001309 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001310}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001311#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001312
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001313#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001314/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001315 * moved forward since the last typed character. Return value:
1316 * whether we wrapped. */
1317int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001318{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001319 size_t len = strlen(inptr->data); /* length of the line we wrap */
1320 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001321 int wrap_loc = -1; /* index of inptr->data where we wrap */
1322 int word_back = -1;
1323#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001324 const char *indentation = NULL;
1325 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001326 int indent_len = 0; /* strlen(indentation) */
1327#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001328 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001329 int after_break_len; /* strlen(after_break) */
1330 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001331 const char *wrap_line = NULL;
1332 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001333 int wrap_line_len = 0; /* strlen(wrap_line) */
1334 char *newline = NULL; /* the line we create */
1335 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001336
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001337/* There are three steps. First, we decide where to wrap. Then, we
1338 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001339
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001340/* Step 1, finding where to wrap. We are going to add a new-line
1341 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001342 * location of this replacement.
1343 *
1344 * Where should we break the line? We need the last "legal wrap point"
1345 * such that the last word before it ended at or before fill. If there
1346 * is no such point, we settle for the first legal wrap point.
1347 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001348 * A "legal wrap point" is a white-space character that is not followed by
1349 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001350 *
1351 * If there is no legal wrap point or we found the last character of the
1352 * line, we should return without wrapping.
1353 *
1354 * Note that the initial indentation does not count as a legal wrap
1355 * point if we are going to auto-indent!
1356 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001357 * Note that the code below could be optimised, by not calling strnlenpt()
1358 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001359
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001360#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001361 if (ISSET(AUTOINDENT))
1362 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001363#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001364 wrap_line = inptr->data + i;
1365 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001366 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001367 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001368 word_back = i;
1369 /* if we have found a "legal wrap point" and the current word
1370 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001371 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001372 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001373 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001374 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001375 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001376 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001377 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001378 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001379
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001380/* Step 2, making the new wrap line. It will consist of indentation +
1381 * after_break + " " + wrap_line (although indentation and wrap_line are
1382 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001383
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001384 /* after_break is the text that will be moved to the next line. */
1385 after_break = inptr->data + wrap_loc + 1;
1386 after_break_len = len - wrap_loc - 1;
1387 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001388
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001389 /* new_line_len will later be increased by the lengths of indentation
1390 * and wrap_line. */
1391 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001392
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001393 /* We prepend the wrapped text to the next line, if the flag is set,
1394 * and there is a next line, and prepending would not make the line
1395 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001396 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001397 wrap_line = inptr->next->data;
1398 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001399
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001400 /* +1 for the space between after_break and wrap_line */
1401 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1402 wrapping = 1;
1403 new_line_len += (1 + wrap_line_len);
1404 }
1405 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001406
Chris Allegrettaff989832001-09-17 13:48:00 +00001407#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001408 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001409 /* Indentation comes from the next line if wrapping, else from
1410 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001411 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001412 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001413 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001414 /* The wrap_line text should not duplicate indentation.
1415 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001416 wrap_line += indent_len;
1417 else
1418 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001419 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001421
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001422 /* Now we allocate the new line and copy into it. */
1423 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1424 *newline = '\0';
1425
1426#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001427 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001428 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001429 newline[indent_len] = '\0';
1430 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001431#endif
1432 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001433 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001434 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001435 null_at(&inptr->data, wrap_loc + 1);
1436 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001437 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001438 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001439 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001440 * in a tab or a space, we don't add a space and decrement
1441 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001442 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001443 strcat(newline, " ");
1444 else
1445 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001446 strcat(newline, wrap_line);
1447 free(inptr->next->data);
1448 inptr->next->data = newline;
1449 } else {
1450 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001451
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001452 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001453 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001454#ifndef NANO_SMALL
1455 totsize += indent_len;
1456#endif
1457 totlines++;
1458 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001459 temp->prev = inptr;
1460 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001461 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001462 /* If temp->next is NULL, then temp is the last line of the
1463 * file, so we must set filebot. */
1464 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001465 temp->next->prev = temp;
1466 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001467 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001468 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001469
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001470/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1471 * other sundry things. */
1472
1473 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001474 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001475
1476 /* Each line knows its line number. We recalculate these if we
1477 * inserted a new line. */
1478 if (!wrapping)
1479 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001480
Chris Allegretta6df90f52002-07-19 01:08:59 +00001481 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001482 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001483 current = current->next;
1484 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001485#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001486 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001487#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001488 wrap_loc + 1;
1489 wrap_reset();
1490 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001491 }
1492
Chris Allegretta6df90f52002-07-19 01:08:59 +00001493#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001494 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001495 * If it was on the next line and we wrapped, we must move it
1496 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001497 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1498 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001499 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001500 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001501 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001502#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001503
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001504 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001505 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001506
1507 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001508}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001509#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001510
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001511#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001512/* A word is misspelled in the file. Let the user replace it. We
1513 * return False if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001514int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001515{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001516 char *save_search;
1517 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001518 filestruct *current_save = current;
1519 int current_x_save = current_x;
1520 filestruct *edittop_save = edittop;
1521 /* Save where we are. */
1522 int i = 0;
1523 /* The return value. */
1524 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001525#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001526 int case_sens_set = ISSET(CASE_SENSITIVE);
1527 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001528
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001529 SET(CASE_SENSITIVE);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001530 /* Make sure the marking highlight is off during Spell Check */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001531 UNSET(MARK_ISSET);
1532#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001533 /* Make sure Spell Check goes forward only */
1534 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001535
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001536 /* save the current search/replace strings */
1537 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001538 save_search = last_search;
1539 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001540
1541 /* set search/replace strings to mis-spelt word */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001542 last_search = mallocstrcpy(NULL, word);
1543 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001544
1545 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001546 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001547 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001548
1549 search_last_line = FALSE;
1550
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001551 /* We find the first whole-word occurrence of word. */
1552 while (findnextstr(TRUE, TRUE, fileage, -1, word))
1553 if (is_whole_word(current_x, current->data, word)) {
1554 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001555
Chris Allegretta6df90f52002-07-19 01:08:59 +00001556 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001557
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001558 /* allow replace word to be corrected */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001559 i = statusq(0, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001560#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001561 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001562#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001563 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001564
Chris Allegretta6df90f52002-07-19 01:08:59 +00001565 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001566
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001567 if (i != -1 && strcmp(word, answer)) {
1568 int j = 0;
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001569
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001570 search_last_line = FALSE;
1571 current_x--;
1572 do_replace_loop(word, current_save, &current_x_save, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001573 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001574
1575 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001576 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001577
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001578 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001579 free(last_search); last_search=save_search;
1580 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001581
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001582 /* restore where we were */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001583 current = current_save;
1584 current_x = current_x_save;
1585 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001586
Chris Allegretta23b74b22002-01-21 20:32:22 +00001587 /* restore Search/Replace direction */
1588 if (reverse_search_set)
1589 SET(REVERSE_SEARCH);
1590
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001591#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001592 if (!case_sens_set)
1593 UNSET(CASE_SENSITIVE);
1594
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001595 /* restore marking highlight */
1596 if (mark_set)
1597 SET(MARK_ISSET);
1598#endif
1599
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001600 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001601}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001602
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001603/* Integrated spell checking using 'spell' program. Return value: NULL
1604 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001605char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001606{
Chris Allegretta271e9722000-11-10 18:15:43 +00001607 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001608 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001609 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001610 pid_t pid_spell, pid_sort, pid_uniq;
1611 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001612
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001613 /* Create all three pipes up front */
Chris Allegretta271e9722000-11-10 18:15:43 +00001614
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001615 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1616 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001617
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001618 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001619 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001620
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001621 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001622
1623 /* Child continues, (i.e. future spell process) */
1624
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001625 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001626
Chris Allegretta271e9722000-11-10 18:15:43 +00001627 /* replace the standard in with the tempfile */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001628 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1629 goto close_pipes_and_exit;
1630
1631 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1632 goto close_pipes_and_exit;
1633
Chris Allegretta271e9722000-11-10 18:15:43 +00001634 close(tempfile_fd);
1635
1636 /* send spell's standard out to the pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001637 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1638 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001639
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001640 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001641
1642 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001643 execlp("spell", "spell", NULL);
1644
Chris Allegretta271e9722000-11-10 18:15:43 +00001645 /* Should not be reached, if spell is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001646 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001647 }
1648
1649 /* Parent continues here */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001650 close(spell_fd[1]);
1651
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001652 /* A new process to run sort in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001653 if ((pid_sort = fork()) == 0) {
1654
1655 /* Child continues, (i.e. future spell process) */
1656 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001657 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1658 goto close_pipes_and_exit;
1659
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001660 close(spell_fd[0]);
1661
1662 /* send sort's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001663 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1664 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001665
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001666 close(sort_fd[1]);
1667
1668 /* Start sort program. Use -f to remove mixed case without having
1669 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1670 execlp("sort", "sort", "-f", NULL);
1671
1672 /* Should not be reached, if sort is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001673 exit(1);
1674 }
1675
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001676 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001677 close(sort_fd[1]);
1678
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001679 /* A new process to run uniq in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001680 if ((pid_uniq = fork()) == 0) {
1681
1682 /* Child continues, (i.e. future uniq process) */
1683 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001684 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1685 goto close_pipes_and_exit;
1686
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001687 close(sort_fd[0]);
1688
1689 /* send uniq's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001690 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1691 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001692
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001693 close(uniq_fd[1]);
1694
1695 /* Start uniq program, we are using PATH */
1696 execlp("uniq", "uniq", NULL);
1697
1698 /* Should not be reached, if uniq is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001699 exit(1);
1700 }
1701
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001702 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001703 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001704
1705 /* Child process was not forked successfully */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001706 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1707 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001708 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001709 }
1710
Chris Allegretta271e9722000-11-10 18:15:43 +00001711 /* Get system pipe buffer size */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001712 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1713 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001714 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001715 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001716
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001717 /* Read-in the returned spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001718 read_buff_read = 0;
1719 read_buff_size = pipe_buff_size + 1;
1720 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001721
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001722 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001723 read_buff_read += bytesread;
1724 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001725 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001726 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001727
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001728 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001729
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001730 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001731 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001732
1733 /* Process the spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001734 read_buff_word = read_buff_ptr = read_buff;
1735
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001736 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001737
1738 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001739 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001740 if (read_buff_word != read_buff_ptr) {
1741 if (!do_int_spell_fix(read_buff_word)) {
1742 read_buff_word = read_buff_ptr;
1743 break;
1744 }
1745 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001746 read_buff_word = read_buff_ptr + 1;
1747 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001748 read_buff_ptr++;
1749 }
1750
1751 /* special case where last word doesn't end with \n or \r */
1752 if (read_buff_word != read_buff_ptr)
1753 do_int_spell_fix(read_buff_word);
1754
Chris Allegretta271e9722000-11-10 18:15:43 +00001755 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001756 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001757 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001758
Chris Allegretta271e9722000-11-10 18:15:43 +00001759 /* Process end of spell process */
1760
Chris Allegretta334a9402002-12-16 04:25:53 +00001761 waitpid(pid_spell, &spell_status, 0);
1762 waitpid(pid_sort, &sort_status, 0);
1763 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001764
Chris Allegretta334a9402002-12-16 04:25:53 +00001765 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1766 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001767
Chris Allegretta334a9402002-12-16 04:25:53 +00001768 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1769 return _("Error invoking \"sort -f\"");
1770
1771 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1772 return _("Error invoking \"uniq\"");
1773
1774 /* Otherwise... */
1775 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001776
1777close_pipes_and_exit:
1778
1779 /* Don't leak any handles */
1780 close(tempfile_fd);
1781 close(spell_fd[0]);
1782 close(spell_fd[1]);
1783 close(sort_fd[0]);
1784 close(sort_fd[1]);
1785 close(uniq_fd[0]);
1786 close(uniq_fd[1]);
1787 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001788}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001789
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001790/* External spell checking. Return value: NULL for normal termination,
1791 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001792char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001793{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001794 int alt_spell_status, lineno_cur = current->lineno;
1795 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001796 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001797 char *ptr;
1798 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001799 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001800#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001801 int mark_set = ISSET(MARK_ISSET);
1802 int mbb_lineno_cur = 0;
1803 /* We're going to close the current file, and open the output of
1804 the alternate spell command. The line that mark_beginbuf
1805 points to will be freed, so we save the line number and restore
1806 afterwards. */
1807
1808 if (mark_set) {
1809 mbb_lineno_cur = mark_beginbuf->lineno;
1810 UNSET(MARK_ISSET);
1811 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001812#endif
1813
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001814 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001815
Chris Allegrettae434b452001-01-27 19:25:00 +00001816 /* Set up an argument list to pass the execvp function */
1817 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001818 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001819
Chris Allegrettae434b452001-01-27 19:25:00 +00001820 spellargs[0] = strtok(alt_speller, " ");
1821 while ((ptr = strtok(NULL, " ")) != NULL) {
1822 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001823 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001824 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001825 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001826 spellargs[arglen - 1] = NULL;
1827 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001828 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001829
1830 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001831 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001832 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001833 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001834
1835 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001836 exit(1);
1837 }
1838
1839 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001840 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001841 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001842
1843 /* Wait for alternate speller to complete */
1844
1845 wait(&alt_spell_status);
Chris Allegretta334a9402002-12-16 04:25:53 +00001846 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1847 char *altspell_error = NULL;
1848 char *invoke_error = _("Could not invoke \"%s\"");
1849 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1850
1851 altspell_error = charalloc(msglen);
1852 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1853 return altspell_error;
1854 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001855
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001856 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001857 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001858 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001859 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001860
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001861#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001862 if (mark_set) {
1863 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1864 mark_beginbuf = current;
1865 mark_beginx = current_x;
1866 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001867 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001868 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001869#endif
1870
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001871 /* go back to the old position, mark the file as modified, and make
1872 sure that the titlebar is refreshed */
1873 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001874 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001875 clearok(topwin, FALSE);
1876 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001877
Chris Allegretta334a9402002-12-16 04:25:53 +00001878 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001879}
1880#endif
1881
1882int do_spell(void)
1883{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001884#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001885 nano_disabled_msg();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001886 return TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001887#else
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001888 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001889
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001890 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001891 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001892 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001893 return 0;
1894 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001895
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001896 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001897 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001898 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001899 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001900 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001901
Chris Allegrettae1f14522001-09-19 03:19:43 +00001902#ifdef ENABLE_MULTIBUFFER
1903 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001904 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00001905 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001906#endif
1907
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001908 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001909 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001910 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001911 spell_msg = do_int_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001912 remove(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001913 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001914
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001915 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001916 statusbar(_("Spell checking failed: %s"), spell_msg);
1917 return 0;
1918 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001919
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001920 statusbar(_("Finished checking spelling"));
1921 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001922#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001923}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001924
Chris Allegrettad865da12002-07-29 23:46:38 +00001925#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001926/* The "indentation" of a line is the white-space between the quote part
1927 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001928size_t indent_length(const char *line)
1929{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001930 size_t len = 0;
1931
1932 assert(line != NULL);
1933 while (*line == ' ' || *line == '\t') {
1934 line++;
1935 len++;
1936 }
1937 return len;
1938}
Chris Allegrettadffa2072002-07-24 01:02:26 +00001939#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001940
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001941#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00001942/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
1943 * it maintains 2 after a . ! or ?). Note the terminating \0
1944 * counts as a space.
1945 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001946 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001947 * returns 1, otherwise returns 0.
1948 *
1949 * If changes_allowed, justify_format() might make line->data
1950 * shorter, and change the actual pointer with null_at().
1951 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001952 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001953 * skip should be at most strlen(line->data). The skip+1st character must
1954 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001955int justify_format(int changes_allowed, filestruct *line, size_t skip)
1956{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001957 const char *punct = ".?!";
1958 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001959 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001960
Chris Allegretta6df90f52002-07-19 01:08:59 +00001961 /* These four asserts are assumptions about the input data. */
1962 assert(line != NULL);
1963 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001964 assert(skip < strlen(line->data));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001965 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001966
Chris Allegretta6df90f52002-07-19 01:08:59 +00001967 back = line->data + skip;
1968 front = back;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001969 for (front = back; ; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001970 int remove_space = 0;
1971 /* Do we want to remove this space? */
1972
Chris Allegretta6df90f52002-07-19 01:08:59 +00001973 if (*front == '\t') {
1974 if (!changes_allowed)
1975 return 1;
1976 *front = ' ';
1977 }
1978 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001979 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001980 const char *bob = front - 2;
1981
1982 remove_space = 1;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001983 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001984 if (strchr(punct, *bob) != NULL) {
1985 remove_space = 0;
1986 break;
1987 }
1988 if (strchr(brackets, *bob) == NULL)
1989 break;
1990 }
1991 }
1992
1993 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001994 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001995 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001996 if (!changes_allowed)
1997 return 1;
1998#ifndef NANO_SMALL
1999 if (mark_beginbuf == line && back - line->data < mark_beginx)
2000 mark_beginx--;
2001#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002002 if (*front == '\0')
2003 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002004 } else {
2005 *back = *front;
2006 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002007 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002008 if (*front == '\0')
2009 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002010 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002011
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002012 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00002013 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00002014
2015 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002016 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002017
2018 /* Now back is the new end of line->data. */
2019 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00002020 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002021 null_at(&line->data, back - line->data);
2022#ifndef NANO_SMALL
2023 if (mark_beginbuf == line && back - line->data < mark_beginx)
2024 mark_beginx = back - line->data;
2025#endif
2026 }
2027 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002028}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002029
2030/* The "quote part" of a line is the largest initial substring matching
2031 * the quote string. This function returns the length of the quote part
2032 * of the given line.
2033 *
2034 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2035 * quotestr. */
2036#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002037size_t quote_length(const char *line, const regex_t *qreg)
2038{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002039 regmatch_t matches;
2040 int rc = regexec(qreg, line, 1, &matches, 0);
2041
2042 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2043 return 0;
2044 /* matches.rm_so should be 0, since the quote string should start with
2045 * the caret ^. */
2046 return matches.rm_eo;
2047}
2048#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002049size_t quote_length(const char *line)
2050{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002051 size_t qdepth = 0;
2052 size_t qlen = strlen(quotestr);
2053
2054 /* Compute quote depth level */
2055 while (!strcmp(line + qdepth, quotestr))
2056 qdepth += qlen;
2057 return qdepth;
2058}
2059#endif /* !HAVE_REGEX_H */
2060
Chris Allegretta6df90f52002-07-19 01:08:59 +00002061/* a_line and b_line are lines of text. The quotation part of a_line is
2062 * the first a_quote characters. Check that the quotation part of
2063 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002064int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002065 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002066{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002067 /* Here is the assumption about a_quote: */
2068 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002069 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002070 !strncmp(a_line, b_line, a_quote);
2071}
2072
2073/* We assume a_line and b_line have no quote part. Then, we return whether
2074 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002075size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002076 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002077{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002078 assert(a_indent == indent_length(a_line));
2079 assert(b_indent == indent_length(b_line));
2080
2081 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2082}
2083
2084/* Put the next par_len lines, starting with first_line, in the cut
2085 * buffer. We assume there are enough lines after first_line. We leave
2086 * copies of the lines in place, too. We return the new copy of
2087 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002088filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002089 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002090{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002091 /* We put the original lines, not copies, into the cut buffer, just
2092 * out of a misguided sense of consistency, so if you un-cut, you
2093 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002094 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002095
2096 set_modified();
2097 cutbuffer = NULL;
2098 for(; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002099 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002100
Chris Allegretta908f7702003-01-15 11:18:58 +00002101 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002102 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002103 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002104 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002105 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002106 edittop = bob;
2107#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002108 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002109 mark_beginbuf = bob;
2110#endif
2111 justify_format(1, bob,
2112 quote_len + indent_length(bob->data + quote_len));
2113
Chris Allegretta908f7702003-01-15 11:18:58 +00002114 assert(alice != NULL && bob != NULL);
2115 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002116 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002117 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002118 }
2119 return first_line;
2120}
2121
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002122/* Is it possible to break line at or before goal? */
2123int breakable(const char *line, int goal)
2124{
2125 for(; *line != '\0' && goal >= 0; line++) {
2126 if (*line == ' ' || *line == '\t')
2127 return TRUE;
2128
2129 if (is_cntrl_char(*line) != 0)
2130 goal -= 2;
2131 else
2132 goal -= 1;
2133 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002134 /* If goal is not negative, the whole line (one word) was short
2135 * enough. */
2136 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002137}
2138
Chris Allegretta6df90f52002-07-19 01:08:59 +00002139/* We are trying to break a chunk off line. We find the last space such
2140 * that the display length to there is at most goal + 1. If there is
2141 * no such space, and force is not 0, then we find the first space.
2142 * Anyway, we then take the last space in that group of spaces. The
2143 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002144int break_line(const char *line, int goal, int force)
2145{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002146 /* Note that we use int instead of size_t, since goal is at most COLS,
2147 * the screen width, which will always be reasonably small. */
2148 int space_loc = -1;
2149 /* Current tentative return value. Index of the last space we
2150 * found with short enough display width. */
2151 int cur_loc = 0;
2152 /* Current index in line */
2153
2154 assert(line != NULL);
2155 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2156 if (*line == ' ')
2157 space_loc = cur_loc;
2158 assert(*line != '\t');
2159
Chris Allegrettacf287c82002-07-20 13:57:41 +00002160 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002161 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002162 else
2163 goal--;
2164 }
2165 if (goal >= 0)
2166 /* In fact, the whole line displays shorter than goal. */
2167 return cur_loc;
2168 if (space_loc == -1) {
2169 /* No space found short enough. */
2170 if (force)
2171 for(; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002172 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002173 return cur_loc;
2174 return -1;
2175 }
2176 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002177 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002178 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2179 *(line - cur_loc + space_loc + 1) == '\0')
2180 space_loc++;
2181 return space_loc;
2182}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002183
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002184/* This function performs operations on paragraphs: justify, go to
2185 * beginning, and go to end. */
2186int do_para_operation(int operation)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002187{
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002188/* operation == 0 means we're justifying the paragraph, operation == 1
2189 * means we're moving to the beginning line of the paragraph, and
2190 * operation == 2 means we're moving to the ending line of the
2191 * paragraph.
2192 *
2193 * To explain the justifying algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002194 * phrases about paragraphs and quotation:
2195 * A line of text consists of a "quote part", followed by an
2196 * "indentation part", followed by text. The functions quote_length()
2197 * and indent_length() calculate these parts.
2198 *
2199 * A line is "part of a paragraph" if it has a part not in the quote
2200 * part or the indentation.
2201 *
2202 * A line is "the beginning of a paragraph" if it is part of a paragraph
2203 * and
2204 * 1) it is the top line of the file, or
2205 * 2) the line above it is not part of a paragraph, or
2206 * 3) the line above it does not have precisely the same quote
2207 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002208 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002209 * indentation of the previous line, or
2210 * 5) this line has no quote part and some indentation, and
2211 * AUTOINDENT is not set.
2212 * The reason for number 5) is that if AUTOINDENT is not set, then an
2213 * indented line is expected to start a paragraph, like in books. Thus,
2214 * nano can justify an indented paragraph only if AUTOINDENT is turned
2215 * on.
2216 *
2217 * A contiguous set of lines is a "paragraph" if each line is part of
2218 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002219 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002220
Chris Allegretta6df90f52002-07-19 01:08:59 +00002221 size_t quote_len;
2222 /* Length of the initial quotation of the paragraph we justify. */
2223 size_t par_len;
2224 /* Number of lines in that paragraph. */
2225 filestruct *first_mod_line = NULL;
2226 /* Will be the first line of the resulting justified paragraph
2227 * that differs from the original. For restoring after uncut. */
2228 filestruct *last_par_line = current;
2229 /* Will be the last line of the result, also for uncut. */
2230 filestruct *cutbuffer_save = cutbuffer;
2231 /* When the paragraph gets modified, all lines from the changed
2232 * one down are stored in the cut buffer. We back up the original
2233 * to restore it later. */
2234
2235 /* We save these global variables to be restored if the user
2236 * unjustifies. Note we don't need to save totlines. */
2237 int current_x_save = current_x;
2238 int current_y_save = current_y;
2239 filestruct *current_save = current;
2240 int flags_save = flags;
2241 long totsize_save = totsize;
2242 filestruct *edittop_save = edittop;
2243 filestruct *editbot_save = editbot;
2244#ifndef NANO_SMALL
2245 filestruct *mark_beginbuf_save = mark_beginbuf;
2246 int mark_beginx_save = mark_beginx;
2247#endif
2248
2249 size_t indent_len; /* generic indentation length */
2250 filestruct *line; /* generic line of text */
2251 size_t i; /* generic loop variable */
2252
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002253 static int no_restart = 0;
2254 /* whether we're blocking restarting when searching for the
2255 * beginning line of the paragraph */
2256
Chris Allegretta6df90f52002-07-19 01:08:59 +00002257#ifdef HAVE_REGEX_H
2258 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002259 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002260 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2261
2262 if (rc) {
2263 size_t size = regerror(rc, &qreg, NULL, 0);
2264 char *strerror = charalloc(size);
2265
2266 regerror(rc, &qreg, strerror, size);
2267 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2268 free(strerror);
2269 return -1;
2270 }
2271#endif
2272
2273 /* Here is an assumption that is always true anyway. */
2274 assert(current != NULL);
2275
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002276 current_x = 0;
2277
2278 restart_bps:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002279/* Here we find the first line of the paragraph to justify. If the
2280 * current line is in a paragraph, then we move back to the first line.
2281 * Otherwise we move down to the first line that is in a paragraph. */
2282 quote_len = quote_length(IFREG(current->data, &qreg));
2283 indent_len = indent_length(current->data + quote_len);
2284
2285 if (current->data[quote_len + indent_len] != '\0') {
2286 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002287 * the first line of this paragraph. First we check items 1) and
2288 * 3) above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002289 while (current->prev != NULL && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002290 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002291 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002292 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002293 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002294
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002295 /* Is this line the beginning of a paragraph, according to
2296 items 2), 5), or 4) above? If so, stop. */
2297 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2298 (quote_len == 0 && indent_len > 0
2299#ifndef NANO_SMALL
2300 && !ISSET(AUTOINDENT)
2301#endif
2302 ) ||
2303 !indents_match(current->prev->data + quote_len,
2304 temp_id_len, current->data + quote_len, indent_len))
2305 break;
2306 indent_len = temp_id_len;
2307 current = current->prev;
2308 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002309 }
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002310 } else if (operation == 1) {
2311 /* This line is not part of a paragraph. Move up until we get
2312 * to a non "blank" line, and then move down once. */
2313 do {
2314 /* There is no previous paragraph, so nothing to move to. */
2315 if (current->prev == NULL) {
2316 placewewant = 0;
2317 if (current_y < 0)
2318 edit_update(current, CENTER);
2319 else
2320 edit_refresh();
2321 return 0;
2322 }
2323 current = current->prev;
2324 current_y--;
2325 quote_len = quote_length(IFREG(current->data, &qreg));
2326 indent_len = indent_length(current->data + quote_len);
2327 } while (current->data[quote_len + indent_len] == '\0');
2328 current = current->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002329 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002330 /* This line is not part of a paragraph. Move down until we get
2331 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002332 do {
2333 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002334 if (current->next == NULL) {
2335 placewewant = 0;
Chris Allegretta428f6202003-02-12 03:21:45 +00002336 edit_refresh();
2337#ifdef HAVE_REGEX_H
2338 regfree(&qreg);
2339#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002340 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002341 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002342 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002343 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002344 quote_len = quote_length(IFREG(current->data, &qreg));
2345 indent_len = indent_length(current->data + quote_len);
2346 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002347 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002348/* Now current is the first line of the paragraph, and quote_len
2349 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002350
Chris Allegretta6df90f52002-07-19 01:08:59 +00002351/* Next step, compute par_len, the number of lines in this paragraph. */
2352 line = current;
2353 par_len = 1;
2354 indent_len = indent_length(line->data + quote_len);
2355
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002356 while (line->next != NULL && quotes_match(current->data, quote_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002357 IFREG(line->next->data, &qreg))) {
2358 size_t temp_id_len = indent_length(line->next->data + quote_len);
2359
2360 if (!indents_match(line->data + quote_len, indent_len,
2361 line->next->data + quote_len, temp_id_len) ||
2362 line->next->data[quote_len + temp_id_len] == '\0' ||
2363 (quote_len == 0 && temp_id_len > 0
2364#ifndef NANO_SMALL
2365 && !ISSET(AUTOINDENT)
2366#endif
2367 ))
2368 break;
2369 indent_len = temp_id_len;
2370 line = line->next;
2371 par_len++;
2372 }
2373#ifdef HAVE_REGEX_H
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002374 /* We no longer need to check quotation, unless we're searching for
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002375 * the beginning of the paragraph. */
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002376 if (operation != 1)
2377 regfree(&qreg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002378#endif
2379/* Now par_len is the number of lines in this paragraph. Should never
2380 * call quotes_match() or quote_length() again. */
2381
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002382 /* If we're searching for the beginning of the paragraph, skip the
2383 * justification. If we're searching for the end of the paragraph,
2384 * move down the number of lines in the paragraph and skip the
2385 * justification. */
2386 if (operation == 1)
2387 goto skip_justify;
2388 else if (operation == 2) {
2389 while (par_len > 0) {
2390 current = current->next;
2391 current_y++;
2392 par_len--;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002393 }
2394 goto skip_justify;
2395 }
2396
Chris Allegretta6df90f52002-07-19 01:08:59 +00002397/* Next step, we loop through the lines of this paragraph, justifying
2398 * each one individually. */
Chris Allegretta8151ba52003-04-19 19:34:05 +00002399 SET(JUSTIFY_MODE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002400 for(; par_len > 0; current_y++, par_len--) {
2401 size_t line_len;
2402 size_t display_len;
2403 /* The width of current in screen columns. */
2404 int break_pos;
2405 /* Where we will break the line. */
2406
2407 indent_len = indent_length(current->data + quote_len) +
2408 quote_len;
2409 /* justify_format() removes excess spaces from the line, and
2410 * changes tabs to spaces. The first argument, 0, means don't
2411 * change the line, just say whether there are changes to be
2412 * made. If there are, we do backup_lines(), which copies the
2413 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002414 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002415 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002416 first_mod_line = backup_lines(current, par_len, quote_len);
2417
2418 line_len = strlen(current->data);
2419 display_len = strlenpt(current->data);
2420
2421 if (display_len > fill) {
2422 /* The line is too long. Try to wrap it to the next. */
2423 break_pos = break_line(current->data + indent_len,
2424 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002425 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002426 if (break_pos == -1 || break_pos + indent_len == line_len)
2427 /* We can't break the line, or don't need to, so just go
2428 * on to the next. */
2429 goto continue_loc;
2430 break_pos += indent_len;
2431 assert(break_pos < line_len);
2432 /* If we haven't backed up the paragraph, do it now. */
2433 if (first_mod_line == NULL)
2434 first_mod_line = backup_lines(current, par_len, quote_len);
2435 if (par_len == 1) {
2436 /* There is no next line in this paragraph. We make a new
2437 * line and copy text after break_pos into it. */
2438 splice_node(current, make_new_node(current),
2439 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002440 /* In a non-quoted paragraph, we copy the indent only if
2441 AUTOINDENT is turned on. */
2442 if (quote_len == 0)
2443#ifndef NANO_SMALL
2444 if (!ISSET(AUTOINDENT))
2445#endif
2446 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002447 current->next->data = charalloc(indent_len + line_len -
2448 break_pos);
2449 strncpy(current->next->data, current->data,
2450 indent_len);
2451 strcpy(current->next->data + indent_len,
2452 current->data + break_pos + 1);
2453 assert(strlen(current->next->data) ==
2454 indent_len + line_len - break_pos - 1);
2455 totlines++;
2456 totsize += indent_len;
2457 par_len++;
2458 } else {
2459 size_t next_line_len = strlen(current->next->data);
2460
2461 indent_len = quote_len +
2462 indent_length(current->next->data + quote_len);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002463 current->next->data = charealloc(current->next->data,
2464 next_line_len + line_len - break_pos + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002465
2466 memmove(current->next->data + indent_len + line_len - break_pos,
2467 current->next->data + indent_len,
2468 next_line_len - indent_len + 1);
2469 strcpy(current->next->data + indent_len,
2470 current->data + break_pos + 1);
2471 current->next->data[indent_len + line_len - break_pos - 1]
2472 = ' ';
2473#ifndef NANO_SMALL
2474 if (mark_beginbuf == current->next) {
2475 if (mark_beginx < indent_len)
2476 mark_beginx = indent_len;
2477 mark_beginx += line_len - break_pos;
2478 }
2479#endif
2480 }
2481#ifndef NANO_SMALL
2482 if (mark_beginbuf == current && mark_beginx > break_pos) {
2483 mark_beginbuf = current->next;
2484 mark_beginx -= break_pos + 1 - indent_len;
2485 }
2486#endif
2487 null_at(&current->data, break_pos);
2488 current = current->next;
2489 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002490 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002491
2492 indent_len = quote_len +
2493 indent_length(current->next->data + quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002494 /* If we can't pull a word from the next line up to this one,
2495 * just go on. */
2496 if (!breakable(current->next->data + indent_len,
2497 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002498 goto continue_loc;
2499
2500 /* If we haven't backed up the paragraph, do it now. */
2501 if (first_mod_line == NULL)
2502 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002503
2504 break_pos = break_line(current->next->data + indent_len,
2505 fill - display_len - 1, FALSE);
2506 assert(break_pos != -1);
2507
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002508 current->data = charealloc(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002509 line_len + break_pos + 2);
2510 current->data[line_len] = ' ';
2511 strncpy(current->data + line_len + 1,
2512 current->next->data + indent_len, break_pos);
2513 current->data[line_len + break_pos + 1] = '\0';
2514#ifndef NANO_SMALL
2515 if (mark_beginbuf == current->next) {
2516 if (mark_beginx < indent_len + break_pos) {
2517 mark_beginbuf = current;
2518 if (mark_beginx <= indent_len)
2519 mark_beginx = line_len + 1;
2520 else
2521 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2522 } else
2523 mark_beginx -= break_pos + 1;
2524 }
2525#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002526 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002527 if (indent_len + break_pos == next_line_len) {
2528 line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002529
2530 /* Don't destroy edittop! */
2531 if (line == edittop)
2532 edittop = current;
2533
Chris Allegretta6df90f52002-07-19 01:08:59 +00002534 unlink_node(line);
2535 delete_node(line);
2536 totlines--;
2537 totsize -= indent_len;
2538 current_y--;
2539 } else {
2540 memmove(current->next->data + indent_len,
2541 current->next->data + indent_len + break_pos + 1,
2542 next_line_len - break_pos - indent_len);
2543 null_at(&current->next->data,
2544 next_line_len - break_pos);
2545 current = current->next;
2546 }
2547 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002548 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002549 current = current->next;
2550 }
Chris Allegretta8151ba52003-04-19 19:34:05 +00002551 UNSET(JUSTIFY_MODE);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002552
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002553/* We are now done justifying the paragraph. There are cleanup things
2554 * to do, and we check for unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002555
2556 /* totlines, totsize, and current_y have been maintained above. We
2557 * now set last_par_line to the new end of the paragraph, update
2558 * fileage, set current_x. Also, edit_refresh() needs the line
2559 * numbers to be right, so we renumber(). */
2560 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002561 if (first_mod_line != NULL) {
2562 if (first_mod_line->prev == NULL)
2563 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002564 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002565 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002566
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002567 skip_justify:
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002568 if (operation == 1) {
2569 /* We're on the same line we started on. Search for the first
2570 * non-"blank" line before the line we're on (if there is one),
2571 * continually restart that search from the current position
2572 * until we find a line that's part of a paragraph, and then
2573 * search once more from there, so that we end up on the first
2574 * line of that paragraph. In the process, skip over lines
2575 * consisting only of spacing characters, as searching for the
2576 * end of the paragraph does. Then update the screen. */
2577 if (current != fileage && current == current_save && !no_restart) {
2578 while (current->prev != NULL) {
2579 int j, j_space = 0;
2580 current = current->prev;
2581 current_y--;
2582 for (j = 0; j < strlen(current->data); j++) {
2583 if (isspace(current->data[j]))
2584 j_space++;
2585 else {
2586 j = -1;
2587 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002588 }
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002589 }
2590 if (j != j_space && strlen(current->data) >=
2591 (quote_len + indent_len) &&
2592 current->data[quote_len + indent_len] != '\0') {
2593 no_restart = 1;
2594 break;
2595 }
2596 }
2597 goto restart_bps;
2598 } else
2599 no_restart = 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002600#ifdef HAVE_REGEX_H
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002601 /* We no longer need to check quotation, if we were
2602 * searching for the beginning of the paragraph. */
2603 regfree(&qreg);
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002604#endif
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002605 if (current_y < 0)
2606 edit_update(current, CENTER);
2607 else
2608 edit_refresh();
2609 return 0;
2610 } else if (operation == 2) {
2611 /* We've already moved to the end of the paragraph. Update the
2612 * screen. */
2613 if (current_y > editwinrows - 1)
2614 edit_update(current, CENTER);
2615 else
2616 edit_refresh();
2617 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002618 }
2619
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002620 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002621 edit_update(current, CENTER);
2622 else
2623 edit_refresh();
2624
Chris Allegretta9149e612000-11-27 00:23:41 +00002625 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002626 /* Change the shortcut list to display the unjustify code */
2627 shortcut_init(1);
2628 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002629 reset_cursor();
2630
Chris Allegretta6df90f52002-07-19 01:08:59 +00002631 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002632 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002633
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002634#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002635 /* If it was a mouse click, parse it with do_mouse() and it might
2636 * become the unjustify key. Else give it back to the input stream. */
2637 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002638 do_mouse();
2639 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002640 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002641#endif
Chris Allegretta5f071802001-05-06 02:34:31 +00002642
Chris Allegretta6df90f52002-07-19 01:08:59 +00002643 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2644 ungetch(i);
2645 /* Did we back up anything at all? */
2646 if (cutbuffer != cutbuffer_save)
2647 free_filestruct(cutbuffer);
2648 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002649 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002650 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002651 current = current_save;
2652 current_x = current_x_save;
2653 current_y = current_y_save;
2654 edittop = edittop_save;
2655 editbot = editbot_save;
2656 if (first_mod_line != NULL) {
2657 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002658
Chris Allegretta6df90f52002-07-19 01:08:59 +00002659 /* Splice the cutbuffer back into the file. */
2660 cutbottom->next = last_par_line->next;
2661 cutbottom->next->prev = cutbottom;
2662 /* The line numbers after the end of the paragraph have
2663 * been changed, so we change them back. */
2664 renumber(cutbottom->next);
2665 if (first_mod_line->prev != NULL) {
2666 cutbuffer->prev = first_mod_line->prev;
2667 cutbuffer->prev->next = cutbuffer;
2668 } else
2669 fileage = cutbuffer;
2670 cutbuffer = NULL;
2671
2672 last_par_line->next = NULL;
2673 free_filestruct(first_mod_line);
2674
2675 /* Restore global variables from before justify */
2676 totsize = totsize_save;
2677 totlines = filebot->lineno;
2678#ifndef NANO_SMALL
2679 mark_beginbuf = mark_beginbuf_save;
2680 mark_beginx = mark_beginx_save;
2681#endif
2682 flags = flags_save;
2683 if (!ISSET(MODIFIED)) {
2684 titlebar(NULL);
2685 wrefresh(topwin);
2686 }
2687 }
2688 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002689 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002690 cutbuffer = cutbuffer_save;
2691 blank_statusbar_refresh();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002692 /* display shortcut list with UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002693 shortcut_init(0);
2694 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002695
Chris Allegretta6df90f52002-07-19 01:08:59 +00002696 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002697}
2698#endif /* !DISABLE_JUSTIFY */
2699
2700int do_justify(void)
2701{
2702#ifdef DISABLE_JUSTIFY
2703 nano_disabled_msg();
2704 return 1;
2705#else
2706 return do_para_operation(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002707#endif
2708}
2709
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002710#ifndef DISABLE_JUSTIFY
2711int do_para_begin(void)
2712{
2713 return do_para_operation(1);
2714}
2715
2716int do_para_end(void)
2717{
2718 return do_para_operation(2);
2719}
2720#endif
2721
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002722int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002723{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002724 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002725
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002726 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002727
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002728#ifdef ENABLE_MULTIBUFFER
2729 if (!close_open_file()) {
2730 display_main_list();
2731 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002732 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002733 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002734#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002735 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002736 }
2737
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002738 if (ISSET(TEMP_OPT)) {
2739 i = 1;
2740 } else {
2741 i = do_yesno(0, 0,
2742 _
2743 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2744 }
2745
2746#ifdef DEBUG
2747 dump_buffer(fileage);
2748#endif
2749
2750 if (i == 1) {
2751 if (do_writeout(filename, 1, 0) > 0) {
2752
2753#ifdef ENABLE_MULTIBUFFER
2754 if (!close_open_file()) {
2755 display_main_list();
2756 return 1;
2757 }
2758 else
2759#endif
2760 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002761 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002762 } else if (i == 0) {
2763
2764#ifdef ENABLE_MULTIBUFFER
2765 if (!close_open_file()) {
2766 display_main_list();
2767 return 1;
2768 }
2769 else
2770#endif
2771 finish(0);
2772 } else
2773 statusbar(_("Cancelled"));
2774
2775 display_main_list();
2776 return 1;
2777}
2778
2779void signal_init(void)
2780{
2781#ifdef _POSIX_VDISABLE
2782 struct termios term;
2783#endif
2784
2785 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2786 memset(&act, 0, sizeof(struct sigaction));
2787 act.sa_handler = SIG_IGN;
2788 sigaction(SIGINT, &act, NULL);
2789
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002790 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2791 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002792 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002793 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002794
2795#ifndef NANO_SMALL
2796 act.sa_handler = handle_sigwinch;
2797 sigaction(SIGWINCH, &act, NULL);
2798#endif
2799
2800#ifdef _POSIX_VDISABLE
2801 tcgetattr(0, &term);
2802
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002803 if (!ISSET(PRESERVE)) {
2804 /* Ignore ^S and ^Q, much to Chris' chagrin */
2805 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2806 term.c_cc[VSTART] = _POSIX_VDISABLE;
2807 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002808#ifdef VDSUSP
2809 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2810#endif /* VDSUSP */
2811
2812#endif /* _POSIX_VDISABLE */
2813
2814 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002815 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002816#ifdef _POSIX_VDISABLE
2817 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2818#else
2819 act.sa_handler = SIG_IGN;
2820 sigaction(SIGTSTP, &act, NULL);
2821#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002822 } else {
2823 /* If we don't do this, it seems other stuff interrupts the
2824 suspend handler! Try using nano with mutt without this
2825 line. */
2826 sigfillset(&act.sa_mask);
2827
2828 act.sa_handler = do_suspend;
2829 sigaction(SIGTSTP, &act, NULL);
2830
2831 act.sa_handler = do_cont;
2832 sigaction(SIGCONT, &act, NULL);
2833 }
2834
2835#ifdef _POSIX_VDISABLE
2836 tcsetattr(0, TCSANOW, &term);
2837#endif
2838}
2839
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002840/* Handler for SIGHUP and SIGTERM */
2841RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002842{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002843 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002844}
2845
2846/* What do we do when we catch the suspend signal */
2847RETSIGTYPE do_suspend(int signal)
2848{
2849 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002850 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002851 fflush(stdout);
2852
2853 /* Restore the terminal settings for the disabled keys */
2854 tcsetattr(0, TCSANOW, &oldterm);
2855
2856 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002857 then we could be (and were) interrupted in the middle of the call.
2858 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002859 kill(0, SIGSTOP);
2860}
2861
2862/* Restore the suspend handler when we come back into the prog */
2863RETSIGTYPE do_cont(int signal)
2864{
2865 /* Now we just update the screen instead of having to reenable the
2866 SIGTSTP handler. */
2867
2868 doupdate();
2869 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2870 start suspending again. */
2871 signal_init();
2872
2873#ifndef NANO_SMALL
2874 /* Perhaps the user resized the window while we slept. */
2875 handle_sigwinch(0);
2876#endif
2877}
2878
2879#ifndef NANO_SMALL
2880void handle_sigwinch(int s)
2881{
2882 const char *tty = ttyname(0);
2883 int fd;
2884 int result = 0;
2885 struct winsize win;
2886
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002887 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002888 return;
2889 fd = open(tty, O_RDWR);
2890 if (fd == -1)
2891 return;
2892 result = ioctl(fd, TIOCGWINSZ, &win);
2893 close(fd);
2894 if (result == -1)
2895 return;
2896
2897 /* Could check whether the COLS or LINES changed, and return
2898 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2899 * variables, and in some cases ncurses has already updated them.
2900 * But not in all cases, argh. */
2901 COLS = win.ws_col;
2902 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002903 editwinrows = LINES - 5 + no_help();
2904 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002905 die_too_small();
2906
2907#ifndef DISABLE_WRAPJUSTIFY
2908 fill = wrap_at;
2909 if (fill <= 0)
2910 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002911 if (fill < 0)
2912 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002913#endif
2914
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002915 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002916 memset(hblank, ' ', COLS);
2917 hblank[COLS] = '\0';
2918
2919#ifdef HAVE_RESIZETERM
2920 resizeterm(LINES, COLS);
2921#ifdef HAVE_WRESIZE
2922 if (wresize(topwin, 2, COLS) == ERR)
2923 die(_("Cannot resize top win"));
2924 if (mvwin(topwin, 0, 0) == ERR)
2925 die(_("Cannot move top win"));
2926 if (wresize(edit, editwinrows, COLS) == ERR)
2927 die(_("Cannot resize edit win"));
2928 if (mvwin(edit, 2, 0) == ERR)
2929 die(_("Cannot move edit win"));
2930 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2931 die(_("Cannot resize bottom win"));
2932 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2933 die(_("Cannot move bottom win"));
2934#endif /* HAVE_WRESIZE */
2935#endif /* HAVE_RESIZETERM */
2936
2937 fix_editbot();
2938
2939 if (current_y > editwinrows - 1)
2940 edit_update(editbot, CENTER);
2941 erase();
2942
2943 /* Do these b/c width may have changed... */
2944 refresh();
2945 titlebar(NULL);
2946 edit_refresh();
2947 display_main_list();
2948 blank_statusbar();
2949 total_refresh();
2950
2951 /* Turn cursor back on for sure */
2952 curs_set(1);
2953
2954 /* Jump back to main loop */
2955 siglongjmp(jmpbuf, 1);
2956}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002957#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002958
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002959/* If the NumLock key has made the keypad go awry, print an error
2960 message; hopefully we can address it later. */
2961void print_numlock_warning(void)
2962{
2963 static int didmsg = 0;
2964 if (!didmsg) {
2965 statusbar(_
2966 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2967 didmsg = 1;
2968 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002969}
2970
Chris Allegrettadab017e2002-04-23 10:56:06 +00002971#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002972void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002973{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002974 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002975
Chris Allegretta658399a2001-06-14 02:54:22 +00002976 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002977 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002978
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002979 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002980 case TOGGLE_SUSPEND_KEY:
2981 signal_init();
2982 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002983#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00002984 case TOGGLE_MOUSE_KEY:
2985 mouse_init();
2986 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002987#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002988 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002989 wclear(bottomwin);
2990 wrefresh(bottomwin);
2991 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002992 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002993 edit_refresh();
2994 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002995 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002996 case TOGGLE_DOS_KEY:
2997 UNSET(MAC_FILE);
2998 break;
2999 case TOGGLE_MAC_KEY:
3000 UNSET(DOS_FILE);
3001 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003002#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003003 case TOGGLE_SYNTAX_KEY:
3004 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003005 break;
3006#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003007 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003008
Chris Allegretta6df90f52002-07-19 01:08:59 +00003009 /* We are assuming here that shortcut_init() above didn't free and
3010 * reallocate the toggles. */
3011 enabled = ISSET(which->flag);
3012 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3013 enabled = !enabled;
3014 statusbar("%s %s", which->desc,
3015 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003016}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003017#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003018
Chris Allegretta1748cd12001-01-13 17:22:54 +00003019/* This function returns the correct keystroke, given the A,B,C or D
3020 input key. This is a common sequence of many terms which send
3021 Esc-O-[A-D] or Esc-[-[A-D]. */
Chris Allegretta908f7702003-01-15 11:18:58 +00003022int abcd(int input)
Chris Allegretta1748cd12001-01-13 17:22:54 +00003023{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003024 switch (input) {
3025 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003026 case 'a':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003027 return KEY_UP;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003028 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003029 case 'b':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003030 return KEY_DOWN;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003031 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003032 case 'c':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003033 return KEY_RIGHT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003034 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003035 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003036 return KEY_LEFT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003037 default:
3038 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00003039 }
3040}
3041
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003042int main(int argc, char *argv[])
3043{
3044 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003045 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003046 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003047 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003048 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003049 int keyhandled = 0; /* Have we handled the keystroke yet? */
3050 int kbinput = -1; /* Input from keyboard */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003051 int meta;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003052
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003053#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003054 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003055#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003056#ifdef _POSIX_VDISABLE
3057 struct termios term;
3058#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003059#ifdef HAVE_GETOPT_LONG
3060 int option_index = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003061 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062 {"help", 0, 0, 'h'},
3063#ifdef ENABLE_MULTIBUFFER
3064 {"multibuffer", 0, 0, 'F'},
3065#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003066#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003067#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003068 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003069#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003070 {"ignorercfiles", 0, 0, 'I'},
3071#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003072#ifndef DISABLE_JUSTIFY
3073 {"quotestr", 1, 0, 'Q'},
3074#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003075#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003076 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003077#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003078 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003079 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003080#ifdef ENABLE_COLOR
3081 {"syntax", 1, 0, 'Y'},
3082#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003083 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003084 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003085 {"nofollow", 0, 0, 'l'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003086#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003087 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003088#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003089#ifndef DISABLE_OPERATINGDIR
3090 {"operatingdir", 1, 0, 'o'},
3091#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003092 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003093#ifndef DISABLE_WRAPJUSTIFY
3094 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003095#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003096#ifndef DISABLE_SPELLER
3097 {"speller", 1, 0, 's'},
3098#endif
3099 {"tempfile", 0, 0, 't'},
3100 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003101#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003102 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003103#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003104 {"nohelp", 0, 0, 'x'},
3105 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003106#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003107 {"backup", 0, 0, 'B'},
3108 {"dos", 0, 0, 'D'},
3109 {"mac", 0, 0, 'M'},
3110 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003111 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003112 {"autoindent", 0, 0, 'i'},
3113 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003114#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003115 {0, 0, 0, 0}
3116 };
3117#endif
3118
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003119#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003120 setlocale(LC_ALL, "");
3121 bindtextdomain(PACKAGE, LOCALEDIR);
3122 textdomain(PACKAGE);
3123#endif
3124
Chris Allegretta7662c862003-01-13 01:35:15 +00003125#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003126 /* if we don't have rcfile support, we're root, and
3127 --disable-wrapping-as-root is used, turn wrapping off */
3128 if (geteuid() == 0)
3129 SET(NO_WRAP);
3130#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003131
3132#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003133 while ((optchr = getopt_long(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
Chris Allegretta7662c862003-01-13 01:35:15 +00003134 long_options, &option_index)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003135#else
3136 while ((optchr =
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003137 getopt(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003138#endif
3139
3140 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003141
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003142 case 'a':
3143 case 'b':
3144 case 'e':
3145 case 'f':
3146 case 'g':
3147 case 'j':
3148 /* Pico compatibility flags */
3149 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003150#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003151 case 'B':
3152 SET(BACKUP_FILE);
3153 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003154 case 'D':
3155 SET(DOS_FILE);
3156 break;
3157#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003158#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003159 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003160 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003161 break;
3162#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003163#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003164#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003165 case 'H':
3166 SET(HISTORYLOG);
3167 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003168#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003169 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003170 SET(NO_RCFILE);
3171 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003172#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003173#ifndef NANO_SMALL
3174 case 'M':
3175 SET(MAC_FILE);
3176 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003177 case 'N':
3178 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003179 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003180#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003181#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003182 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003183 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003184 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003185#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003186#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003187 case 'R':
3188 SET(USE_REGEXP);
3189 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003190#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003191#ifndef NANO_SMALL
3192 case 'S':
3193 SET(SMOOTHSCROLL);
3194 break;
3195#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003196 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003197 {
3198 int i;
3199 char *first_error;
3200
Chris Allegretta7662c862003-01-13 01:35:15 +00003201 /* Using strtol() instead of atoi() lets us accept 0
3202 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003203 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003204 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003205 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003206 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003207 tabsize = i;
3208 if (tabsize <= 0) {
3209 fprintf(stderr, _("Tab size is too small for nano...\n"));
3210 exit(1);
3211 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003212 }
3213 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003214 case 'V':
3215 version();
3216 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003217#ifdef ENABLE_COLOR
3218 case 'Y':
3219 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3220 break;
3221#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003222 case 'c':
3223 SET(CONSTUPDATE);
3224 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003225 case 'd':
3226 SET(REBIND_DELETE);
3227 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003228#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003229 case 'i':
3230 SET(AUTOINDENT);
3231 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003232 case 'k':
3233 SET(CUT_TO_END);
3234 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003235#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003236 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003237 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003238 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003239#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003240 case 'm':
3241 SET(USE_MOUSE);
3242 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003243#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003244#ifndef DISABLE_OPERATINGDIR
3245 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003246 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003247 break;
3248#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003249 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003250 SET(PRESERVE);
3251#ifdef HAVE_GETOPT_LONG
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003252#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003253 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003254#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003255 case 'r':
3256 {
3257 int i;
3258 char *first_error;
3259
Chris Allegretta7662c862003-01-13 01:35:15 +00003260 /* Using strtol() instead of atoi() lets us accept 0
3261 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003262 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003263 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003264 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003265 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003266 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003267 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003268 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003269 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003270#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003271#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003272 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003273 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003274 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003275#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003276 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003277 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003278 break;
3279 case 'v':
3280 SET(VIEW_MODE);
3281 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003282#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003283 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003284 SET(NO_WRAP);
3285 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003286#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003287 case 'x':
3288 SET(NO_HELP);
3289 break;
3290 case 'z':
3291 SET(SUSPEND);
3292 break;
3293 default:
3294 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003295 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003296 }
3297
Chris Allegretta7662c862003-01-13 01:35:15 +00003298/* We've read through the command line options. Now back up the flags
3299 and values that are set, and read the rcfile(s). If the values
3300 haven't changed afterward, restore the backed-up values. */
3301#ifdef ENABLE_NANORC
3302 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003303#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003304 char *operating_dir_cpy = operating_dir;
3305#endif
3306#ifndef DISABLE_WRAPPING
3307 int wrap_at_cpy = wrap_at;
3308#endif
3309#ifndef DISABLE_JUSTIFY
3310 char *quotestr_cpy = quotestr;
3311#endif
3312#ifndef DISABLE_SPELLER
3313 char *alt_speller_cpy = alt_speller;
3314#endif
3315 int tabsize_cpy = tabsize;
3316 long flags_cpy = flags;
3317
Chris Allegretta5ec68622003-02-05 02:39:34 +00003318#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003319 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003320#endif
3321#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003322 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003323#endif
3324#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003325 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003326#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003327
3328 do_rcfile();
3329
3330#ifndef DISABLE_OPERATINGDIR
3331 if (operating_dir_cpy != NULL) {
3332 free(operating_dir);
3333 operating_dir = operating_dir_cpy;
3334 }
3335#endif
3336#ifndef DISABLE_WRAPPING
3337 if (fill_flag_used)
3338 wrap_at = wrap_at_cpy;
3339#endif
3340#ifndef DISABLE_JUSTIFY
3341 if (quotestr_cpy != NULL) {
3342 free(quotestr);
3343 quotestr = quotestr_cpy;
3344 }
3345#endif
3346#ifndef DISABLE_SPELLER
3347 if (alt_speller_cpy != NULL) {
3348 free(alt_speller);
3349 alt_speller = alt_speller_cpy;
3350 }
3351#endif
3352 if (tabsize_cpy > 0)
3353 tabsize = tabsize_cpy;
3354 flags |= flags_cpy;
3355 }
3356#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3357 else if (geteuid() == 0)
3358 SET(NO_WRAP);
3359#endif
3360#endif /* ENABLE_NANORC */
3361
Chris Allegrettad8451932003-03-11 03:50:40 +00003362#ifndef NANO_SMALL
3363 history_init();
3364#ifdef ENABLE_NANORC
3365 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3366 load_history();
3367#endif
3368#endif
3369
Chris Allegretta7662c862003-01-13 01:35:15 +00003370#ifndef DISABLE_OPERATINGDIR
3371 /* Set up the operating directory. This entails chdir()ing there,
3372 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003373 init_operating_dir();
3374#endif
3375
Chris Allegretta7662c862003-01-13 01:35:15 +00003376#ifndef DISABLE_JUSTIFY
3377 if (quotestr == NULL)
3378#ifdef HAVE_REGEX_H
3379 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3380#else
3381 quotestr = mallocstrcpy(NULL, "> ");
3382#endif
3383#endif /* !DISABLE_JUSTIFY */
3384 if (tabsize == -1)
3385 tabsize = 8;
3386
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003387 /* Clear the filename we'll be using */
3388 filename = charalloc(1);
3389 filename[0] = '\0';
3390
Chris Allegretta7662c862003-01-13 01:35:15 +00003391 /* If there's a +LINE flag, it is the first non-option argument. */
3392 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3393 startline = atoi(&argv[optind][1]);
3394 optind++;
3395 }
3396 if (0 < optind && optind < argc)
3397 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003398
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003399 /* See if there's a non-option in argv (first non-option is the
3400 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003401 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003402 /* Look for the +line flag... */
3403 if (argv[optind][0] == '+') {
3404 startline = atoi(&argv[optind][1]);
3405 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003406 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003407 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003408 } else
3409 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003410 }
3411
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003412 /* First back up the old settings so they can be restored, duh */
3413 tcgetattr(0, &oldterm);
3414
3415#ifdef _POSIX_VDISABLE
3416 term = oldterm;
3417 term.c_cc[VINTR] = _POSIX_VDISABLE;
3418 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3419 term.c_lflag &= ~IEXTEN;
3420 tcsetattr(0, TCSANOW, &term);
3421#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003422
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003423 /* now ncurses init stuff... */
3424 initscr();
3425 savetty();
3426 nonl();
3427 cbreak();
3428 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003429
3430 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003431 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003432 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003433 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003434
3435#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003436 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003437#endif
3438
Chris Allegretta2a42af12000-09-12 23:02:49 +00003439 window_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003440#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00003441 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003442#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003443
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003444 keypad(edit, TRUE);
3445 keypad(bottomwin, TRUE);
Chris Allegretta48bd3782002-01-03 21:26:34 +00003446
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003447#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003448 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003449#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003450 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003451 display_main_list();
3452
3453#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003454 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003455#endif
3456
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003457 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003458#ifdef ENABLE_MULTIBUFFER
3459 /* If we're using multibuffers and more than one file is specified
3460 on the command line, load them all and switch to the first one
3461 afterward */
3462 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3463 for (optind++; optind < argc; optind++) {
3464 add_open_file(1);
3465 new_file();
3466 filename = mallocstrcpy(filename, argv[optind]);
3467 open_file(filename, 0, 0);
3468 load_file(0);
3469 }
3470 open_nextfile_void();
3471 }
3472#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003473
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003474 titlebar(NULL);
3475
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003476 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003477 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003478
Chris Allegretta7662c862003-01-13 01:35:15 +00003479 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003480 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003481
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003482 /* SHUT UP GCC! */
3483 startline = 0;
3484 fill_flag_used = 0;
3485 keyhandled = 0;
3486
Chris Allegretta7662c862003-01-13 01:35:15 +00003487 /* This variable should be initialized after the sigsetjmp(), so we
3488 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003489 modify_control_seq = 0;
3490
Robert Siemborski6967eec2000-07-08 14:23:32 +00003491 edit_refresh();
3492 reset_cursor();
3493
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003494 while (1) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003495 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003496
Chris Allegrettad26ab912003-01-28 01:16:47 +00003497 if (ISSET(CONSTUPDATE))
3498 do_cursorpos(1);
3499
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003500#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003501 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003502#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003503
Chris Allegretta9239d742000-09-06 15:19:18 +00003504#ifndef _POSIX_VDISABLE
3505 /* We're going to have to do it the old way, i.e. on cygwin */
3506 raw();
3507#endif
3508
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003509 kbinput = get_kbinput(edit, &meta, ISSET(REBIND_DELETE));
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003510#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003511 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003512#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003513 if (meta == 1) {
Chris Allegretta7662c862003-01-13 01:35:15 +00003514 switch (kbinput) {
Chris Allegretta355fbe52001-07-14 19:32:47 +00003515#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003516 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003517 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003518 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003519 keyhandled = 1;
3520 break;
3521 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003522 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003523 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003524 keyhandled = 1;
3525 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003526#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003527 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003528 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003529 for (s = main_list; s != NULL; s = s->next)
Chris Allegretta7662c862003-01-13 01:35:15 +00003530 if (kbinput == s->altval || (kbinput >= 'A' &&
3531 kbinput <= 'Z' && kbinput == s->altval - 32)) {
Chris Allegretta6232d662002-05-12 19:52:15 +00003532 if (ISSET(VIEW_MODE) && !s->viewok)
3533 print_view_warning();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003534 else {
3535 if (s->func != do_cut_text)
3536 UNSET(KEEP_CUTBUFFER);
Chris Allegretta6232d662002-05-12 19:52:15 +00003537 s->func();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003538 }
Chris Allegretta6232d662002-05-12 19:52:15 +00003539 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003540 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003541 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003542#ifndef NANO_SMALL
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003543 if (!keyhandled)
3544 /* And for toggle switches */
3545 for (t = toggles; t != NULL; t = t->next)
3546 if (kbinput == t->val || (t->val >= 'a' &&
3547 t->val <= 'z' && kbinput == t->val - 32)) {
3548 UNSET(KEEP_CUTBUFFER);
3549 do_toggle(t);
3550 keyhandled = 1;
3551 break;
3552 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003553#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003554#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003555 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003556 kbinput);
3557#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003558 }
3559 }
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003560
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003561 /* Look through the main shortcut list to see if we've hit a
3562 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003563
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003564 if (!keyhandled)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003565#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003566 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003567#else
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003568 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003569#endif
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003570 if (kbinput == s->val ||
3571 (s->misc1 && kbinput == s->misc1) ||
3572 (s->misc2 && kbinput == s->misc2)) {
3573 if (ISSET(VIEW_MODE) && !s->viewok)
3574 print_view_warning();
3575 else {
3576 if (s->func != do_cut_text)
3577 UNSET(KEEP_CUTBUFFER);
3578 s->func();
3579 }
3580 keyhandled = 1;
3581 /* Rarely, the value of s can change after
3582 s->func(), leading to problems; get around this
3583 by breaking out explicitly once we successfully
3584 handle a shortcut */
3585 break;
3586 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003587 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003588
3589 if (!keyhandled)
3590 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003591
3592#ifdef _POSIX_VDISABLE
3593 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003594 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003595 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003596 if (kbinput == NANO_CONTROL_S)
3597 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003598#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003599 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3600 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003601 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003602 keyhandled = 1;
3603
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003604 /* Catch ^Z by hand when triggered also */
3605 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003606 if (ISSET(SUSPEND))
3607 do_suspend(0);
3608 keyhandled = 1;
3609 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003610
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003611 /* Last gasp, stuff that's not in the main lists */
3612 if (!keyhandled)
3613 switch (kbinput) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003614#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003615 case KEY_MOUSE:
3616 do_mouse();
3617 break;
3618#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003619
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003620 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3621 * have been handled before we
3622 * got here */
3623 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003624 break;
3625 default:
3626#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003627 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003628#endif
3629 /* We no longer stop unhandled sequences so that people with
3630 odd character sets can type... */
3631
Chris Allegretta7662c862003-01-13 01:35:15 +00003632 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003633 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003634 else
3635 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003636 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003637
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003638 reset_cursor();
3639 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003640 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003641 assert(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003642}