blob: 268d473e251ce07643e3e344da81dbb55895aa78 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 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
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +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 Ramsey53809442004-01-30 04:29:52 +0000243 /* Turn the keypad on, so that it still works after a Meta-X. */
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 Ramseyf5b256b2003-10-03 20:26:25 +0000248#ifndef DISABLE_MOUSE
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) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000406 /* true if the character in s->metaval is shown in first column */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000407 int meta_shortcut = 0;
408
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000409 if (s->val != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000410#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000411 if (s->val == NANO_HISTORY_KEY)
412 ptr += sprintf(ptr, "%.2s", _("Up"));
413 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000414#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000415 if (s->val == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000416 ptr += sprintf(ptr, "^%.5s", _("Space"));
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000417 else if (s->val == NANO_CONTROL_8)
418 ptr += sprintf(ptr, "^?");
419 else
420 ptr += sprintf(ptr, "^%c", s->val + 64);
421 }
422#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000423 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000424 meta_shortcut = 1;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000425 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000426 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
427 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000428 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000429 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000430#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000431
432 *(ptr++) = '\t';
433
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000434 if (s->func_key != NANO_NO_KEY)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000435 ptr += sprintf(ptr, "(F%d)", s->func_key - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000436
437 *(ptr++) = '\t';
438
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000439 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
440 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000441 else if (meta_shortcut && s->misc != NANO_NO_KEY)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000442 ptr += sprintf(ptr, "(M-%c)", toupper(s->misc));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000443
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);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000455 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000456 _("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"));
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +0000632 print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000633#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000634#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000635 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000636#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000637#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000638#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000639 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000640#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000641 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
642#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000643#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000644 print1opt("-M", "--mac", _("Write file in Mac format"));
645 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000646#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000647#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000648 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000649#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000650#ifdef HAVE_REGEX_H
651 print1opt("-R", "--regexp", _("Do regular expression searches"));
652#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000653#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000654 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000655#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000656 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000657 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000658#ifdef ENABLE_COLOR
659 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
660#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000661 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000662#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000663 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000664 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
665 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000666#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000667 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000668#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000669 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000670#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000671#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000672 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000673#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000674 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000675#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000676 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000677#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000678#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000679 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000680#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000681 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
682 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000683#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000684 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000685#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000686 print1opt("-x", "--nohelp", _("Don't show help window"));
687 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000688
689 /* this is a special case */
690 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000691
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000692 exit(0);
693}
694
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000695void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000696{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000697 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000698 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000699 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000700 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000701 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000702
Chris Allegrettae6600372003-01-17 03:39:41 +0000703#ifndef ENABLE_NLS
704 printf(" --disable-nls");
705#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000706#ifdef DEBUG
707 printf(" --enable-debug");
708#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000709#ifdef NANO_EXTRA
710 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000711#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000712#ifdef NANO_SMALL
713 printf(" --enable-tiny");
714#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000715#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000716 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000717#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000718#ifdef DISABLE_HELP
719 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000720#endif
721#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000722 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000723#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000724#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000725 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000726#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000727#ifdef DISABLE_OPERATINGDIR
728 printf(" --disable-operatingdir");
729#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000730#ifdef DISABLE_SPELLER
731 printf(" --disable-speller");
732#endif
733#ifdef DISABLE_TABCOMP
734 printf(" --disable-tabcomp");
735#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000736#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000737#ifdef DISABLE_WRAPPING
738 printf(" --disable-wrapping");
739#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000740#ifdef DISABLE_ROOTWRAP
741 printf(" --disable-wrapping-as-root");
742#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000743#ifdef ENABLE_COLOR
744 printf(" --enable-color");
745#endif
746#ifdef ENABLE_MULTIBUFFER
747 printf(" --enable-multibuffer");
748#endif
749#ifdef ENABLE_NANORC
750 printf(" --enable-nanorc");
751#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000752#ifdef USE_SLANG
753 printf(" --with-slang");
754#endif
755 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000756}
757
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000758/* Stuff we do when we abort from programs and want to clean up the
759 * screen. This doesn't do much right now. */
760void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000761{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000762 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000763}
764
765int no_help(void)
766{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000767 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000768}
769
Chris Allegrettad865da12002-07-29 23:46:38 +0000770#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000771void nano_disabled_msg(void)
772{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000773 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000774}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000775#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000776
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000777#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000778static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000779 * below. It must be global since the signal
780 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000781RETSIGTYPE cancel_fork(int signal)
782{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000783 if (kill(pid, SIGKILL) == -1)
784 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000785}
786
787int open_pipe(const char *command)
788{
789 int fd[2];
790 FILE *f;
791 struct sigaction oldaction, newaction;
792 /* original and temporary handlers for SIGINT */
793#ifdef _POSIX_VDISABLE
794 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000795#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000796 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000797 /* cancel_sigs == 1 means that sigaction() failed without changing
798 * the signal handlers. cancel_sigs == 2 means the signal handler
799 * was changed, but the tcsetattr didn't succeed.
800 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000801 * I use this variable since it is important to put things back when
802 * we finish, even if we get errors. */
803
804 /* Make our pipes. */
805
806 if (pipe(fd) == -1) {
807 statusbar(_("Could not pipe"));
808 return 1;
809 }
810
811 /* Fork a child. */
812
813 if ((pid = fork()) == 0) {
814 close(fd[0]);
815 dup2(fd[1], fileno(stdout));
816 dup2(fd[1], fileno(stderr));
817 /* If execl() returns at all, there was an error. */
818
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000819 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000820 exit(0);
821 }
822
823 /* Else continue as parent. */
824
825 close(fd[1]);
826
827 if (pid == -1) {
828 close(fd[0]);
829 statusbar(_("Could not fork"));
830 return 1;
831 }
832
833 /* Before we start reading the forked command's output, we set
834 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000835 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000836 cancel_sigs = 1;
837 nperror("sigaction");
838 } else {
839 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000840 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000841 cancel_sigs = 1;
842 nperror("sigaction");
843 }
844 }
845 /* Note that now oldaction is the previous SIGINT signal handler,
846 * to be restored later. */
847
848 /* See if the platform supports disabling individual control
849 * characters. */
850#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000851 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000852 cancel_sigs = 2;
853 nperror("tcgetattr");
854 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000855 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000856 newterm = term;
857 /* Grab oldterm's VINTR key :-) */
858 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
859 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
860 cancel_sigs = 2;
861 nperror("tcsetattr");
862 }
863 }
864#endif /* _POSIX_VDISABLE */
865
866 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000867 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000868 nperror("fdopen");
869
870 read_file(f, "stdin", 0);
871 /* if multibuffer mode is on, we could be here in view mode; if so,
872 don't set the modification flag */
873 if (!ISSET(VIEW_MODE))
874 set_modified();
875
876 if (wait(NULL) == -1)
877 nperror("wait");
878
879#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000880 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000881 nperror("tcsetattr");
882#endif /* _POSIX_VDISABLE */
883
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000884 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000885 nperror("sigaction");
886
887 return 0;
888}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000889#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000890
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000891#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000892void do_mouse(void)
893{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000894 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000895
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000896 if (get_mouseinput(&mouse_x, &mouse_y, 1) == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000897
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000898 /* Click in the edit window to move the cursor, but only when
899 we're not in a subfunction. */
900 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
901 int sameline;
902 /* Did they click on the line with the cursor? If they
903 clicked on the cursor, we set the mark. */
904 size_t xcur;
905 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000906
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000907 /* Subtract out size of topwin. Perhaps we need a constant
908 somewhere? */
909 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000910
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000911 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000912
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000913 /* Move to where the click occurred. */
914 for (; current_y < mouse_y && current->next != NULL; current_y++)
915 current = current->next;
916 for (; current_y > mouse_y && current->prev != NULL; current_y--)
917 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000918
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000919 xcur = actual_x(current->data, get_page_start(xplustabs()) +
920 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000921
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000922 /* Selecting where the cursor is toggles the mark. As does
923 selecting beyond the line length with the cursor at the
924 end of the line. */
925 if (sameline && xcur == current_x) {
926 if (ISSET(VIEW_MODE)) {
927 print_view_warning();
928 return;
929 }
930 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000931 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000932
933 current_x = xcur;
934 placewewant = xplustabs();
935 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000936 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000937 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000938 /* FIXME: If we clicked on a location in the statusbar, the cursor
939 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000940}
941#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000942
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000943/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000944void do_char(char ch)
945{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000946 size_t current_len = strlen(current->data);
947#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
948 int refresh = 0;
949 /* Do we have to run edit_refresh(), or can we get away with
950 * update_line()? */
951#endif
952
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000953 if (ch == '\0') /* Null to newline, if needed. */
954 ch = '\n';
955 else if (ch == '\n') { /* Newline to Enter, if needed. */
956 do_enter();
957 return;
958 }
959
960 assert(current != NULL && current->data != NULL);
961
962 /* When a character is inserted on the current magicline, it means
963 * we need a new one! */
964 if (filebot == current) {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000965 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000966 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000967 }
968
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000969 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000970 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000971 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000972 charmove(&current->data[current_x + 1], &current->data[current_x],
973 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000974 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000975 totsize++;
976 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000977
Chris Allegretta6df90f52002-07-19 01:08:59 +0000978#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000979 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000980 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000981 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000982#endif
983
Chris Allegretta6df90f52002-07-19 01:08:59 +0000984 do_right();
985
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000986#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +0000987 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +0000988 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000989#endif
990
Chris Allegretta6df90f52002-07-19 01:08:59 +0000991#ifdef ENABLE_COLOR
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000992 if (ISSET(COLOR_SYNTAX))
993 refresh = 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000994#endif
995
996#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
997 if (refresh)
998 edit_refresh();
999#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001000}
1001
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001002int do_verbatim_input(void)
1003{
David Lawrence Ramseyee383db2004-02-06 03:07:10 +00001004 int *verbatim_kbinput; /* Used to hold verbatim input. */
1005 int verbatim_len; /* Length of verbatim input. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001006 int i;
1007
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001008 statusbar(_("Verbatim input"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001009 verbatim_kbinput = get_verbatim_kbinput(edit, &verbatim_len, 1);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001010
1011 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1012 * off afterwards, so that if constant cursor position display is
1013 * on, it will be updated properly. */
1014 SET(DISABLE_CURPOS);
1015 for (i = 0; i < verbatim_len; i++)
David Lawrence Ramsey815cba82004-02-07 03:07:01 +00001016 do_char((char)verbatim_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001017 UNSET(DISABLE_CURPOS);
1018
1019 free(verbatim_kbinput);
1020
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001021 return 1;
1022}
1023
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001024int do_backspace(void)
1025{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001026 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001027 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001028 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001030 return 1;
1031}
1032
1033int do_delete(void)
1034{
1035 int refresh = 0;
1036
1037 /* blbf -> blank line before filebot (see below) */
1038 int blbf = 0;
1039
1040 if (current->next == filebot && current->data[0] == '\0')
1041 blbf = 1;
1042
1043 placewewant = xplustabs();
1044
1045 if (current_x != strlen(current->data)) {
1046 /* Let's get dangerous */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001047 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001048 strlen(current->data) - current_x);
1049
1050 align(&current->data);
1051#ifdef ENABLE_COLOR
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +00001052 if (ISSET(COLOR_SYNTAX))
1053 refresh = 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001054#endif
1055 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1056 /* We can delete the line before filebot only if it is blank: it
1057 becomes the new magic line then. */
1058
1059 filestruct *foo;
1060
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001061 current->data = charealloc(current->data,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001062 strlen(current->data) +
1063 strlen(current->next->data) + 1);
1064 strcat(current->data, current->next->data);
1065
1066 foo = current->next;
1067 if (filebot == foo) {
1068 filebot = current;
1069 editbot = current;
1070 }
1071
1072 unlink_node(foo);
1073 delete_node(foo);
1074 renumber(current);
1075 totlines--;
1076 refresh = 1;
1077 } else
1078 return 0;
1079
1080 totsize--;
1081 set_modified();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001082 update_line(current, current_x);
1083 if (refresh)
1084 edit_refresh();
1085 return 1;
1086}
1087
1088int do_tab(void)
1089{
1090 do_char('\t');
1091 return 1;
1092}
1093
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001094/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001095int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001096{
Chris Allegrettae3167732001-03-18 16:59:34 +00001097 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001098 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001099
Chris Allegretta6df90f52002-07-19 01:08:59 +00001100 newnode = make_new_node(current);
1101 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001102 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001103
Chris Allegrettaff989832001-09-17 13:48:00 +00001104#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001105 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001106 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001107 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001108 const char *spc = current->data;
1109
1110 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001111 extra++;
1112 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001113 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001114 /* If current_x < extra, then we are breaking the line in the
1115 * indentation. Autoindenting should add only current_x
1116 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001117 if (current_x < extra)
1118 extra = current_x;
1119 else
1120 current_x = extra;
1121 totsize += extra;
1122
1123 newnode->data = charalloc(strlen(tmp) + extra + 1);
1124 strncpy(newnode->data, current->data, extra);
1125 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001126 } else
1127#endif
1128 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001129 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001130 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001131 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001132 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001133 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001134
Chris Allegretta6df90f52002-07-19 01:08:59 +00001135 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001136 filebot = newnode;
1137 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001138 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001139 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001140
1141 totsize++;
1142 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001143 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001144 align(&current->data);
1145
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001146 /* The logic here is as follows:
1147 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001148 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001149 * -> otherwise, we want simply to redraw the screen and update
1150 * where we think the cursor is.
1151 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001152 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001153#ifndef NANO_SMALL
1154 if (ISSET(SMOOTHSCROLL))
1155 edit_update(current, NONE);
1156 else
1157#endif
1158 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001159 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001160 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001161 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001162 edit_refresh();
1163 update_cursor();
1164 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001165
1166 totlines++;
1167 set_modified();
1168
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001169 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001170 return 1;
1171}
1172
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001173#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001174int do_next_word(void)
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
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001198 /* Refresh the screen. If current has run off the bottom, this
1199 * call puts it at the center line. */
1200 edit_refresh();
1201
Chris Allegretta6232d662002-05-12 19:52:15 +00001202 return 0;
1203}
1204
Chris Allegretta6df90f52002-07-19 01:08:59 +00001205/* The same thing for backwards. */
1206int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001207{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001208 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001209
Chris Allegretta6df90f52002-07-19 01:08:59 +00001210 /* Skip letters in this word first. */
1211 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1212 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001213
Chris Allegretta6df90f52002-07-19 01:08:59 +00001214 for (; current != NULL; current = current->prev) {
1215 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1216 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001217
Chris Allegretta6df90f52002-07-19 01:08:59 +00001218 if (current_x >= 0)
1219 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001220
Chris Allegretta6df90f52002-07-19 01:08:59 +00001221 if (current->prev != NULL)
1222 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001223 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001224
Chris Allegretta6df90f52002-07-19 01:08:59 +00001225 if (current != NULL) {
1226 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1227 current_x--;
1228 } else {
1229 current = fileage;
1230 current_x = 0;
1231 }
1232
Chris Allegretta76e291b2001-10-14 19:05:10 +00001233 placewewant = xplustabs();
1234
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001235 /* Refresh the screen. If current has run off the top, this call
1236 * puts it at the center line. */
1237 edit_refresh();
1238
Chris Allegretta6232d662002-05-12 19:52:15 +00001239 return 0;
1240}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001241#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001242
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001243int do_mark(void)
1244{
1245#ifdef NANO_SMALL
1246 nano_disabled_msg();
1247#else
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001248 TOGGLE(MARK_ISSET);
1249 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001250 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001251 mark_beginbuf = current;
1252 mark_beginx = current_x;
1253 } else {
1254 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001255 edit_refresh();
1256 }
1257#endif
1258 return 1;
1259}
1260
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001261#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001262void wrap_reset(void)
1263{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001264 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001265}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001266#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001267
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001268#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001269/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001270 * moved forward since the last typed character. Return value:
1271 * whether we wrapped. */
1272int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001273{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001274 size_t len = strlen(inptr->data); /* length of the line we wrap */
1275 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001276 int wrap_loc = -1; /* index of inptr->data where we wrap */
1277 int word_back = -1;
1278#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001279 const char *indentation = NULL;
1280 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001281 int indent_len = 0; /* strlen(indentation) */
1282#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001283 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001284 int after_break_len; /* strlen(after_break) */
1285 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001286 const char *wrap_line = NULL;
1287 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001288 int wrap_line_len = 0; /* strlen(wrap_line) */
1289 char *newline = NULL; /* the line we create */
1290 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001291
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001292/* There are three steps. First, we decide where to wrap. Then, we
1293 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001294
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001295/* Step 1, finding where to wrap. We are going to add a new-line
1296 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001297 * location of this replacement.
1298 *
1299 * Where should we break the line? We need the last "legal wrap point"
1300 * such that the last word before it ended at or before fill. If there
1301 * is no such point, we settle for the first legal wrap point.
1302 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001303 * A "legal wrap point" is a white-space character that is not followed by
1304 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001305 *
1306 * If there is no legal wrap point or we found the last character of the
1307 * line, we should return without wrapping.
1308 *
1309 * Note that the initial indentation does not count as a legal wrap
1310 * point if we are going to auto-indent!
1311 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001312 * Note that the code below could be optimised, by not calling strnlenpt()
1313 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001314
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001315#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001316 if (ISSET(AUTOINDENT))
1317 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001318#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001319 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001320 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001321 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001322 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001323 word_back = i;
1324 /* if we have found a "legal wrap point" and the current word
1325 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001326 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001327 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001328 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001329 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001330 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001331 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001332 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001333 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001334
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001335/* Step 2, making the new wrap line. It will consist of indentation +
1336 * after_break + " " + wrap_line (although indentation and wrap_line are
1337 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001338
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001339 /* after_break is the text that will be moved to the next line. */
1340 after_break = inptr->data + wrap_loc + 1;
1341 after_break_len = len - wrap_loc - 1;
1342 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001343
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001344 /* new_line_len will later be increased by the lengths of indentation
1345 * and wrap_line. */
1346 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001347
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001348 /* We prepend the wrapped text to the next line, if the flag is set,
1349 * and there is a next line, and prepending would not make the line
1350 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001351 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001352 wrap_line = inptr->next->data;
1353 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001354
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001355 /* +1 for the space between after_break and wrap_line */
1356 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1357 wrapping = 1;
1358 new_line_len += (1 + wrap_line_len);
1359 }
1360 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001361
Chris Allegrettaff989832001-09-17 13:48:00 +00001362#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001363 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001364 /* Indentation comes from the next line if wrapping, else from
1365 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001366 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001367 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001368 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001369 /* The wrap_line text should not duplicate indentation.
1370 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001371 wrap_line += indent_len;
1372 else
1373 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001374 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001375#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001376
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001377 /* Now we allocate the new line and copy into it. */
1378 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1379 *newline = '\0';
1380
1381#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001382 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001383 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001384 newline[indent_len] = '\0';
1385 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001386#endif
1387 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001388 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001389 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001390 null_at(&inptr->data, wrap_loc + 1);
1391 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001392 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001393 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001394 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001395 * in a tab or a space, we don't add a space and decrement
1396 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001397 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001398 strcat(newline, " ");
1399 else
1400 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001401 strcat(newline, wrap_line);
1402 free(inptr->next->data);
1403 inptr->next->data = newline;
1404 } else {
1405 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001406
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001407 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001408 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001409#ifndef NANO_SMALL
1410 totsize += indent_len;
1411#endif
1412 totlines++;
1413 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001414 temp->prev = inptr;
1415 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001416 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001417 /* If temp->next is NULL, then temp is the last line of the
1418 * file, so we must set filebot. */
1419 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420 temp->next->prev = temp;
1421 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001422 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001423 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001424
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001425/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1426 * other sundry things. */
1427
1428 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001429 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001430
1431 /* Each line knows its line number. We recalculate these if we
1432 * inserted a new line. */
1433 if (!wrapping)
1434 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001435
Chris Allegretta6df90f52002-07-19 01:08:59 +00001436 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001437 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001438 current = current->next;
1439 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001440#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001441 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001442#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001443 wrap_loc + 1;
1444 wrap_reset();
1445 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001446 }
1447
Chris Allegretta6df90f52002-07-19 01:08:59 +00001448#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001449 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001450 * If it was on the next line and we wrapped, we must move it
1451 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001452 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1453 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001454 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001455 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001456 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001457#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001458
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001459 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001460 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001461
1462 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001463}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001464#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001465
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001466#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001467/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001468 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001469int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001470{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001471 char *save_search;
1472 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001473 filestruct *current_save = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001474 size_t current_x_save = current_x;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001475 filestruct *edittop_save = edittop;
1476 /* Save where we are. */
1477 int i = 0;
1478 /* The return value. */
1479 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001480#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001481 int case_sens_set = ISSET(CASE_SENSITIVE);
1482 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001483
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001484 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001485 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001486 UNSET(MARK_ISSET);
1487#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001488 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001489 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001490
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001491 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001492 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001493 save_search = last_search;
1494 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001495
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001496 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001497 last_search = mallocstrcpy(NULL, word);
1498 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001499
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001500 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001501 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001502 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001503
1504 search_last_line = FALSE;
1505
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001506 /* Find the first whole-word occurrence of word. */
1507 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001508 if (is_whole_word(current_x, current->data, word)) {
1509 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001510
Chris Allegretta6df90f52002-07-19 01:08:59 +00001511 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001512
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001513 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001514 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001515#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001516 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001517#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001518 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001519
Chris Allegretta6df90f52002-07-19 01:08:59 +00001520 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001521
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001522 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001523 search_last_line = FALSE;
1524 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001525 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001526 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001527
1528 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001529 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001530
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001531 /* Restore the search/replace strings. */
1532 free(last_search);
1533 last_search = save_search;
1534 free(last_replace);
1535 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001536
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001537 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001538 current = current_save;
1539 current_x = current_x_save;
1540 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001541
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001542 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001543 if (reverse_search_set)
1544 SET(REVERSE_SEARCH);
1545
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001546#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001547 if (!case_sens_set)
1548 UNSET(CASE_SENSITIVE);
1549
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001550 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001551 if (mark_set)
1552 SET(MARK_ISSET);
1553#endif
1554
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001555 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001556}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001557
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001558/* Integrated spell checking using 'spell' program. Return value: NULL
1559 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001560char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001561{
Chris Allegretta271e9722000-11-10 18:15:43 +00001562 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001563 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001564 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001565 pid_t pid_spell, pid_sort, pid_uniq;
1566 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001567
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001568 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001569 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1570 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001571
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001572 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001573
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001574 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001575 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001576
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001577 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001578
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001579 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001580
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001581 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001582 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1583 goto close_pipes_and_exit;
1584
1585 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1586 goto close_pipes_and_exit;
1587
Chris Allegretta271e9722000-11-10 18:15:43 +00001588 close(tempfile_fd);
1589
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001590 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001591 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1592 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001593
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001594 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001595
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001596 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001597 execlp("spell", "spell", NULL);
1598
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001599 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001600 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001601 }
1602
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001603 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001604 close(spell_fd[1]);
1605
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001606 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001607 if ((pid_sort = fork()) == 0) {
1608
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001609 /* Child continues (i.e, future spell process). Replace the
1610 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001611 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1612 goto close_pipes_and_exit;
1613
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001614 close(spell_fd[0]);
1615
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001616 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001617 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1618 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001619
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001620 close(sort_fd[1]);
1621
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001622 /* Start sort program. Use -f to remove mixed case without
1623 * having to have ANOTHER pipe for tr. If this isn't portable,
1624 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001625 execlp("sort", "sort", "-f", NULL);
1626
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001627 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001628 exit(1);
1629 }
1630
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001631 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001632 close(sort_fd[1]);
1633
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001634 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001635 if ((pid_uniq = fork()) == 0) {
1636
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001637 /* Child continues (i.e, future uniq process). Replace the
1638 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001639 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1640 goto close_pipes_and_exit;
1641
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001642 close(sort_fd[0]);
1643
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001644 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001645 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1646 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001647
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001648 close(uniq_fd[1]);
1649
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001650 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001651 execlp("uniq", "uniq", NULL);
1652
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001653 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001654 exit(1);
1655 }
1656
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001657 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001658 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001659
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001660 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001661 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1662 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001663 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001664 }
1665
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001666 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001667 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1668 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001669 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001670 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001671
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001672 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001673 read_buff_read = 0;
1674 read_buff_size = pipe_buff_size + 1;
1675 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001676
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001677 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001678 read_buff_read += bytesread;
1679 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001680 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001681 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001682
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001683 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001684
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001685 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001686 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001687
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001688 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001689 read_buff_word = read_buff_ptr = read_buff;
1690
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001691 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001692
1693 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001694 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001695 if (read_buff_word != read_buff_ptr) {
1696 if (!do_int_spell_fix(read_buff_word)) {
1697 read_buff_word = read_buff_ptr;
1698 break;
1699 }
1700 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001701 read_buff_word = read_buff_ptr + 1;
1702 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001703 read_buff_ptr++;
1704 }
1705
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001706 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001707 if (read_buff_word != read_buff_ptr)
1708 do_int_spell_fix(read_buff_word);
1709
Chris Allegretta271e9722000-11-10 18:15:43 +00001710 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001711 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001712 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001713
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001714 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001715 waitpid(pid_spell, &spell_status, 0);
1716 waitpid(pid_sort, &sort_status, 0);
1717 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001718
Chris Allegretta334a9402002-12-16 04:25:53 +00001719 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1720 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001721
Chris Allegretta334a9402002-12-16 04:25:53 +00001722 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1723 return _("Error invoking \"sort -f\"");
1724
1725 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1726 return _("Error invoking \"uniq\"");
1727
1728 /* Otherwise... */
1729 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001730
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001731 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001732
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001733 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001734 close(tempfile_fd);
1735 close(spell_fd[0]);
1736 close(spell_fd[1]);
1737 close(sort_fd[0]);
1738 close(sort_fd[1]);
1739 close(uniq_fd[0]);
1740 close(uniq_fd[1]);
1741 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001742}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001743
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001744/* External spell checking. Return value: NULL for normal termination,
1745 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001746char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001747{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001748 int alt_spell_status, lineno_cur = current->lineno;
1749 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001750 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001751 char *ptr;
1752 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001753 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001754#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001755 int mark_set = ISSET(MARK_ISSET);
1756 int mbb_lineno_cur = 0;
1757 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001758 * the alternate spell command. The line that mark_beginbuf
1759 * points to will be freed, so we save the line number and
1760 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001761
1762 if (mark_set) {
1763 mbb_lineno_cur = mark_beginbuf->lineno;
1764 UNSET(MARK_ISSET);
1765 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001766#endif
1767
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001768 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001769
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001770 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001771 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001772 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001773
Chris Allegrettae434b452001-01-27 19:25:00 +00001774 spellargs[0] = strtok(alt_speller, " ");
1775 while ((ptr = strtok(NULL, " ")) != NULL) {
1776 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001777 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001778 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001779 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001780 spellargs[arglen - 1] = NULL;
1781 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001782 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001783
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001784 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001785 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001786 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001787 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001788
1789 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001790 exit(1);
1791 }
1792
1793 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001794 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001795 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001796
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001797 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001798 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001799
Chris Allegretta334a9402002-12-16 04:25:53 +00001800 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1801 char *altspell_error = NULL;
1802 char *invoke_error = _("Could not invoke \"%s\"");
1803 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1804
1805 altspell_error = charalloc(msglen);
1806 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1807 return altspell_error;
1808 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001809
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001810 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001811#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001812 if (!mark_set) {
1813 /* Only reload the temp file if it isn't a marked selection. */
1814#endif
1815 free_filestruct(fileage);
1816 global_init(1);
1817 open_file(tempfile_name, 0, 1);
1818#ifndef NANO_SMALL
1819 }
1820
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001821 if (mark_set) {
1822 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1823 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001824 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001825 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001826 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001827 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001828#endif
1829
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001830 /* Go back to the old position, mark the file as modified, and make
1831 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001832 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001833 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001834 clearok(topwin, FALSE);
1835 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001836
Chris Allegretta334a9402002-12-16 04:25:53 +00001837 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001838}
1839#endif
1840
1841int do_spell(void)
1842{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001843#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001844 nano_disabled_msg();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001845 return 1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001846#else
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001847 int i;
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001848 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001849
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001850 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001851 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001852 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001853 return 0;
1854 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001855
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001856#ifndef NANO_SMALL
1857 if (ISSET(MARK_ISSET))
1858 i = write_marked(temp, 1, 0, 0);
1859 else
1860#endif
1861 i = write_file(temp, 1, 0, 0);
1862
1863 if (i == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001864 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001865 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001866 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001867 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001868
Chris Allegrettae1f14522001-09-19 03:19:43 +00001869#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001870 /* Update the current open_files entry before spell-checking, in
1871 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001872 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001873#endif
1874
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001875 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001876 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001877 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001878 spell_msg = do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001879 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001880 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001881
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001882 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001883 statusbar(_("Spell checking failed: %s"), spell_msg);
1884 return 0;
1885 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001886
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001887 statusbar(_("Finished checking spelling"));
1888 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001889#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001890}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001891
Chris Allegrettad865da12002-07-29 23:46:38 +00001892#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001893/* The "indentation" of a line is the white-space between the quote part
1894 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001895size_t indent_length(const char *line)
1896{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001897 size_t len = 0;
1898
1899 assert(line != NULL);
1900 while (*line == ' ' || *line == '\t') {
1901 line++;
1902 len++;
1903 }
1904 return len;
1905}
Chris Allegrettadffa2072002-07-24 01:02:26 +00001906#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001907
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001908#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00001909/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
1910 * it maintains 2 after a . ! or ?). Note the terminating \0
1911 * counts as a space.
1912 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001913 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001914 * returns 1, otherwise returns 0.
1915 *
1916 * If changes_allowed, justify_format() might make line->data
1917 * shorter, and change the actual pointer with null_at().
1918 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001919 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001920 * skip should be at most strlen(line->data). The skip+1st character must
1921 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001922int justify_format(int changes_allowed, filestruct *line, size_t skip)
1923{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001924 const char *punct = ".?!";
1925 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001926 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001927
Chris Allegretta6df90f52002-07-19 01:08:59 +00001928 /* These four asserts are assumptions about the input data. */
1929 assert(line != NULL);
1930 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001931 assert(skip < strlen(line->data));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001932 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001933
Chris Allegretta6df90f52002-07-19 01:08:59 +00001934 back = line->data + skip;
1935 front = back;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001936 for (front = back; ; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001937 int remove_space = 0;
1938 /* Do we want to remove this space? */
1939
Chris Allegretta6df90f52002-07-19 01:08:59 +00001940 if (*front == '\t') {
1941 if (!changes_allowed)
1942 return 1;
1943 *front = ' ';
1944 }
1945 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001946 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001947 const char *bob = front - 2;
1948
1949 remove_space = 1;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001950 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001951 if (strchr(punct, *bob) != NULL) {
1952 remove_space = 0;
1953 break;
1954 }
1955 if (strchr(brackets, *bob) == NULL)
1956 break;
1957 }
1958 }
1959
1960 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001961 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001962 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001963 if (!changes_allowed)
1964 return 1;
1965#ifndef NANO_SMALL
1966 if (mark_beginbuf == line && back - line->data < mark_beginx)
1967 mark_beginx--;
1968#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001969 if (*front == '\0')
1970 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001971 } else {
1972 *back = *front;
1973 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001974 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001975 if (*front == '\0')
1976 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001977 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001978
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001979 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001980 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001981
1982 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001983 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001984
1985 /* Now back is the new end of line->data. */
1986 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001987 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001988 null_at(&line->data, back - line->data);
1989#ifndef NANO_SMALL
1990 if (mark_beginbuf == line && back - line->data < mark_beginx)
1991 mark_beginx = back - line->data;
1992#endif
1993 }
1994 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001995}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001996
1997/* The "quote part" of a line is the largest initial substring matching
1998 * the quote string. This function returns the length of the quote part
1999 * of the given line.
2000 *
2001 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2002 * quotestr. */
2003#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002004size_t quote_length(const char *line, const regex_t *qreg)
2005{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002006 regmatch_t matches;
2007 int rc = regexec(qreg, line, 1, &matches, 0);
2008
2009 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2010 return 0;
2011 /* matches.rm_so should be 0, since the quote string should start with
2012 * the caret ^. */
2013 return matches.rm_eo;
2014}
2015#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002016size_t quote_length(const char *line)
2017{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002018 size_t qdepth = 0;
2019 size_t qlen = strlen(quotestr);
2020
2021 /* Compute quote depth level */
2022 while (!strcmp(line + qdepth, quotestr))
2023 qdepth += qlen;
2024 return qdepth;
2025}
2026#endif /* !HAVE_REGEX_H */
2027
Chris Allegretta6df90f52002-07-19 01:08:59 +00002028/* a_line and b_line are lines of text. The quotation part of a_line is
2029 * the first a_quote characters. Check that the quotation part of
2030 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002031int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002032 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002033{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002034 /* Here is the assumption about a_quote: */
2035 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002036 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002037 !strncmp(a_line, b_line, a_quote);
2038}
2039
2040/* We assume a_line and b_line have no quote part. Then, we return whether
2041 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002042size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002043 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002044{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002045 assert(a_indent == indent_length(a_line));
2046 assert(b_indent == indent_length(b_line));
2047
2048 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2049}
2050
2051/* Put the next par_len lines, starting with first_line, in the cut
2052 * buffer. We assume there are enough lines after first_line. We leave
2053 * copies of the lines in place, too. We return the new copy of
2054 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002055filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002056 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002057{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002058 /* We put the original lines, not copies, into the cut buffer, just
2059 * out of a misguided sense of consistency, so if you un-cut, you
2060 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002061 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002062
2063 set_modified();
2064 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002065 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002066 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002067
Chris Allegretta908f7702003-01-15 11:18:58 +00002068 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002069 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002070 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002071 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002072 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002073 edittop = bob;
2074#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002075 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002076 mark_beginbuf = bob;
2077#endif
2078 justify_format(1, bob,
2079 quote_len + indent_length(bob->data + quote_len));
2080
Chris Allegretta908f7702003-01-15 11:18:58 +00002081 assert(alice != NULL && bob != NULL);
2082 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002083 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002084 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002085 }
2086 return first_line;
2087}
2088
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002089/* Is it possible to break line at or before goal? */
2090int breakable(const char *line, int goal)
2091{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002092 for (; *line != '\0' && goal >= 0; line++) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002093 if (*line == ' ' || *line == '\t')
2094 return TRUE;
2095
2096 if (is_cntrl_char(*line) != 0)
2097 goal -= 2;
2098 else
2099 goal -= 1;
2100 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002101 /* If goal is not negative, the whole line (one word) was short
2102 * enough. */
2103 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002104}
2105
Chris Allegretta6df90f52002-07-19 01:08:59 +00002106/* We are trying to break a chunk off line. We find the last space such
2107 * that the display length to there is at most goal + 1. If there is
2108 * no such space, and force is not 0, then we find the first space.
2109 * Anyway, we then take the last space in that group of spaces. The
2110 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002111int break_line(const char *line, int goal, int force)
2112{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002113 /* Note that we use int instead of size_t, since goal is at most COLS,
2114 * the screen width, which will always be reasonably small. */
2115 int space_loc = -1;
2116 /* Current tentative return value. Index of the last space we
2117 * found with short enough display width. */
2118 int cur_loc = 0;
2119 /* Current index in line */
2120
2121 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002122 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002123 if (*line == ' ')
2124 space_loc = cur_loc;
2125 assert(*line != '\t');
2126
Chris Allegrettacf287c82002-07-20 13:57:41 +00002127 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002128 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002129 else
2130 goal--;
2131 }
2132 if (goal >= 0)
2133 /* In fact, the whole line displays shorter than goal. */
2134 return cur_loc;
2135 if (space_loc == -1) {
2136 /* No space found short enough. */
2137 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002138 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002139 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002140 return cur_loc;
2141 return -1;
2142 }
2143 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002144 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002145 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2146 *(line - cur_loc + space_loc + 1) == '\0')
2147 space_loc++;
2148 return space_loc;
2149}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002150
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002151/* Search a paragraph. If search_type is 0, search for the beginning of
2152 * the current paragraph or, if we're at the end of it, the beginning of
2153 * the next paragraph. If search_type is 1, search for the beginning of
2154 * the current paragraph or, if we're already there, the beginning of
2155 * the previous paragraph. If search_type is 2, search for the end of
2156 * the current paragraph or, if we're already there, the end of the next
2157 * paragraph. Afterwards, save the quote length, paragraph length, and
2158 * indentation length in *quote, *par, and *indent if they aren't NULL,
2159 * and refresh the screen if do_refresh is nonzero. Return 0 if we
2160 * found a paragraph, or 1 if there was an error or we didn't find a
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002161 * paragraph.
2162 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002163 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002164 * phrases about paragraphs and quotation:
2165 * A line of text consists of a "quote part", followed by an
2166 * "indentation part", followed by text. The functions quote_length()
2167 * and indent_length() calculate these parts.
2168 *
2169 * A line is "part of a paragraph" if it has a part not in the quote
2170 * part or the indentation.
2171 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002172 * A line is "the beginning of a paragraph" if it is part of a
2173 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002174 * 1) it is the top line of the file, or
2175 * 2) the line above it is not part of a paragraph, or
2176 * 3) the line above it does not have precisely the same quote
2177 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002178 * 4) the indentation of this line is not an initial substring of
2179 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002180 * 5) this line has no quote part and some indentation, and
2181 * AUTOINDENT is not set.
2182 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002183 * indented line is expected to start a paragraph, like in books.
2184 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2185 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002186 *
2187 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002188 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002189 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002190int do_para_search(int search_type, size_t *quote, size_t *par, size_t
2191 *indent, int do_refresh)
2192{
2193 size_t quote_len;
2194 /* Length of the initial quotation of the paragraph we
2195 * search. */
2196 size_t par_len;
2197 /* Number of lines in that paragraph. */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002198
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002199 /* We save this global variable to see if we're where we started
2200 * when searching for the beginning of the paragraph. */
2201 filestruct *current_save = current;
2202
2203 size_t indent_len; /* Generic indentation length. */
2204 filestruct *line; /* Generic line of text. */
2205
2206 static int do_restart = 1;
2207 /* Whether we're restarting when searching for the beginning
2208 * line of the paragraph. */
2209
2210#ifdef HAVE_REGEX_H
2211 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2212 * longer care about quotestr. */
2213 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2214
2215 if (rc != 0) {
2216 size_t size = regerror(rc, &qreg, NULL, 0);
2217 char *strerror = charalloc(size);
2218
2219 regerror(rc, &qreg, strerror, size);
2220 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2221 free(strerror);
2222 return 1;
2223 }
2224#endif
2225
2226 /* Here is an assumption that is always true anyway. */
2227 assert(current != NULL);
2228
2229 current_x = 0;
2230
2231 restart_para_search:
2232/* Here we find the first line of the paragraph to search. If the
2233 * current line is in a paragraph, then we move back to the first line.
2234 * Otherwise we move to the first line that is in a paragraph. */
2235 quote_len = quote_length(IFREG(current->data, &qreg));
2236 indent_len = indent_length(current->data + quote_len);
2237
2238 if (current->data[quote_len + indent_len] != '\0') {
2239 /* This line is part of a paragraph. So we must search back to
2240 * the first line of this paragraph. First we check items 1)
2241 * and 3) above. */
2242 while (current->prev != NULL && quotes_match(current->data,
2243 quote_len, IFREG(current->prev->data, &qreg))) {
2244 size_t temp_id_len =
2245 indent_length(current->prev->data + quote_len);
2246 /* The indentation length of the previous line. */
2247
2248 /* Is this line the beginning of a paragraph, according to
2249 * items 2), 5), or 4) above? If so, stop. */
2250 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2251 (quote_len == 0 && indent_len > 0
2252#ifndef NANO_SMALL
2253 && !ISSET(AUTOINDENT)
2254#endif
2255 ) ||
2256 !indents_match(current->prev->data + quote_len,
2257 temp_id_len, current->data + quote_len, indent_len))
2258 break;
2259 indent_len = temp_id_len;
2260 current = current->prev;
2261 current_y--;
2262 }
2263 } else if (search_type == 1) {
2264 /* This line is not part of a paragraph. Move up until we get
2265 * to a non "blank" line, and then move down once. */
2266 do {
2267 /* There is no previous paragraph, so nothing to move to. */
2268 if (current->prev == NULL) {
2269 placewewant = 0;
2270 if (do_refresh) {
2271 if (current_y < 0)
2272 edit_update(current, CENTER);
2273 else
2274 edit_refresh();
2275 }
2276#ifdef HAVE_REGEX_H
2277 if (!do_restart)
2278 regfree(&qreg);
2279#endif
2280 return 1;
2281 }
2282 current = current->prev;
2283 current_y--;
2284 quote_len = quote_length(IFREG(current->data, &qreg));
2285 indent_len = indent_length(current->data + quote_len);
2286 } while (current->data[quote_len + indent_len] == '\0');
2287 current = current->next;
2288 } else {
2289 /* This line is not part of a paragraph. Move down until we get
2290 * to a non "blank" line. */
2291 do {
2292 /* There is no next paragraph, so nothing to move to. */
2293 if (current->next == NULL) {
2294 placewewant = 0;
2295 if (do_refresh)
2296 edit_refresh();
2297#ifdef HAVE_REGEX_H
2298 regfree(&qreg);
2299#endif
2300 return 1;
2301 }
2302 current = current->next;
2303 current_y++;
2304 quote_len = quote_length(IFREG(current->data, &qreg));
2305 indent_len = indent_length(current->data + quote_len);
2306 } while (current->data[quote_len + indent_len] == '\0');
2307 }
2308
2309/* Now current is the first line of the paragraph, and quote_len is the
2310 * quotation length of that line. */
2311
2312/* Next step, compute par_len, the number of lines in this paragraph. */
2313 line = current;
2314 par_len = 1;
2315 indent_len = indent_length(line->data + quote_len);
2316
2317 while (line->next != NULL && quotes_match(current->data, quote_len,
2318 IFREG(line->next->data, &qreg))) {
2319 size_t temp_id_len = indent_length(line->next->data + quote_len);
2320
2321 if (!indents_match(line->data + quote_len, indent_len,
2322 line->next->data + quote_len, temp_id_len) ||
2323 line->next->data[quote_len + temp_id_len] == '\0' ||
2324 (quote_len == 0 && temp_id_len > 0
2325#ifndef NANO_SMALL
2326 && !ISSET(AUTOINDENT)
2327#endif
2328 ))
2329 break;
2330 indent_len = temp_id_len;
2331 line = line->next;
2332 par_len++;
2333 }
2334
2335 if (search_type == 1) {
2336 /* We're on the same line we started on. Move up until we get
2337 * to a non-"blank" line, restart the search from there until we
2338 * find a line that's part of a paragraph, and search once more
2339 * so that we end up at the beginning of that paragraph. */
2340 if (current != fileage && current == current_save && do_restart) {
2341 while (current->prev != NULL) {
2342 size_t i, j = 0;
2343 current = current->prev;
2344 current_y--;
2345 /* Skip over lines consisting only of spacing
2346 * characters, as searching for the end of the paragraph
2347 * does. */
2348 for (i = 0; current->data[i] != '\0'; i++) {
2349 if (isspace(current->data[i]))
2350 j++;
2351 else {
2352 i = 0;
2353 j = 1;
2354 break;
2355 }
2356 }
2357 if (i != j && strlen(current->data) >=
2358 (quote_len + indent_len) &&
2359 current->data[quote_len + indent_len] != '\0') {
2360 do_restart = 0;
2361 break;
2362 }
2363 }
2364 goto restart_para_search;
2365 } else
2366 do_restart = 1;
2367 }
2368
2369#ifdef HAVE_REGEX_H
2370 /* We no longer need to check quotation. */
2371 regfree(&qreg);
2372#endif
2373
2374/* Now par_len is the number of lines in this paragraph. We should
2375 * never call quotes_match() or quote_length() again. */
2376
2377 /* If we're searching for the end of the paragraph, move down the
2378 * number of lines in the paragraph. */
2379 if (search_type == 2) {
2380 for (; par_len > 0; current_y++, par_len--)
2381 current = current->next;
2382 }
2383
2384 /* Refresh the screen if needed. */
2385 if (do_refresh) {
2386 if (((search_type == 0 || search_type == 2) && current_y >
2387 editwinrows - 1) || (search_type == 1 && current_y < 0))
2388 edit_update(current, CENTER);
2389 else
2390 edit_refresh();
2391 }
2392
2393 /* Save the values of quote_len, par_len, and indent_len if
2394 * needed. */
2395 if (quote != NULL)
2396 *quote = quote_len;
2397 if (par != NULL)
2398 *par = par_len;
2399 if (indent != NULL)
2400 *indent = indent_len;
2401
2402 return 0;
2403}
2404
2405int do_para_begin(void)
2406{
2407 return do_para_search(1, NULL, NULL, NULL, TRUE);
2408}
2409
2410int do_para_end(void)
2411{
2412 return do_para_search(2, NULL, NULL, NULL, TRUE);
2413}
2414#endif
2415
2416/* Justify a paragraph. */
2417int do_justify(void)
2418{
2419#ifdef DISABLE_JUSTIFY
2420 nano_disabled_msg();
2421 return 1;
2422#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002423 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002424 /* Length of the initial quotation of the paragraph we
2425 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002426 size_t par_len;
2427 /* Number of lines in that paragraph. */
2428 filestruct *first_mod_line = NULL;
2429 /* Will be the first line of the resulting justified paragraph
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002430 * that differs from the original. For restoring after
2431 * uncut. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002432 filestruct *last_par_line = current;
2433 /* Will be the last line of the result, also for uncut. */
2434 filestruct *cutbuffer_save = cutbuffer;
2435 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002436 * one down are stored in the cut buffer. We back up the
2437 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002438
2439 /* We save these global variables to be restored if the user
2440 * unjustifies. Note we don't need to save totlines. */
2441 int current_x_save = current_x;
2442 int current_y_save = current_y;
2443 filestruct *current_save = current;
2444 int flags_save = flags;
2445 long totsize_save = totsize;
2446 filestruct *edittop_save = edittop;
2447 filestruct *editbot_save = editbot;
2448#ifndef NANO_SMALL
2449 filestruct *mark_beginbuf_save = mark_beginbuf;
2450 int mark_beginx_save = mark_beginx;
2451#endif
2452
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002453 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002454 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002455
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002456 /* First, search for the beginning of the current paragraph or, if
2457 * we're at the end of it, the beginning of the next paragraph.
2458 * Save the quote length, paragraph length, and indentation length
2459 * and don't refresh the screen yet (since we'll do that after we
2460 * justify). If the search failed, refresh the screen and get
2461 * out. */
2462 if (do_para_search(0, &quote_len, &par_len, &indent_len, FALSE) != 0) {
2463 edit_refresh();
2464 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002465 }
2466
Chris Allegretta6df90f52002-07-19 01:08:59 +00002467/* Next step, we loop through the lines of this paragraph, justifying
2468 * each one individually. */
Chris Allegretta8151ba52003-04-19 19:34:05 +00002469 SET(JUSTIFY_MODE);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002470 for (; par_len > 0; current_y++, par_len--) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002471 size_t line_len;
2472 size_t display_len;
2473 /* The width of current in screen columns. */
2474 int break_pos;
2475 /* Where we will break the line. */
2476
2477 indent_len = indent_length(current->data + quote_len) +
2478 quote_len;
2479 /* justify_format() removes excess spaces from the line, and
2480 * changes tabs to spaces. The first argument, 0, means don't
2481 * change the line, just say whether there are changes to be
2482 * made. If there are, we do backup_lines(), which copies the
2483 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002484 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002485 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002486 first_mod_line = backup_lines(current, par_len, quote_len);
2487
2488 line_len = strlen(current->data);
2489 display_len = strlenpt(current->data);
2490
2491 if (display_len > fill) {
2492 /* The line is too long. Try to wrap it to the next. */
2493 break_pos = break_line(current->data + indent_len,
2494 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002495 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002496 if (break_pos == -1 || break_pos + indent_len == line_len)
2497 /* We can't break the line, or don't need to, so just go
2498 * on to the next. */
2499 goto continue_loc;
2500 break_pos += indent_len;
2501 assert(break_pos < line_len);
2502 /* If we haven't backed up the paragraph, do it now. */
2503 if (first_mod_line == NULL)
2504 first_mod_line = backup_lines(current, par_len, quote_len);
2505 if (par_len == 1) {
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002506 /* There is no next line in this paragraph. We make a
2507 * new line and copy text after break_pos into it. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002508 splice_node(current, make_new_node(current),
2509 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002510 /* In a non-quoted paragraph, we copy the indent only if
2511 AUTOINDENT is turned on. */
2512 if (quote_len == 0)
2513#ifndef NANO_SMALL
2514 if (!ISSET(AUTOINDENT))
2515#endif
2516 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002517 current->next->data = charalloc(indent_len + line_len -
2518 break_pos);
2519 strncpy(current->next->data, current->data,
2520 indent_len);
2521 strcpy(current->next->data + indent_len,
2522 current->data + break_pos + 1);
2523 assert(strlen(current->next->data) ==
2524 indent_len + line_len - break_pos - 1);
2525 totlines++;
2526 totsize += indent_len;
2527 par_len++;
2528 } else {
2529 size_t next_line_len = strlen(current->next->data);
2530
2531 indent_len = quote_len +
2532 indent_length(current->next->data + quote_len);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002533 current->next->data = charealloc(current->next->data,
2534 next_line_len + line_len - break_pos + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002535
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002536 charmove(current->next->data + indent_len + line_len - break_pos,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002537 current->next->data + indent_len,
2538 next_line_len - indent_len + 1);
2539 strcpy(current->next->data + indent_len,
2540 current->data + break_pos + 1);
2541 current->next->data[indent_len + line_len - break_pos - 1]
2542 = ' ';
2543#ifndef NANO_SMALL
2544 if (mark_beginbuf == current->next) {
2545 if (mark_beginx < indent_len)
2546 mark_beginx = indent_len;
2547 mark_beginx += line_len - break_pos;
2548 }
2549#endif
2550 }
2551#ifndef NANO_SMALL
2552 if (mark_beginbuf == current && mark_beginx > break_pos) {
2553 mark_beginbuf = current->next;
2554 mark_beginx -= break_pos + 1 - indent_len;
2555 }
2556#endif
2557 null_at(&current->data, break_pos);
2558 current = current->next;
2559 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002560 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002561
2562 indent_len = quote_len +
2563 indent_length(current->next->data + quote_len);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002564 /* If we can't pull a word from the next line up to this
2565 * one, just go on. */
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002566 if (!breakable(current->next->data + indent_len,
2567 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002568 goto continue_loc;
2569
2570 /* If we haven't backed up the paragraph, do it now. */
2571 if (first_mod_line == NULL)
2572 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002573
2574 break_pos = break_line(current->next->data + indent_len,
2575 fill - display_len - 1, FALSE);
2576 assert(break_pos != -1);
2577
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002578 current->data = charealloc(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002579 line_len + break_pos + 2);
2580 current->data[line_len] = ' ';
2581 strncpy(current->data + line_len + 1,
2582 current->next->data + indent_len, break_pos);
2583 current->data[line_len + break_pos + 1] = '\0';
2584#ifndef NANO_SMALL
2585 if (mark_beginbuf == current->next) {
2586 if (mark_beginx < indent_len + break_pos) {
2587 mark_beginbuf = current;
2588 if (mark_beginx <= indent_len)
2589 mark_beginx = line_len + 1;
2590 else
2591 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2592 } else
2593 mark_beginx -= break_pos + 1;
2594 }
2595#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002596 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002597 if (indent_len + break_pos == next_line_len) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002598 filestruct *line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002599
2600 /* Don't destroy edittop! */
2601 if (line == edittop)
2602 edittop = current;
2603
Chris Allegretta6df90f52002-07-19 01:08:59 +00002604 unlink_node(line);
2605 delete_node(line);
2606 totlines--;
2607 totsize -= indent_len;
2608 current_y--;
2609 } else {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002610 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002611 current->next->data + indent_len + break_pos + 1,
2612 next_line_len - break_pos - indent_len);
2613 null_at(&current->next->data,
2614 next_line_len - break_pos);
2615 current = current->next;
2616 }
2617 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002618 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002619 current = current->next;
2620 }
Chris Allegretta8151ba52003-04-19 19:34:05 +00002621 UNSET(JUSTIFY_MODE);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002622
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002623/* We are now done justifying the paragraph. There are cleanup things
2624 * to do, and we check for unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002625
2626 /* totlines, totsize, and current_y have been maintained above. We
2627 * now set last_par_line to the new end of the paragraph, update
2628 * fileage, set current_x. Also, edit_refresh() needs the line
2629 * numbers to be right, so we renumber(). */
2630 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002631 if (first_mod_line != NULL) {
2632 if (first_mod_line->prev == NULL)
2633 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002634 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002635 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002636
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002637 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002638 edit_update(current, CENTER);
2639 else
2640 edit_refresh();
2641
Chris Allegretta9149e612000-11-27 00:23:41 +00002642 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002643 /* Change the shortcut list to display the unjustify code. */
Chris Allegretta07798352000-11-27 22:58:23 +00002644 shortcut_init(1);
2645 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002646 reset_cursor();
2647
Chris Allegretta6df90f52002-07-19 01:08:59 +00002648 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002649 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002650
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002651 {
2652 int meta;
2653 i = get_kbinput(edit, &meta);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002654#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002655 /* If it was a mouse click, parse it with do_mouse() and it
2656 * might become the unjustify key. Else give it back to the
2657 * input stream. */
2658 if (i == KEY_MOUSE)
2659 do_mouse();
2660 else
2661 ungetch(i);
2662 i = get_kbinput(edit, &meta);
Chris Allegretta5f071802001-05-06 02:34:31 +00002663#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002664 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002665
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002666 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002667 ungetch(i);
2668 /* Did we back up anything at all? */
2669 if (cutbuffer != cutbuffer_save)
2670 free_filestruct(cutbuffer);
2671 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002672 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002673 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002674 current = current_save;
2675 current_x = current_x_save;
2676 current_y = current_y_save;
2677 edittop = edittop_save;
2678 editbot = editbot_save;
2679 if (first_mod_line != NULL) {
2680 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002681
Chris Allegretta6df90f52002-07-19 01:08:59 +00002682 /* Splice the cutbuffer back into the file. */
2683 cutbottom->next = last_par_line->next;
2684 cutbottom->next->prev = cutbottom;
2685 /* The line numbers after the end of the paragraph have
2686 * been changed, so we change them back. */
2687 renumber(cutbottom->next);
2688 if (first_mod_line->prev != NULL) {
2689 cutbuffer->prev = first_mod_line->prev;
2690 cutbuffer->prev->next = cutbuffer;
2691 } else
2692 fileage = cutbuffer;
2693 cutbuffer = NULL;
2694
2695 last_par_line->next = NULL;
2696 free_filestruct(first_mod_line);
2697
2698 /* Restore global variables from before justify */
2699 totsize = totsize_save;
2700 totlines = filebot->lineno;
2701#ifndef NANO_SMALL
2702 mark_beginbuf = mark_beginbuf_save;
2703 mark_beginx = mark_beginx_save;
2704#endif
2705 flags = flags_save;
2706 if (!ISSET(MODIFIED)) {
2707 titlebar(NULL);
2708 wrefresh(topwin);
2709 }
2710 }
2711 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002712 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002713 cutbuffer = cutbuffer_save;
2714 blank_statusbar_refresh();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002715 /* display shortcut list with UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002716 shortcut_init(0);
2717 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002718
Chris Allegretta6df90f52002-07-19 01:08:59 +00002719 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002720#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002721}
2722
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002723int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002724{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002725 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002726
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002727 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002728
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002729#ifdef ENABLE_MULTIBUFFER
2730 if (!close_open_file()) {
2731 display_main_list();
2732 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002733 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002734 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002735#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002736 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002737 }
2738
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002739 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002740 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002741 else
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002742 i = do_yesno(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002743
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002744#ifdef DEBUG
2745 dump_buffer(fileage);
2746#endif
2747
2748 if (i == 1) {
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002749 if (do_writeout(TRUE) > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002750
2751#ifdef ENABLE_MULTIBUFFER
2752 if (!close_open_file()) {
2753 display_main_list();
2754 return 1;
2755 }
2756 else
2757#endif
2758 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002759 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002760 } else if (i == 0) {
2761
2762#ifdef ENABLE_MULTIBUFFER
2763 if (!close_open_file()) {
2764 display_main_list();
2765 return 1;
2766 }
2767 else
2768#endif
2769 finish(0);
2770 } else
2771 statusbar(_("Cancelled"));
2772
2773 display_main_list();
2774 return 1;
2775}
2776
2777void signal_init(void)
2778{
2779#ifdef _POSIX_VDISABLE
2780 struct termios term;
2781#endif
2782
2783 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2784 memset(&act, 0, sizeof(struct sigaction));
2785 act.sa_handler = SIG_IGN;
2786 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002787 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002788
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002789 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2790 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002791 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002792 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002793
2794#ifndef NANO_SMALL
2795 act.sa_handler = handle_sigwinch;
2796 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002797 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002798#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
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002856 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
2857 suspended */
2858 act.sa_handler = handle_hupterm;
2859 sigaction(SIGHUP, &act, NULL);
2860 sigaction(SIGTERM, &act, NULL);
2861
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002862 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002863 then we could be (and were) interrupted in the middle of the call.
2864 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002865 kill(0, SIGSTOP);
2866}
2867
2868/* Restore the suspend handler when we come back into the prog */
2869RETSIGTYPE do_cont(int signal)
2870{
2871 /* Now we just update the screen instead of having to reenable the
2872 SIGTSTP handler. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002873 doupdate();
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002874
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002875 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
David Lawrence Ramseya593f532003-11-28 19:47:42 +00002876 start suspending again. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002877 signal_init();
2878
2879#ifndef NANO_SMALL
2880 /* Perhaps the user resized the window while we slept. */
2881 handle_sigwinch(0);
2882#endif
2883}
2884
2885#ifndef NANO_SMALL
2886void handle_sigwinch(int s)
2887{
2888 const char *tty = ttyname(0);
2889 int fd;
2890 int result = 0;
2891 struct winsize win;
2892
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002893 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002894 return;
2895 fd = open(tty, O_RDWR);
2896 if (fd == -1)
2897 return;
2898 result = ioctl(fd, TIOCGWINSZ, &win);
2899 close(fd);
2900 if (result == -1)
2901 return;
2902
2903 /* Could check whether the COLS or LINES changed, and return
2904 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2905 * variables, and in some cases ncurses has already updated them.
2906 * But not in all cases, argh. */
2907 COLS = win.ws_col;
2908 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002909 editwinrows = LINES - 5 + no_help();
2910 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002911 die_too_small();
2912
2913#ifndef DISABLE_WRAPJUSTIFY
2914 fill = wrap_at;
2915 if (fill <= 0)
2916 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002917 if (fill < 0)
2918 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002919#endif
2920
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002921 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002922 memset(hblank, ' ', COLS);
2923 hblank[COLS] = '\0';
2924
2925#ifdef HAVE_RESIZETERM
2926 resizeterm(LINES, COLS);
2927#ifdef HAVE_WRESIZE
2928 if (wresize(topwin, 2, COLS) == ERR)
2929 die(_("Cannot resize top win"));
2930 if (mvwin(topwin, 0, 0) == ERR)
2931 die(_("Cannot move top win"));
2932 if (wresize(edit, editwinrows, COLS) == ERR)
2933 die(_("Cannot resize edit win"));
2934 if (mvwin(edit, 2, 0) == ERR)
2935 die(_("Cannot move edit win"));
2936 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2937 die(_("Cannot resize bottom win"));
2938 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2939 die(_("Cannot move bottom win"));
2940#endif /* HAVE_WRESIZE */
2941#endif /* HAVE_RESIZETERM */
2942
2943 fix_editbot();
2944
2945 if (current_y > editwinrows - 1)
2946 edit_update(editbot, CENTER);
2947 erase();
2948
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002949 /* Do these because width may have changed. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002950 refresh();
2951 titlebar(NULL);
2952 edit_refresh();
2953 display_main_list();
2954 blank_statusbar();
2955 total_refresh();
2956
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002957 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002958 curs_set(1);
2959
David Lawrence Ramsey53809442004-01-30 04:29:52 +00002960 /* Turn the keypad on and switch to cbreak mode, so that the keypad
2961 * and input still work if we resized during verbatim input. */
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002962 keypad(edit, TRUE);
2963 keypad(bottomwin, TRUE);
David Lawrence Ramsey53809442004-01-30 04:29:52 +00002964#ifdef _POSIX_VDISABLE
2965 cbreak();
2966#endif
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002967
2968 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002969 siglongjmp(jmpbuf, 1);
2970}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002971
2972void allow_pending_sigwinch(int allow)
2973{
2974 sigset_t winch;
2975 sigemptyset(&winch);
2976 sigaddset(&winch, SIGWINCH);
2977 if (allow)
2978 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2979 else
2980 sigprocmask(SIG_BLOCK, &winch, NULL);
2981}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002982#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002983
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002984/* If the NumLock key has made the keypad go awry, print an error
2985 message; hopefully we can address it later. */
2986void print_numlock_warning(void)
2987{
2988 static int didmsg = 0;
2989 if (!didmsg) {
2990 statusbar(_
2991 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2992 didmsg = 1;
2993 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002994}
2995
Chris Allegrettadab017e2002-04-23 10:56:06 +00002996#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002997void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002998{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002999 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00003000
Chris Allegretta658399a2001-06-14 02:54:22 +00003001 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003002 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00003003
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003004 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00003005 case TOGGLE_SUSPEND_KEY:
3006 signal_init();
3007 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003008#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003009 case TOGGLE_MOUSE_KEY:
3010 mouse_init();
3011 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003012#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003013 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00003014 wclear(bottomwin);
3015 wrefresh(bottomwin);
3016 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00003017 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00003018 edit_refresh();
3019 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00003020 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00003021 case TOGGLE_DOS_KEY:
3022 UNSET(MAC_FILE);
3023 break;
3024 case TOGGLE_MAC_KEY:
3025 UNSET(DOS_FILE);
3026 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003027#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003028 case TOGGLE_SYNTAX_KEY:
3029 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003030 break;
3031#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003032 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003033
Chris Allegretta6df90f52002-07-19 01:08:59 +00003034 /* We are assuming here that shortcut_init() above didn't free and
3035 * reallocate the toggles. */
3036 enabled = ISSET(which->flag);
3037 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3038 enabled = !enabled;
3039 statusbar("%s %s", which->desc,
3040 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003041}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003042#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003043
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003044int main(int argc, char *argv[])
3045{
3046 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003047 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003048 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003049 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003050 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003051 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003052 int kbinput; /* Input from keyboard */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003053 int meta;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003054
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003055#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003056 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003057#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003058#ifdef _POSIX_VDISABLE
3059 struct termios term;
3060#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003061#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003062 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003063 {"help", 0, 0, 'h'},
3064#ifdef ENABLE_MULTIBUFFER
3065 {"multibuffer", 0, 0, 'F'},
3066#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003067#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003068#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003069 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003070#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003071 {"ignorercfiles", 0, 0, 'I'},
3072#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003073#ifndef DISABLE_JUSTIFY
3074 {"quotestr", 1, 0, 'Q'},
3075#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003076#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003077 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003078#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003079 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003080 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003081#ifdef ENABLE_COLOR
3082 {"syntax", 1, 0, 'Y'},
3083#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003084 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003085 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003086 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003087#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003088 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003089#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003090#ifndef DISABLE_OPERATINGDIR
3091 {"operatingdir", 1, 0, 'o'},
3092#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003093 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003094#ifndef DISABLE_WRAPJUSTIFY
3095 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003096#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003097#ifndef DISABLE_SPELLER
3098 {"speller", 1, 0, 's'},
3099#endif
3100 {"tempfile", 0, 0, 't'},
3101 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003102#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003103 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003104#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003105 {"nohelp", 0, 0, 'x'},
3106 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003107#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003108 {"backup", 0, 0, 'B'},
3109 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003110 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003111 {"mac", 0, 0, 'M'},
3112 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003113 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003114 {"autoindent", 0, 0, 'i'},
3115 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003116#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003117 {0, 0, 0, 0}
3118 };
3119#endif
3120
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003121#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003122 setlocale(LC_ALL, "");
3123 bindtextdomain(PACKAGE, LOCALEDIR);
3124 textdomain(PACKAGE);
3125#endif
3126
Chris Allegretta7662c862003-01-13 01:35:15 +00003127#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003128 /* if we don't have rcfile support, we're root, and
3129 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003130 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003131 SET(NO_WRAP);
3132#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003133
3134#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003135 while ((optchr = getopt_long(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003136 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003137#else
3138 while ((optchr =
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003139 getopt(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003140#endif
3141
3142 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003143
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003144 case 'a':
3145 case 'b':
3146 case 'e':
3147 case 'f':
3148 case 'g':
3149 case 'j':
3150 /* Pico compatibility flags */
3151 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003152#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003153 case 'B':
3154 SET(BACKUP_FILE);
3155 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003156 case 'D':
3157 SET(DOS_FILE);
3158 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003159 case 'E':
3160 backup_dir = mallocstrcpy(backup_dir, optarg);
3161 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003162#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003163#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003164 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003165 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003166 break;
3167#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003168#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003169#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003170 case 'H':
3171 SET(HISTORYLOG);
3172 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003173#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003174 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003175 SET(NO_RCFILE);
3176 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003177#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003178#ifndef NANO_SMALL
3179 case 'M':
3180 SET(MAC_FILE);
3181 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003182 case 'N':
3183 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003184 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003185#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003186#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003187 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003188 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003189 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003190#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003191#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003192 case 'R':
3193 SET(USE_REGEXP);
3194 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003195#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003196#ifndef NANO_SMALL
3197 case 'S':
3198 SET(SMOOTHSCROLL);
3199 break;
3200#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003201 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003202 {
3203 int i;
3204 char *first_error;
3205
Chris Allegretta7662c862003-01-13 01:35:15 +00003206 /* Using strtol() instead of atoi() lets us accept 0
3207 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003208 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003209 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003210 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003211 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003212 tabsize = i;
3213 if (tabsize <= 0) {
3214 fprintf(stderr, _("Tab size is too small for nano...\n"));
3215 exit(1);
3216 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003217 }
3218 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003219 case 'V':
3220 version();
3221 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003222#ifdef ENABLE_COLOR
3223 case 'Y':
3224 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3225 break;
3226#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003227 case 'c':
3228 SET(CONSTUPDATE);
3229 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003230 case 'd':
3231 SET(REBIND_DELETE);
3232 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003233#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003234 case 'i':
3235 SET(AUTOINDENT);
3236 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003237 case 'k':
3238 SET(CUT_TO_END);
3239 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003240#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003241 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003242 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003243 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003244#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003245 case 'm':
3246 SET(USE_MOUSE);
3247 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003248#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003249#ifndef DISABLE_OPERATINGDIR
3250 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003251 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003252 break;
3253#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003254 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003255 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003256 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003257#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003258 case 'r':
3259 {
3260 int i;
3261 char *first_error;
3262
Chris Allegretta7662c862003-01-13 01:35:15 +00003263 /* Using strtol() instead of atoi() lets us accept 0
3264 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003265 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003266 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003267 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003268 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003269 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003270 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003271 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003272 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003273#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003274#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003275 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003276 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003277 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003278#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003279 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003280 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003281 break;
3282 case 'v':
3283 SET(VIEW_MODE);
3284 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003285#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003286 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003287 SET(NO_WRAP);
3288 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003289#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003290 case 'x':
3291 SET(NO_HELP);
3292 break;
3293 case 'z':
3294 SET(SUSPEND);
3295 break;
3296 default:
3297 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003298 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003299 }
3300
Chris Allegretta7662c862003-01-13 01:35:15 +00003301/* We've read through the command line options. Now back up the flags
3302 and values that are set, and read the rcfile(s). If the values
3303 haven't changed afterward, restore the backed-up values. */
3304#ifdef ENABLE_NANORC
3305 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003306#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003307 char *operating_dir_cpy = operating_dir;
3308#endif
3309#ifndef DISABLE_WRAPPING
3310 int wrap_at_cpy = wrap_at;
3311#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003312#ifndef NANO_SMALL
3313 char *backup_dir_cpy = backup_dir;
3314#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003315#ifndef DISABLE_JUSTIFY
3316 char *quotestr_cpy = quotestr;
3317#endif
3318#ifndef DISABLE_SPELLER
3319 char *alt_speller_cpy = alt_speller;
3320#endif
3321 int tabsize_cpy = tabsize;
3322 long flags_cpy = flags;
3323
Chris Allegretta5ec68622003-02-05 02:39:34 +00003324#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003325 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003326#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003327#ifndef NANO_SMALL
3328 backup_dir = NULL;
3329#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003330#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003331 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003332#endif
3333#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003334 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003335#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003336
3337 do_rcfile();
3338
3339#ifndef DISABLE_OPERATINGDIR
3340 if (operating_dir_cpy != NULL) {
3341 free(operating_dir);
3342 operating_dir = operating_dir_cpy;
3343 }
3344#endif
3345#ifndef DISABLE_WRAPPING
3346 if (fill_flag_used)
3347 wrap_at = wrap_at_cpy;
3348#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003349#ifndef NANO_SMALL
3350 if (backup_dir_cpy != NULL) {
3351 free(backup_dir);
3352 backup_dir = backup_dir_cpy;
3353 }
3354#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003355#ifndef DISABLE_JUSTIFY
3356 if (quotestr_cpy != NULL) {
3357 free(quotestr);
3358 quotestr = quotestr_cpy;
3359 }
3360#endif
3361#ifndef DISABLE_SPELLER
3362 if (alt_speller_cpy != NULL) {
3363 free(alt_speller);
3364 alt_speller = alt_speller_cpy;
3365 }
3366#endif
3367 if (tabsize_cpy > 0)
3368 tabsize = tabsize_cpy;
3369 flags |= flags_cpy;
3370 }
3371#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003372 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003373 SET(NO_WRAP);
3374#endif
3375#endif /* ENABLE_NANORC */
3376
Chris Allegrettad8451932003-03-11 03:50:40 +00003377#ifndef NANO_SMALL
3378 history_init();
3379#ifdef ENABLE_NANORC
3380 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3381 load_history();
3382#endif
3383#endif
3384
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003385#ifndef NANO_SMALL
3386 /* Set up the backup directory. This entails making sure it exists
3387 * and is a directory, so that backup files will be saved there. */
3388 init_backup_dir();
3389#endif
3390
Chris Allegretta7662c862003-01-13 01:35:15 +00003391#ifndef DISABLE_OPERATINGDIR
3392 /* Set up the operating directory. This entails chdir()ing there,
3393 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003394 init_operating_dir();
3395#endif
3396
Chris Allegretta7662c862003-01-13 01:35:15 +00003397#ifndef DISABLE_JUSTIFY
3398 if (quotestr == NULL)
3399#ifdef HAVE_REGEX_H
3400 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3401#else
3402 quotestr = mallocstrcpy(NULL, "> ");
3403#endif
3404#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003405
Chris Allegretta7662c862003-01-13 01:35:15 +00003406 if (tabsize == -1)
3407 tabsize = 8;
3408
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003409 /* Clear the filename we'll be using */
3410 filename = charalloc(1);
3411 filename[0] = '\0';
3412
Chris Allegretta7662c862003-01-13 01:35:15 +00003413 /* If there's a +LINE flag, it is the first non-option argument. */
3414 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3415 startline = atoi(&argv[optind][1]);
3416 optind++;
3417 }
3418 if (0 < optind && optind < argc)
3419 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003420
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003421 /* See if there's a non-option in argv (first non-option is the
3422 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003423 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003424 /* Look for the +line flag... */
3425 if (argv[optind][0] == '+') {
3426 startline = atoi(&argv[optind][1]);
3427 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003428 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003429 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003430 } else
3431 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003432 }
3433
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003434 /* Termios initialization stuff: Back up the old settings so that
3435 * they can be restored, disable SIGINT on ^C and SIGQUIT on ^\,
3436 * since we need them for Cancel and Replace, and disable
3437 * implementation-defined input processing. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003438 tcgetattr(0, &oldterm);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003439#ifdef _POSIX_VDISABLE
3440 term = oldterm;
3441 term.c_cc[VINTR] = _POSIX_VDISABLE;
3442 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3443 term.c_lflag &= ~IEXTEN;
3444 tcsetattr(0, TCSANOW, &term);
3445#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003446
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003447 /* Curses initialization stuff: Start curses, save the state of the
3448 * the terminal mode, disable translation of carriage return (^M)
3449 * into newline (^J) so we can catch the Enter key and use ^J for
3450 * Justify, turn the keypad on for the windows that read input, put
3451 * the terminal in cbreak mode (read one character at a time and
3452 * interpret the special control keys) if we can selectively disable
3453 * the special control keys or raw mode (read one character at a
3454 * time and don't interpret the special control keys) if we
3455 * can't, and turn off echoing of characters as they're typed. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003456 initscr();
3457 savetty();
3458 nonl();
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003459 keypad(edit, TRUE);
3460 keypad(bottomwin, TRUE);
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003461#ifdef _POSIX_VDISABLE
3462 cbreak();
3463#else
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003464 raw();
3465#endif
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003466 noecho();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003467
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003468 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003469 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003470 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003471
3472 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003473 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003474
3475#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003476 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003477#endif
3478
Chris Allegretta2a42af12000-09-12 23:02:49 +00003479 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003480#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003481 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003482#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003483
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003484#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003485 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003486#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003487 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003488 display_main_list();
3489
3490#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003491 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003492#endif
3493
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003494 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003495#ifdef ENABLE_MULTIBUFFER
3496 /* If we're using multibuffers and more than one file is specified
3497 on the command line, load them all and switch to the first one
3498 afterward */
3499 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3500 for (optind++; optind < argc; optind++) {
3501 add_open_file(1);
3502 new_file();
3503 filename = mallocstrcpy(filename, argv[optind]);
3504 open_file(filename, 0, 0);
3505 load_file(0);
3506 }
3507 open_nextfile_void();
3508 }
3509#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003510
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003511 titlebar(NULL);
3512
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003513 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003514 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003515
Chris Allegretta7662c862003-01-13 01:35:15 +00003516 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003517 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003518
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003519 /* SHUT UP GCC! */
3520 startline = 0;
3521 fill_flag_used = 0;
3522 keyhandled = 0;
3523
Chris Allegretta7662c862003-01-13 01:35:15 +00003524 /* This variable should be initialized after the sigsetjmp(), so we
3525 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003526 modify_control_seq = 0;
3527
Robert Siemborski6967eec2000-07-08 14:23:32 +00003528 edit_refresh();
3529 reset_cursor();
3530
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003531 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003532 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003533
Chris Allegrettad26ab912003-01-28 01:16:47 +00003534 if (ISSET(CONSTUPDATE))
3535 do_cursorpos(1);
3536
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003537#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003538 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003539#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003540
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003541 kbinput = get_kbinput(edit, &meta);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003542#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003543 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003544#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003545 if (meta == 1) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003546 /* Check for the metaval and misc defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003547 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003548 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
3549 (s->misc != NANO_NO_KEY && kbinput == s->misc)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003550 if (ISSET(VIEW_MODE) && !s->viewok)
3551 print_view_warning();
3552 else {
3553 if (s->func != do_cut_text)
3554 UNSET(KEEP_CUTBUFFER);
3555 s->func();
3556 }
3557 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003558 }
3559#ifndef NANO_SMALL
3560 if (!keyhandled)
3561 /* And for toggle switches */
3562 for (t = toggles; t != NULL; t = t->next)
3563 if (kbinput == t->val) {
3564 UNSET(KEEP_CUTBUFFER);
3565 do_toggle(t);
3566 keyhandled = 1;
3567 }
3568#endif
3569#ifdef DEBUG
3570 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3571 kbinput);
3572#endif
3573 }
3574
3575 /* Look through the main shortcut list to see if we've hit a
3576 shortcut key or function key */
3577
3578 if (!keyhandled)
3579#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3580 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3581#else
3582 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3583#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003584 if ((s->val != NANO_NO_KEY && kbinput == s->val) ||
3585 (s->func_key != NANO_NO_KEY && kbinput == s->func_key)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003586 if (ISSET(VIEW_MODE) && !s->viewok)
3587 print_view_warning();
3588 else {
3589 if (s->func != do_cut_text)
3590 UNSET(KEEP_CUTBUFFER);
3591 s->func();
3592 }
3593 keyhandled = 1;
3594 /* Break out explicitly once we successfully handle
3595 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003596 break;
3597 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003598 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003599
3600 if (!keyhandled)
3601 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003602
3603#ifdef _POSIX_VDISABLE
3604 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003605 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003606 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003607 if (kbinput == NANO_CONTROL_S)
3608 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003609#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003610 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3611 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003612 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003613 keyhandled = 1;
3614
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003615 /* Catch ^Z by hand when triggered also */
3616 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003617 if (ISSET(SUSPEND))
3618 do_suspend(0);
3619 keyhandled = 1;
3620 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003621
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003622 /* Last gasp, stuff that's not in the main lists */
3623 if (!keyhandled)
3624 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003625#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003626 case KEY_MOUSE:
3627 do_mouse();
3628 break;
3629#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003630
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003631 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3632 * have been handled before we
3633 * got here */
3634 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003635 break;
3636 default:
3637#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003638 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003639#endif
3640 /* We no longer stop unhandled sequences so that people with
3641 odd character sets can type... */
3642
Chris Allegretta7662c862003-01-13 01:35:15 +00003643 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003644 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003645 else
3646 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003647 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003648
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003649 reset_cursor();
3650 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003651 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003652 assert(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003653}