blob: e5e8e6fe8e28c6e6efd886f4426f635627b41c2a [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 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001179
Chris Allegretta6df90f52002-07-19 01:08:59 +00001180 /* Skip letters in this word first. */
1181 while (current->data[current_x] != '\0' &&
1182 isalnum((int)current->data[current_x]))
1183 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001184
Chris Allegretta6df90f52002-07-19 01:08:59 +00001185 for (; current != NULL; current = current->next) {
1186 while (current->data[current_x] != '\0' &&
1187 !isalnum((int)current->data[current_x]))
1188 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189
Chris Allegretta6df90f52002-07-19 01:08:59 +00001190 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001191 break;
1192
Chris Allegretta6df90f52002-07-19 01:08:59 +00001193 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001194 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001195 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001196 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001197
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001198 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001199
Chris Allegrettad865da12002-07-29 23:46:38 +00001200 if (current->lineno >= editbot->lineno) {
1201 /* If we're on the last line, don't center the screen. */
1202 if (current->lineno == filebot->lineno)
1203 edit_refresh();
1204 else
1205 edit_update(current, CENTER);
1206 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001207 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001208 /* If we've jumped lines, refresh the old line. We can't just
1209 use current->prev here, because we may have skipped over some
1210 blank lines, in which case the previous line is the wrong
1211 one. */
1212 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001213 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001214 /* If the mark was set, then the lines between old and
1215 current have to be updated too. */
1216 if (ISSET(MARK_ISSET)) {
1217 while (old->next != current) {
1218 old = old->next;
1219 update_line(old, 0);
1220 }
1221 }
1222 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001223 update_line(current, current_x);
1224 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001225 return 0;
1226}
1227
Chris Allegretta6df90f52002-07-19 01:08:59 +00001228/* The same thing for backwards. */
1229int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001230{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001231 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001232
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001233 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001234
Chris Allegretta6df90f52002-07-19 01:08:59 +00001235 /* Skip letters in this word first. */
1236 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1237 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001238
Chris Allegretta6df90f52002-07-19 01:08:59 +00001239 for (; current != NULL; current = current->prev) {
1240 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1241 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001242
Chris Allegretta6df90f52002-07-19 01:08:59 +00001243 if (current_x >= 0)
1244 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001245
Chris Allegretta6df90f52002-07-19 01:08:59 +00001246 if (current->prev != NULL)
1247 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001248 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001249
Chris Allegretta6df90f52002-07-19 01:08:59 +00001250 if (current != NULL) {
1251 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1252 current_x--;
1253 } else {
1254 current = fileage;
1255 current_x = 0;
1256 }
1257
Chris Allegretta76e291b2001-10-14 19:05:10 +00001258 placewewant = xplustabs();
1259
Chris Allegrettad865da12002-07-29 23:46:38 +00001260 if (current->lineno <= edittop->lineno) {
1261 /* If we're on the first line, don't center the screen. */
1262 if (current->lineno == fileage->lineno)
1263 edit_refresh();
1264 else
1265 edit_update(current, CENTER);
1266 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001267 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001268 /* If we've jumped lines, refresh the old line. We can't just
1269 use current->prev here, because we may have skipped over some
1270 blank lines, in which case the previous line is the wrong
1271 one. */
1272 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001273 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001274 /* If the mark was set, then the lines between old and
1275 current have to be updated too. */
1276 if (ISSET(MARK_ISSET)) {
1277 while (old->prev != current) {
1278 old = old->prev;
1279 update_line(old, 0);
1280 }
1281 }
1282 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001283 update_line(current, current_x);
1284 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001285 return 0;
1286}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001287#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001288
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001289int do_mark(void)
1290{
1291#ifdef NANO_SMALL
1292 nano_disabled_msg();
1293#else
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001294 TOGGLE(MARK_ISSET);
1295 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001296 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001297 mark_beginbuf = current;
1298 mark_beginx = current_x;
1299 } else {
1300 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001301 edit_refresh();
1302 }
1303#endif
1304 return 1;
1305}
1306
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001307#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001308void wrap_reset(void)
1309{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001310 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001311}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001312#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001313
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001314#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001315/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001316 * moved forward since the last typed character. Return value:
1317 * whether we wrapped. */
1318int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001319{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001320 size_t len = strlen(inptr->data); /* length of the line we wrap */
1321 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001322 int wrap_loc = -1; /* index of inptr->data where we wrap */
1323 int word_back = -1;
1324#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001325 const char *indentation = NULL;
1326 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001327 int indent_len = 0; /* strlen(indentation) */
1328#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001329 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001330 int after_break_len; /* strlen(after_break) */
1331 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001332 const char *wrap_line = NULL;
1333 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001334 int wrap_line_len = 0; /* strlen(wrap_line) */
1335 char *newline = NULL; /* the line we create */
1336 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001337
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001338/* There are three steps. First, we decide where to wrap. Then, we
1339 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001340
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001341/* Step 1, finding where to wrap. We are going to add a new-line
1342 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001343 * location of this replacement.
1344 *
1345 * Where should we break the line? We need the last "legal wrap point"
1346 * such that the last word before it ended at or before fill. If there
1347 * is no such point, we settle for the first legal wrap point.
1348 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001349 * A "legal wrap point" is a white-space character that is not followed by
1350 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001351 *
1352 * If there is no legal wrap point or we found the last character of the
1353 * line, we should return without wrapping.
1354 *
1355 * Note that the initial indentation does not count as a legal wrap
1356 * point if we are going to auto-indent!
1357 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001358 * Note that the code below could be optimised, by not calling strnlenpt()
1359 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001360
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001361#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001362 if (ISSET(AUTOINDENT))
1363 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001364#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001365 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001366 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001367 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001368 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001369 word_back = i;
1370 /* if we have found a "legal wrap point" and the current word
1371 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001372 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001373 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001374 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001375 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001376 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001377 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001378 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001379 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001380
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001381/* Step 2, making the new wrap line. It will consist of indentation +
1382 * after_break + " " + wrap_line (although indentation and wrap_line are
1383 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001384
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001385 /* after_break is the text that will be moved to the next line. */
1386 after_break = inptr->data + wrap_loc + 1;
1387 after_break_len = len - wrap_loc - 1;
1388 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001389
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001390 /* new_line_len will later be increased by the lengths of indentation
1391 * and wrap_line. */
1392 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001393
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394 /* We prepend the wrapped text to the next line, if the flag is set,
1395 * and there is a next line, and prepending would not make the line
1396 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001397 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001398 wrap_line = inptr->next->data;
1399 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001400
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001401 /* +1 for the space between after_break and wrap_line */
1402 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1403 wrapping = 1;
1404 new_line_len += (1 + wrap_line_len);
1405 }
1406 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001407
Chris Allegrettaff989832001-09-17 13:48:00 +00001408#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001409 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001410 /* Indentation comes from the next line if wrapping, else from
1411 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001412 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001413 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001414 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001415 /* The wrap_line text should not duplicate indentation.
1416 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001417 wrap_line += indent_len;
1418 else
1419 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001420 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001421#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001422
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001423 /* Now we allocate the new line and copy into it. */
1424 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1425 *newline = '\0';
1426
1427#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001428 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001429 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001430 newline[indent_len] = '\0';
1431 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001432#endif
1433 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001434 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001435 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001436 null_at(&inptr->data, wrap_loc + 1);
1437 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001438 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001439 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001440 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001441 * in a tab or a space, we don't add a space and decrement
1442 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001443 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001444 strcat(newline, " ");
1445 else
1446 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001447 strcat(newline, wrap_line);
1448 free(inptr->next->data);
1449 inptr->next->data = newline;
1450 } else {
1451 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001452
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001453 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001454 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001455#ifndef NANO_SMALL
1456 totsize += indent_len;
1457#endif
1458 totlines++;
1459 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001460 temp->prev = inptr;
1461 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001462 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001463 /* If temp->next is NULL, then temp is the last line of the
1464 * file, so we must set filebot. */
1465 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001466 temp->next->prev = temp;
1467 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001468 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001469 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001470
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001471/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1472 * other sundry things. */
1473
1474 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001475 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001476
1477 /* Each line knows its line number. We recalculate these if we
1478 * inserted a new line. */
1479 if (!wrapping)
1480 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001481
Chris Allegretta6df90f52002-07-19 01:08:59 +00001482 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001483 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001484 current = current->next;
1485 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001486#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001487 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001488#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001489 wrap_loc + 1;
1490 wrap_reset();
1491 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001492 }
1493
Chris Allegretta6df90f52002-07-19 01:08:59 +00001494#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001495 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001496 * If it was on the next line and we wrapped, we must move it
1497 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001498 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1499 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001500 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001501 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001502 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001503#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001504
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001505 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001506 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001507
1508 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001509}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001510#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001511
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001512#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001513/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001514 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001515int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001516{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001517 char *save_search;
1518 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001519 filestruct *current_save = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001520 size_t current_x_save = current_x;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001521 filestruct *edittop_save = edittop;
1522 /* Save where we are. */
1523 int i = 0;
1524 /* The return value. */
1525 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001526#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001527 int case_sens_set = ISSET(CASE_SENSITIVE);
1528 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001529
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001530 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001531 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001532 UNSET(MARK_ISSET);
1533#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001534 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001535 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001536
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001537 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001538 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001539 save_search = last_search;
1540 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001541
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001542 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001543 last_search = mallocstrcpy(NULL, word);
1544 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001545
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001546 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001547 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001548 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001549
1550 search_last_line = FALSE;
1551
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001552 /* Find the first whole-word occurrence of word. */
1553 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001554 if (is_whole_word(current_x, current->data, word)) {
1555 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001556
Chris Allegretta6df90f52002-07-19 01:08:59 +00001557 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001558
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001559 /* Allow the replace word to be corrected. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001560 i = statusq(0, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001561#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001562 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001563#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001564 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001565
Chris Allegretta6df90f52002-07-19 01:08:59 +00001566 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001567
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001568 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001569 search_last_line = FALSE;
1570 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001571 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001572 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001573
1574 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001575 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001576
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001577 /* Restore the search/replace strings. */
1578 free(last_search);
1579 last_search = save_search;
1580 free(last_replace);
1581 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001582
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001583 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001584 current = current_save;
1585 current_x = current_x_save;
1586 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001587
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001588 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001589 if (reverse_search_set)
1590 SET(REVERSE_SEARCH);
1591
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001592#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001593 if (!case_sens_set)
1594 UNSET(CASE_SENSITIVE);
1595
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001596 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001597 if (mark_set)
1598 SET(MARK_ISSET);
1599#endif
1600
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001601 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001602}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001603
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001604/* Integrated spell checking using 'spell' program. Return value: NULL
1605 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001606char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001607{
Chris Allegretta271e9722000-11-10 18:15:43 +00001608 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001609 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001610 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001611 pid_t pid_spell, pid_sort, pid_uniq;
1612 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001613
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001614 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001615 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1616 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001617
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001618 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001619
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001620 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001621 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001622
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001623 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001624
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001625 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001626
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001627 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001628 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1629 goto close_pipes_and_exit;
1630
1631 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1632 goto close_pipes_and_exit;
1633
Chris Allegretta271e9722000-11-10 18:15:43 +00001634 close(tempfile_fd);
1635
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001636 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001637 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1638 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001639
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001640 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001641
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001642 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001643 execlp("spell", "spell", NULL);
1644
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001645 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001646 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001647 }
1648
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001649 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001650 close(spell_fd[1]);
1651
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001652 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001653 if ((pid_sort = fork()) == 0) {
1654
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001655 /* Child continues (i.e, future spell process). Replace the
1656 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001657 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1658 goto close_pipes_and_exit;
1659
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001660 close(spell_fd[0]);
1661
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001662 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001663 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1664 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001665
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001666 close(sort_fd[1]);
1667
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001668 /* Start sort program. Use -f to remove mixed case without
1669 * having to have ANOTHER pipe for tr. If this isn't portable,
1670 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001671 execlp("sort", "sort", "-f", NULL);
1672
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001673 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001674 exit(1);
1675 }
1676
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001677 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001678 close(sort_fd[1]);
1679
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001680 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001681 if ((pid_uniq = fork()) == 0) {
1682
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001683 /* Child continues (i.e, future uniq process). Replace the
1684 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001685 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1686 goto close_pipes_and_exit;
1687
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001688 close(sort_fd[0]);
1689
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001690 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001691 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1692 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001693
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001694 close(uniq_fd[1]);
1695
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001696 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001697 execlp("uniq", "uniq", NULL);
1698
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001699 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001700 exit(1);
1701 }
1702
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001703 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001704 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001705
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001706 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001707 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1708 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001709 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001710 }
1711
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001712 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001713 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1714 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001715 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001716 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001717
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001718 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001719 read_buff_read = 0;
1720 read_buff_size = pipe_buff_size + 1;
1721 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001722
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001723 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001724 read_buff_read += bytesread;
1725 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001726 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001727 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001728
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001729 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001730
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001731 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001732 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001733
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001734 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001735 read_buff_word = read_buff_ptr = read_buff;
1736
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001737 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001738
1739 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001740 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001741 if (read_buff_word != read_buff_ptr) {
1742 if (!do_int_spell_fix(read_buff_word)) {
1743 read_buff_word = read_buff_ptr;
1744 break;
1745 }
1746 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001747 read_buff_word = read_buff_ptr + 1;
1748 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001749 read_buff_ptr++;
1750 }
1751
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001752 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001753 if (read_buff_word != read_buff_ptr)
1754 do_int_spell_fix(read_buff_word);
1755
Chris Allegretta271e9722000-11-10 18:15:43 +00001756 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001757 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001758 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001759
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001760 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001761 waitpid(pid_spell, &spell_status, 0);
1762 waitpid(pid_sort, &sort_status, 0);
1763 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001764
Chris Allegretta334a9402002-12-16 04:25:53 +00001765 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1766 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001767
Chris Allegretta334a9402002-12-16 04:25:53 +00001768 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1769 return _("Error invoking \"sort -f\"");
1770
1771 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1772 return _("Error invoking \"uniq\"");
1773
1774 /* Otherwise... */
1775 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001776
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001777 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001778
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001779 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001780 close(tempfile_fd);
1781 close(spell_fd[0]);
1782 close(spell_fd[1]);
1783 close(sort_fd[0]);
1784 close(sort_fd[1]);
1785 close(uniq_fd[0]);
1786 close(uniq_fd[1]);
1787 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001788}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001789
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001790/* External spell checking. Return value: NULL for normal termination,
1791 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001792char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001793{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001794 int alt_spell_status, lineno_cur = current->lineno;
1795 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001796 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001797 char *ptr;
1798 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001799 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001800#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001801 int mark_set = ISSET(MARK_ISSET);
1802 int mbb_lineno_cur = 0;
1803 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001804 * the alternate spell command. The line that mark_beginbuf
1805 * points to will be freed, so we save the line number and
1806 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001807
1808 if (mark_set) {
1809 mbb_lineno_cur = mark_beginbuf->lineno;
1810 UNSET(MARK_ISSET);
1811 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001812#endif
1813
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001814 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001815
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001816 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001817 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001818 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001819
Chris Allegrettae434b452001-01-27 19:25:00 +00001820 spellargs[0] = strtok(alt_speller, " ");
1821 while ((ptr = strtok(NULL, " ")) != NULL) {
1822 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001823 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001824 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001825 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001826 spellargs[arglen - 1] = NULL;
1827 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001828 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001829
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001830 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001831 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001832 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001833 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001834
1835 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001836 exit(1);
1837 }
1838
1839 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001840 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001841 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001842
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001843 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001844 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001845
Chris Allegretta334a9402002-12-16 04:25:53 +00001846 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1847 char *altspell_error = NULL;
1848 char *invoke_error = _("Could not invoke \"%s\"");
1849 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1850
1851 altspell_error = charalloc(msglen);
1852 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1853 return altspell_error;
1854 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001855
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001856 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001857#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001858 if (!mark_set) {
1859 /* Only reload the temp file if it isn't a marked selection. */
1860#endif
1861 free_filestruct(fileage);
1862 global_init(1);
1863 open_file(tempfile_name, 0, 1);
1864#ifndef NANO_SMALL
1865 }
1866
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001867 if (mark_set) {
1868 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1869 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001870 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001871 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001872 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001873 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001874#endif
1875
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001876 /* Go back to the old position, mark the file as modified, and make
1877 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001878 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001879 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001880 clearok(topwin, FALSE);
1881 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001882
Chris Allegretta334a9402002-12-16 04:25:53 +00001883 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001884}
1885#endif
1886
1887int do_spell(void)
1888{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001889#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001890 nano_disabled_msg();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001891 return 1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001892#else
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001893 int i;
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001894 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001895
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001896 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001897 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001898 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001899 return 0;
1900 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001901
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001902#ifndef NANO_SMALL
1903 if (ISSET(MARK_ISSET))
1904 i = write_marked(temp, 1, 0, 0);
1905 else
1906#endif
1907 i = write_file(temp, 1, 0, 0);
1908
1909 if (i == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001910 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001911 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001912 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001913 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001914
Chris Allegrettae1f14522001-09-19 03:19:43 +00001915#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001916 /* Update the current open_files entry before spell-checking, in
1917 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001918 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001919#endif
1920
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001921 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001922 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001923 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001924 spell_msg = do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001925 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001926 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001927
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001928 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001929 statusbar(_("Spell checking failed: %s"), spell_msg);
1930 return 0;
1931 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001932
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001933 statusbar(_("Finished checking spelling"));
1934 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001935#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001936}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001937
Chris Allegrettad865da12002-07-29 23:46:38 +00001938#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001939/* The "indentation" of a line is the white-space between the quote part
1940 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001941size_t indent_length(const char *line)
1942{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001943 size_t len = 0;
1944
1945 assert(line != NULL);
1946 while (*line == ' ' || *line == '\t') {
1947 line++;
1948 len++;
1949 }
1950 return len;
1951}
Chris Allegrettadffa2072002-07-24 01:02:26 +00001952#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001953
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001954#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00001955/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
1956 * it maintains 2 after a . ! or ?). Note the terminating \0
1957 * counts as a space.
1958 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001959 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001960 * returns 1, otherwise returns 0.
1961 *
1962 * If changes_allowed, justify_format() might make line->data
1963 * shorter, and change the actual pointer with null_at().
1964 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001965 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001966 * skip should be at most strlen(line->data). The skip+1st character must
1967 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001968int justify_format(int changes_allowed, filestruct *line, size_t skip)
1969{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001970 const char *punct = ".?!";
1971 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001972 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001973
Chris Allegretta6df90f52002-07-19 01:08:59 +00001974 /* These four asserts are assumptions about the input data. */
1975 assert(line != NULL);
1976 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001977 assert(skip < strlen(line->data));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001978 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001979
Chris Allegretta6df90f52002-07-19 01:08:59 +00001980 back = line->data + skip;
1981 front = back;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001982 for (front = back; ; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001983 int remove_space = 0;
1984 /* Do we want to remove this space? */
1985
Chris Allegretta6df90f52002-07-19 01:08:59 +00001986 if (*front == '\t') {
1987 if (!changes_allowed)
1988 return 1;
1989 *front = ' ';
1990 }
1991 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001992 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001993 const char *bob = front - 2;
1994
1995 remove_space = 1;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001996 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001997 if (strchr(punct, *bob) != NULL) {
1998 remove_space = 0;
1999 break;
2000 }
2001 if (strchr(brackets, *bob) == NULL)
2002 break;
2003 }
2004 }
2005
2006 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002007 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002008 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002009 if (!changes_allowed)
2010 return 1;
2011#ifndef NANO_SMALL
2012 if (mark_beginbuf == line && back - line->data < mark_beginx)
2013 mark_beginx--;
2014#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002015 if (*front == '\0')
2016 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002017 } else {
2018 *back = *front;
2019 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002020 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002021 if (*front == '\0')
2022 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002023 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002024
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002025 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00002026 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00002027
2028 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002029 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002030
2031 /* Now back is the new end of line->data. */
2032 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00002033 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002034 null_at(&line->data, back - line->data);
2035#ifndef NANO_SMALL
2036 if (mark_beginbuf == line && back - line->data < mark_beginx)
2037 mark_beginx = back - line->data;
2038#endif
2039 }
2040 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002041}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002042
2043/* The "quote part" of a line is the largest initial substring matching
2044 * the quote string. This function returns the length of the quote part
2045 * of the given line.
2046 *
2047 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2048 * quotestr. */
2049#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002050size_t quote_length(const char *line, const regex_t *qreg)
2051{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002052 regmatch_t matches;
2053 int rc = regexec(qreg, line, 1, &matches, 0);
2054
2055 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2056 return 0;
2057 /* matches.rm_so should be 0, since the quote string should start with
2058 * the caret ^. */
2059 return matches.rm_eo;
2060}
2061#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002062size_t quote_length(const char *line)
2063{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002064 size_t qdepth = 0;
2065 size_t qlen = strlen(quotestr);
2066
2067 /* Compute quote depth level */
2068 while (!strcmp(line + qdepth, quotestr))
2069 qdepth += qlen;
2070 return qdepth;
2071}
2072#endif /* !HAVE_REGEX_H */
2073
Chris Allegretta6df90f52002-07-19 01:08:59 +00002074/* a_line and b_line are lines of text. The quotation part of a_line is
2075 * the first a_quote characters. Check that the quotation part of
2076 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002077int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002078 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002079{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002080 /* Here is the assumption about a_quote: */
2081 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002082 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002083 !strncmp(a_line, b_line, a_quote);
2084}
2085
2086/* We assume a_line and b_line have no quote part. Then, we return whether
2087 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002088size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002089 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002090{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002091 assert(a_indent == indent_length(a_line));
2092 assert(b_indent == indent_length(b_line));
2093
2094 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2095}
2096
2097/* Put the next par_len lines, starting with first_line, in the cut
2098 * buffer. We assume there are enough lines after first_line. We leave
2099 * copies of the lines in place, too. We return the new copy of
2100 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002101filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002102 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002103{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002104 /* We put the original lines, not copies, into the cut buffer, just
2105 * out of a misguided sense of consistency, so if you un-cut, you
2106 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002107 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002108
2109 set_modified();
2110 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002111 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002112 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002113
Chris Allegretta908f7702003-01-15 11:18:58 +00002114 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002115 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002116 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002117 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002118 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002119 edittop = bob;
2120#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002121 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002122 mark_beginbuf = bob;
2123#endif
2124 justify_format(1, bob,
2125 quote_len + indent_length(bob->data + quote_len));
2126
Chris Allegretta908f7702003-01-15 11:18:58 +00002127 assert(alice != NULL && bob != NULL);
2128 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002129 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002130 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002131 }
2132 return first_line;
2133}
2134
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002135/* Is it possible to break line at or before goal? */
2136int breakable(const char *line, int goal)
2137{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002138 for (; *line != '\0' && goal >= 0; line++) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002139 if (*line == ' ' || *line == '\t')
2140 return TRUE;
2141
2142 if (is_cntrl_char(*line) != 0)
2143 goal -= 2;
2144 else
2145 goal -= 1;
2146 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002147 /* If goal is not negative, the whole line (one word) was short
2148 * enough. */
2149 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002150}
2151
Chris Allegretta6df90f52002-07-19 01:08:59 +00002152/* We are trying to break a chunk off line. We find the last space such
2153 * that the display length to there is at most goal + 1. If there is
2154 * no such space, and force is not 0, then we find the first space.
2155 * Anyway, we then take the last space in that group of spaces. The
2156 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002157int break_line(const char *line, int goal, int force)
2158{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002159 /* Note that we use int instead of size_t, since goal is at most COLS,
2160 * the screen width, which will always be reasonably small. */
2161 int space_loc = -1;
2162 /* Current tentative return value. Index of the last space we
2163 * found with short enough display width. */
2164 int cur_loc = 0;
2165 /* Current index in line */
2166
2167 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002168 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002169 if (*line == ' ')
2170 space_loc = cur_loc;
2171 assert(*line != '\t');
2172
Chris Allegrettacf287c82002-07-20 13:57:41 +00002173 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002174 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002175 else
2176 goal--;
2177 }
2178 if (goal >= 0)
2179 /* In fact, the whole line displays shorter than goal. */
2180 return cur_loc;
2181 if (space_loc == -1) {
2182 /* No space found short enough. */
2183 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002184 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002185 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002186 return cur_loc;
2187 return -1;
2188 }
2189 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002190 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002191 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2192 *(line - cur_loc + space_loc + 1) == '\0')
2193 space_loc++;
2194 return space_loc;
2195}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002196
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002197/* Search a paragraph. If search_type is 0, search for the beginning of
2198 * the current paragraph or, if we're at the end of it, the beginning of
2199 * the next paragraph. If search_type is 1, search for the beginning of
2200 * the current paragraph or, if we're already there, the beginning of
2201 * the previous paragraph. If search_type is 2, search for the end of
2202 * the current paragraph or, if we're already there, the end of the next
2203 * paragraph. Afterwards, save the quote length, paragraph length, and
2204 * indentation length in *quote, *par, and *indent if they aren't NULL,
2205 * and refresh the screen if do_refresh is nonzero. Return 0 if we
2206 * found a paragraph, or 1 if there was an error or we didn't find a
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002207 * paragraph.
2208 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002209 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002210 * phrases about paragraphs and quotation:
2211 * A line of text consists of a "quote part", followed by an
2212 * "indentation part", followed by text. The functions quote_length()
2213 * and indent_length() calculate these parts.
2214 *
2215 * A line is "part of a paragraph" if it has a part not in the quote
2216 * part or the indentation.
2217 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002218 * A line is "the beginning of a paragraph" if it is part of a
2219 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002220 * 1) it is the top line of the file, or
2221 * 2) the line above it is not part of a paragraph, or
2222 * 3) the line above it does not have precisely the same quote
2223 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002224 * 4) the indentation of this line is not an initial substring of
2225 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002226 * 5) this line has no quote part and some indentation, and
2227 * AUTOINDENT is not set.
2228 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002229 * indented line is expected to start a paragraph, like in books.
2230 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2231 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002232 *
2233 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002234 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002235 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002236int do_para_search(int search_type, size_t *quote, size_t *par, size_t
2237 *indent, int do_refresh)
2238{
2239 size_t quote_len;
2240 /* Length of the initial quotation of the paragraph we
2241 * search. */
2242 size_t par_len;
2243 /* Number of lines in that paragraph. */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002244
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002245 /* We save this global variable to see if we're where we started
2246 * when searching for the beginning of the paragraph. */
2247 filestruct *current_save = current;
2248
2249 size_t indent_len; /* Generic indentation length. */
2250 filestruct *line; /* Generic line of text. */
2251
2252 static int do_restart = 1;
2253 /* Whether we're restarting when searching for the beginning
2254 * line of the paragraph. */
2255
2256#ifdef HAVE_REGEX_H
2257 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2258 * longer care about quotestr. */
2259 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2260
2261 if (rc != 0) {
2262 size_t size = regerror(rc, &qreg, NULL, 0);
2263 char *strerror = charalloc(size);
2264
2265 regerror(rc, &qreg, strerror, size);
2266 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2267 free(strerror);
2268 return 1;
2269 }
2270#endif
2271
2272 /* Here is an assumption that is always true anyway. */
2273 assert(current != NULL);
2274
2275 current_x = 0;
2276
2277 restart_para_search:
2278/* Here we find the first line of the paragraph to search. If the
2279 * current line is in a paragraph, then we move back to the first line.
2280 * Otherwise we move to the first line that is in a paragraph. */
2281 quote_len = quote_length(IFREG(current->data, &qreg));
2282 indent_len = indent_length(current->data + quote_len);
2283
2284 if (current->data[quote_len + indent_len] != '\0') {
2285 /* This line is part of a paragraph. So we must search back to
2286 * the first line of this paragraph. First we check items 1)
2287 * and 3) above. */
2288 while (current->prev != NULL && quotes_match(current->data,
2289 quote_len, IFREG(current->prev->data, &qreg))) {
2290 size_t temp_id_len =
2291 indent_length(current->prev->data + quote_len);
2292 /* The indentation length of the previous line. */
2293
2294 /* Is this line the beginning of a paragraph, according to
2295 * items 2), 5), or 4) above? If so, stop. */
2296 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2297 (quote_len == 0 && indent_len > 0
2298#ifndef NANO_SMALL
2299 && !ISSET(AUTOINDENT)
2300#endif
2301 ) ||
2302 !indents_match(current->prev->data + quote_len,
2303 temp_id_len, current->data + quote_len, indent_len))
2304 break;
2305 indent_len = temp_id_len;
2306 current = current->prev;
2307 current_y--;
2308 }
2309 } else if (search_type == 1) {
2310 /* This line is not part of a paragraph. Move up until we get
2311 * to a non "blank" line, and then move down once. */
2312 do {
2313 /* There is no previous paragraph, so nothing to move to. */
2314 if (current->prev == NULL) {
2315 placewewant = 0;
2316 if (do_refresh) {
2317 if (current_y < 0)
2318 edit_update(current, CENTER);
2319 else
2320 edit_refresh();
2321 }
2322#ifdef HAVE_REGEX_H
2323 if (!do_restart)
2324 regfree(&qreg);
2325#endif
2326 return 1;
2327 }
2328 current = current->prev;
2329 current_y--;
2330 quote_len = quote_length(IFREG(current->data, &qreg));
2331 indent_len = indent_length(current->data + quote_len);
2332 } while (current->data[quote_len + indent_len] == '\0');
2333 current = current->next;
2334 } else {
2335 /* This line is not part of a paragraph. Move down until we get
2336 * to a non "blank" line. */
2337 do {
2338 /* There is no next paragraph, so nothing to move to. */
2339 if (current->next == NULL) {
2340 placewewant = 0;
2341 if (do_refresh)
2342 edit_refresh();
2343#ifdef HAVE_REGEX_H
2344 regfree(&qreg);
2345#endif
2346 return 1;
2347 }
2348 current = current->next;
2349 current_y++;
2350 quote_len = quote_length(IFREG(current->data, &qreg));
2351 indent_len = indent_length(current->data + quote_len);
2352 } while (current->data[quote_len + indent_len] == '\0');
2353 }
2354
2355/* Now current is the first line of the paragraph, and quote_len is the
2356 * quotation length of that line. */
2357
2358/* Next step, compute par_len, the number of lines in this paragraph. */
2359 line = current;
2360 par_len = 1;
2361 indent_len = indent_length(line->data + quote_len);
2362
2363 while (line->next != NULL && quotes_match(current->data, quote_len,
2364 IFREG(line->next->data, &qreg))) {
2365 size_t temp_id_len = indent_length(line->next->data + quote_len);
2366
2367 if (!indents_match(line->data + quote_len, indent_len,
2368 line->next->data + quote_len, temp_id_len) ||
2369 line->next->data[quote_len + temp_id_len] == '\0' ||
2370 (quote_len == 0 && temp_id_len > 0
2371#ifndef NANO_SMALL
2372 && !ISSET(AUTOINDENT)
2373#endif
2374 ))
2375 break;
2376 indent_len = temp_id_len;
2377 line = line->next;
2378 par_len++;
2379 }
2380
2381 if (search_type == 1) {
2382 /* We're on the same line we started on. Move up until we get
2383 * to a non-"blank" line, restart the search from there until we
2384 * find a line that's part of a paragraph, and search once more
2385 * so that we end up at the beginning of that paragraph. */
2386 if (current != fileage && current == current_save && do_restart) {
2387 while (current->prev != NULL) {
2388 size_t i, j = 0;
2389 current = current->prev;
2390 current_y--;
2391 /* Skip over lines consisting only of spacing
2392 * characters, as searching for the end of the paragraph
2393 * does. */
2394 for (i = 0; current->data[i] != '\0'; i++) {
2395 if (isspace(current->data[i]))
2396 j++;
2397 else {
2398 i = 0;
2399 j = 1;
2400 break;
2401 }
2402 }
2403 if (i != j && strlen(current->data) >=
2404 (quote_len + indent_len) &&
2405 current->data[quote_len + indent_len] != '\0') {
2406 do_restart = 0;
2407 break;
2408 }
2409 }
2410 goto restart_para_search;
2411 } else
2412 do_restart = 1;
2413 }
2414
2415#ifdef HAVE_REGEX_H
2416 /* We no longer need to check quotation. */
2417 regfree(&qreg);
2418#endif
2419
2420/* Now par_len is the number of lines in this paragraph. We should
2421 * never call quotes_match() or quote_length() again. */
2422
2423 /* If we're searching for the end of the paragraph, move down the
2424 * number of lines in the paragraph. */
2425 if (search_type == 2) {
2426 for (; par_len > 0; current_y++, par_len--)
2427 current = current->next;
2428 }
2429
2430 /* Refresh the screen if needed. */
2431 if (do_refresh) {
2432 if (((search_type == 0 || search_type == 2) && current_y >
2433 editwinrows - 1) || (search_type == 1 && current_y < 0))
2434 edit_update(current, CENTER);
2435 else
2436 edit_refresh();
2437 }
2438
2439 /* Save the values of quote_len, par_len, and indent_len if
2440 * needed. */
2441 if (quote != NULL)
2442 *quote = quote_len;
2443 if (par != NULL)
2444 *par = par_len;
2445 if (indent != NULL)
2446 *indent = indent_len;
2447
2448 return 0;
2449}
2450
2451int do_para_begin(void)
2452{
2453 return do_para_search(1, NULL, NULL, NULL, TRUE);
2454}
2455
2456int do_para_end(void)
2457{
2458 return do_para_search(2, NULL, NULL, NULL, TRUE);
2459}
2460#endif
2461
2462/* Justify a paragraph. */
2463int do_justify(void)
2464{
2465#ifdef DISABLE_JUSTIFY
2466 nano_disabled_msg();
2467 return 1;
2468#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002469 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002470 /* Length of the initial quotation of the paragraph we
2471 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002472 size_t par_len;
2473 /* Number of lines in that paragraph. */
2474 filestruct *first_mod_line = NULL;
2475 /* Will be the first line of the resulting justified paragraph
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002476 * that differs from the original. For restoring after
2477 * uncut. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002478 filestruct *last_par_line = current;
2479 /* Will be the last line of the result, also for uncut. */
2480 filestruct *cutbuffer_save = cutbuffer;
2481 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002482 * one down are stored in the cut buffer. We back up the
2483 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002484
2485 /* We save these global variables to be restored if the user
2486 * unjustifies. Note we don't need to save totlines. */
2487 int current_x_save = current_x;
2488 int current_y_save = current_y;
2489 filestruct *current_save = current;
2490 int flags_save = flags;
2491 long totsize_save = totsize;
2492 filestruct *edittop_save = edittop;
2493 filestruct *editbot_save = editbot;
2494#ifndef NANO_SMALL
2495 filestruct *mark_beginbuf_save = mark_beginbuf;
2496 int mark_beginx_save = mark_beginx;
2497#endif
2498
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002499 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002500 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002501
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002502 /* First, search for the beginning of the current paragraph or, if
2503 * we're at the end of it, the beginning of the next paragraph.
2504 * Save the quote length, paragraph length, and indentation length
2505 * and don't refresh the screen yet (since we'll do that after we
2506 * justify). If the search failed, refresh the screen and get
2507 * out. */
2508 if (do_para_search(0, &quote_len, &par_len, &indent_len, FALSE) != 0) {
2509 edit_refresh();
2510 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002511 }
2512
Chris Allegretta6df90f52002-07-19 01:08:59 +00002513/* Next step, we loop through the lines of this paragraph, justifying
2514 * each one individually. */
Chris Allegretta8151ba52003-04-19 19:34:05 +00002515 SET(JUSTIFY_MODE);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002516 for (; par_len > 0; current_y++, par_len--) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002517 size_t line_len;
2518 size_t display_len;
2519 /* The width of current in screen columns. */
2520 int break_pos;
2521 /* Where we will break the line. */
2522
2523 indent_len = indent_length(current->data + quote_len) +
2524 quote_len;
2525 /* justify_format() removes excess spaces from the line, and
2526 * changes tabs to spaces. The first argument, 0, means don't
2527 * change the line, just say whether there are changes to be
2528 * made. If there are, we do backup_lines(), which copies the
2529 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002530 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002531 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002532 first_mod_line = backup_lines(current, par_len, quote_len);
2533
2534 line_len = strlen(current->data);
2535 display_len = strlenpt(current->data);
2536
2537 if (display_len > fill) {
2538 /* The line is too long. Try to wrap it to the next. */
2539 break_pos = break_line(current->data + indent_len,
2540 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002541 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002542 if (break_pos == -1 || break_pos + indent_len == line_len)
2543 /* We can't break the line, or don't need to, so just go
2544 * on to the next. */
2545 goto continue_loc;
2546 break_pos += indent_len;
2547 assert(break_pos < line_len);
2548 /* If we haven't backed up the paragraph, do it now. */
2549 if (first_mod_line == NULL)
2550 first_mod_line = backup_lines(current, par_len, quote_len);
2551 if (par_len == 1) {
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002552 /* There is no next line in this paragraph. We make a
2553 * new line and copy text after break_pos into it. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002554 splice_node(current, make_new_node(current),
2555 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002556 /* In a non-quoted paragraph, we copy the indent only if
2557 AUTOINDENT is turned on. */
2558 if (quote_len == 0)
2559#ifndef NANO_SMALL
2560 if (!ISSET(AUTOINDENT))
2561#endif
2562 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002563 current->next->data = charalloc(indent_len + line_len -
2564 break_pos);
2565 strncpy(current->next->data, current->data,
2566 indent_len);
2567 strcpy(current->next->data + indent_len,
2568 current->data + break_pos + 1);
2569 assert(strlen(current->next->data) ==
2570 indent_len + line_len - break_pos - 1);
2571 totlines++;
2572 totsize += indent_len;
2573 par_len++;
2574 } else {
2575 size_t next_line_len = strlen(current->next->data);
2576
2577 indent_len = quote_len +
2578 indent_length(current->next->data + quote_len);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002579 current->next->data = charealloc(current->next->data,
2580 next_line_len + line_len - break_pos + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002581
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002582 charmove(current->next->data + indent_len + line_len - break_pos,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002583 current->next->data + indent_len,
2584 next_line_len - indent_len + 1);
2585 strcpy(current->next->data + indent_len,
2586 current->data + break_pos + 1);
2587 current->next->data[indent_len + line_len - break_pos - 1]
2588 = ' ';
2589#ifndef NANO_SMALL
2590 if (mark_beginbuf == current->next) {
2591 if (mark_beginx < indent_len)
2592 mark_beginx = indent_len;
2593 mark_beginx += line_len - break_pos;
2594 }
2595#endif
2596 }
2597#ifndef NANO_SMALL
2598 if (mark_beginbuf == current && mark_beginx > break_pos) {
2599 mark_beginbuf = current->next;
2600 mark_beginx -= break_pos + 1 - indent_len;
2601 }
2602#endif
2603 null_at(&current->data, break_pos);
2604 current = current->next;
2605 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002606 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002607
2608 indent_len = quote_len +
2609 indent_length(current->next->data + quote_len);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002610 /* If we can't pull a word from the next line up to this
2611 * one, just go on. */
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002612 if (!breakable(current->next->data + indent_len,
2613 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002614 goto continue_loc;
2615
2616 /* If we haven't backed up the paragraph, do it now. */
2617 if (first_mod_line == NULL)
2618 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002619
2620 break_pos = break_line(current->next->data + indent_len,
2621 fill - display_len - 1, FALSE);
2622 assert(break_pos != -1);
2623
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002624 current->data = charealloc(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002625 line_len + break_pos + 2);
2626 current->data[line_len] = ' ';
2627 strncpy(current->data + line_len + 1,
2628 current->next->data + indent_len, break_pos);
2629 current->data[line_len + break_pos + 1] = '\0';
2630#ifndef NANO_SMALL
2631 if (mark_beginbuf == current->next) {
2632 if (mark_beginx < indent_len + break_pos) {
2633 mark_beginbuf = current;
2634 if (mark_beginx <= indent_len)
2635 mark_beginx = line_len + 1;
2636 else
2637 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2638 } else
2639 mark_beginx -= break_pos + 1;
2640 }
2641#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002642 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002643 if (indent_len + break_pos == next_line_len) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002644 filestruct *line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002645
2646 /* Don't destroy edittop! */
2647 if (line == edittop)
2648 edittop = current;
2649
Chris Allegretta6df90f52002-07-19 01:08:59 +00002650 unlink_node(line);
2651 delete_node(line);
2652 totlines--;
2653 totsize -= indent_len;
2654 current_y--;
2655 } else {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002656 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002657 current->next->data + indent_len + break_pos + 1,
2658 next_line_len - break_pos - indent_len);
2659 null_at(&current->next->data,
2660 next_line_len - break_pos);
2661 current = current->next;
2662 }
2663 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002664 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002665 current = current->next;
2666 }
Chris Allegretta8151ba52003-04-19 19:34:05 +00002667 UNSET(JUSTIFY_MODE);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002668
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002669/* We are now done justifying the paragraph. There are cleanup things
2670 * to do, and we check for unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671
2672 /* totlines, totsize, and current_y have been maintained above. We
2673 * now set last_par_line to the new end of the paragraph, update
2674 * fileage, set current_x. Also, edit_refresh() needs the line
2675 * numbers to be right, so we renumber(). */
2676 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002677 if (first_mod_line != NULL) {
2678 if (first_mod_line->prev == NULL)
2679 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002680 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002681 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002682
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002683 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002684 edit_update(current, CENTER);
2685 else
2686 edit_refresh();
2687
Chris Allegretta9149e612000-11-27 00:23:41 +00002688 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002689 /* Change the shortcut list to display the unjustify code. */
Chris Allegretta07798352000-11-27 22:58:23 +00002690 shortcut_init(1);
2691 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002692 reset_cursor();
2693
Chris Allegretta6df90f52002-07-19 01:08:59 +00002694 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002695 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002696
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002697 {
2698 int meta;
2699 i = get_kbinput(edit, &meta);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002700#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002701 /* If it was a mouse click, parse it with do_mouse() and it
2702 * might become the unjustify key. Else give it back to the
2703 * input stream. */
2704 if (i == KEY_MOUSE)
2705 do_mouse();
2706 else
2707 ungetch(i);
2708 i = get_kbinput(edit, &meta);
Chris Allegretta5f071802001-05-06 02:34:31 +00002709#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002710 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002711
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002712 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002713 ungetch(i);
2714 /* Did we back up anything at all? */
2715 if (cutbuffer != cutbuffer_save)
2716 free_filestruct(cutbuffer);
2717 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002718 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002719 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002720 current = current_save;
2721 current_x = current_x_save;
2722 current_y = current_y_save;
2723 edittop = edittop_save;
2724 editbot = editbot_save;
2725 if (first_mod_line != NULL) {
2726 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002727
Chris Allegretta6df90f52002-07-19 01:08:59 +00002728 /* Splice the cutbuffer back into the file. */
2729 cutbottom->next = last_par_line->next;
2730 cutbottom->next->prev = cutbottom;
2731 /* The line numbers after the end of the paragraph have
2732 * been changed, so we change them back. */
2733 renumber(cutbottom->next);
2734 if (first_mod_line->prev != NULL) {
2735 cutbuffer->prev = first_mod_line->prev;
2736 cutbuffer->prev->next = cutbuffer;
2737 } else
2738 fileage = cutbuffer;
2739 cutbuffer = NULL;
2740
2741 last_par_line->next = NULL;
2742 free_filestruct(first_mod_line);
2743
2744 /* Restore global variables from before justify */
2745 totsize = totsize_save;
2746 totlines = filebot->lineno;
2747#ifndef NANO_SMALL
2748 mark_beginbuf = mark_beginbuf_save;
2749 mark_beginx = mark_beginx_save;
2750#endif
2751 flags = flags_save;
2752 if (!ISSET(MODIFIED)) {
2753 titlebar(NULL);
2754 wrefresh(topwin);
2755 }
2756 }
2757 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002758 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002759 cutbuffer = cutbuffer_save;
2760 blank_statusbar_refresh();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002761 /* display shortcut list with UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002762 shortcut_init(0);
2763 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002764
Chris Allegretta6df90f52002-07-19 01:08:59 +00002765 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002766#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002767}
2768
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002769int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002770{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002771 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002772
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002773 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002774
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002775#ifdef ENABLE_MULTIBUFFER
2776 if (!close_open_file()) {
2777 display_main_list();
2778 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002779 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002780 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002781#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002782 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002783 }
2784
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002785 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002786 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002787 else
2788 i = do_yesno(0, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2789
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002790#ifdef DEBUG
2791 dump_buffer(fileage);
2792#endif
2793
2794 if (i == 1) {
2795 if (do_writeout(filename, 1, 0) > 0) {
2796
2797#ifdef ENABLE_MULTIBUFFER
2798 if (!close_open_file()) {
2799 display_main_list();
2800 return 1;
2801 }
2802 else
2803#endif
2804 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002805 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002806 } else if (i == 0) {
2807
2808#ifdef ENABLE_MULTIBUFFER
2809 if (!close_open_file()) {
2810 display_main_list();
2811 return 1;
2812 }
2813 else
2814#endif
2815 finish(0);
2816 } else
2817 statusbar(_("Cancelled"));
2818
2819 display_main_list();
2820 return 1;
2821}
2822
2823void signal_init(void)
2824{
2825#ifdef _POSIX_VDISABLE
2826 struct termios term;
2827#endif
2828
2829 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2830 memset(&act, 0, sizeof(struct sigaction));
2831 act.sa_handler = SIG_IGN;
2832 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002833 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002834
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002835 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2836 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002837 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002838 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002839
2840#ifndef NANO_SMALL
2841 act.sa_handler = handle_sigwinch;
2842 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002843 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002844#endif
2845
2846#ifdef _POSIX_VDISABLE
2847 tcgetattr(0, &term);
2848
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002849 if (!ISSET(PRESERVE)) {
2850 /* Ignore ^S and ^Q, much to Chris' chagrin */
2851 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2852 term.c_cc[VSTART] = _POSIX_VDISABLE;
2853 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002854#ifdef VDSUSP
2855 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2856#endif /* VDSUSP */
2857
2858#endif /* _POSIX_VDISABLE */
2859
2860 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002861 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002862#ifdef _POSIX_VDISABLE
2863 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2864#else
2865 act.sa_handler = SIG_IGN;
2866 sigaction(SIGTSTP, &act, NULL);
2867#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002868 } else {
2869 /* If we don't do this, it seems other stuff interrupts the
2870 suspend handler! Try using nano with mutt without this
2871 line. */
2872 sigfillset(&act.sa_mask);
2873
2874 act.sa_handler = do_suspend;
2875 sigaction(SIGTSTP, &act, NULL);
2876
2877 act.sa_handler = do_cont;
2878 sigaction(SIGCONT, &act, NULL);
2879 }
2880
2881#ifdef _POSIX_VDISABLE
2882 tcsetattr(0, TCSANOW, &term);
2883#endif
2884}
2885
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002886/* Handler for SIGHUP and SIGTERM */
2887RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002888{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002889 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002890}
2891
2892/* What do we do when we catch the suspend signal */
2893RETSIGTYPE do_suspend(int signal)
2894{
2895 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002896 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002897 fflush(stdout);
2898
2899 /* Restore the terminal settings for the disabled keys */
2900 tcsetattr(0, TCSANOW, &oldterm);
2901
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002902 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
2903 suspended */
2904 act.sa_handler = handle_hupterm;
2905 sigaction(SIGHUP, &act, NULL);
2906 sigaction(SIGTERM, &act, NULL);
2907
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002908 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002909 then we could be (and were) interrupted in the middle of the call.
2910 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002911 kill(0, SIGSTOP);
2912}
2913
2914/* Restore the suspend handler when we come back into the prog */
2915RETSIGTYPE do_cont(int signal)
2916{
2917 /* Now we just update the screen instead of having to reenable the
2918 SIGTSTP handler. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002919 doupdate();
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002920
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002921 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
David Lawrence Ramseya593f532003-11-28 19:47:42 +00002922 start suspending again. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002923 signal_init();
2924
2925#ifndef NANO_SMALL
2926 /* Perhaps the user resized the window while we slept. */
2927 handle_sigwinch(0);
2928#endif
2929}
2930
2931#ifndef NANO_SMALL
2932void handle_sigwinch(int s)
2933{
2934 const char *tty = ttyname(0);
2935 int fd;
2936 int result = 0;
2937 struct winsize win;
2938
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002939 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002940 return;
2941 fd = open(tty, O_RDWR);
2942 if (fd == -1)
2943 return;
2944 result = ioctl(fd, TIOCGWINSZ, &win);
2945 close(fd);
2946 if (result == -1)
2947 return;
2948
2949 /* Could check whether the COLS or LINES changed, and return
2950 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2951 * variables, and in some cases ncurses has already updated them.
2952 * But not in all cases, argh. */
2953 COLS = win.ws_col;
2954 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002955 editwinrows = LINES - 5 + no_help();
2956 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002957 die_too_small();
2958
2959#ifndef DISABLE_WRAPJUSTIFY
2960 fill = wrap_at;
2961 if (fill <= 0)
2962 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002963 if (fill < 0)
2964 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002965#endif
2966
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002967 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002968 memset(hblank, ' ', COLS);
2969 hblank[COLS] = '\0';
2970
2971#ifdef HAVE_RESIZETERM
2972 resizeterm(LINES, COLS);
2973#ifdef HAVE_WRESIZE
2974 if (wresize(topwin, 2, COLS) == ERR)
2975 die(_("Cannot resize top win"));
2976 if (mvwin(topwin, 0, 0) == ERR)
2977 die(_("Cannot move top win"));
2978 if (wresize(edit, editwinrows, COLS) == ERR)
2979 die(_("Cannot resize edit win"));
2980 if (mvwin(edit, 2, 0) == ERR)
2981 die(_("Cannot move edit win"));
2982 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2983 die(_("Cannot resize bottom win"));
2984 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2985 die(_("Cannot move bottom win"));
2986#endif /* HAVE_WRESIZE */
2987#endif /* HAVE_RESIZETERM */
2988
2989 fix_editbot();
2990
2991 if (current_y > editwinrows - 1)
2992 edit_update(editbot, CENTER);
2993 erase();
2994
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002995 /* Do these because width may have changed. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002996 refresh();
2997 titlebar(NULL);
2998 edit_refresh();
2999 display_main_list();
3000 blank_statusbar();
3001 total_refresh();
3002
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003003 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003004 curs_set(1);
3005
David Lawrence Ramsey53809442004-01-30 04:29:52 +00003006 /* Turn the keypad on and switch to cbreak mode, so that the keypad
3007 * and input still work if we resized during verbatim input. */
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003008 keypad(edit, TRUE);
3009 keypad(bottomwin, TRUE);
David Lawrence Ramsey53809442004-01-30 04:29:52 +00003010#ifdef _POSIX_VDISABLE
3011 cbreak();
3012#endif
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003013
3014 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003015 siglongjmp(jmpbuf, 1);
3016}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003017
3018void allow_pending_sigwinch(int allow)
3019{
3020 sigset_t winch;
3021 sigemptyset(&winch);
3022 sigaddset(&winch, SIGWINCH);
3023 if (allow)
3024 sigprocmask(SIG_UNBLOCK, &winch, NULL);
3025 else
3026 sigprocmask(SIG_BLOCK, &winch, NULL);
3027}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003028#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003029
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003030/* If the NumLock key has made the keypad go awry, print an error
3031 message; hopefully we can address it later. */
3032void print_numlock_warning(void)
3033{
3034 static int didmsg = 0;
3035 if (!didmsg) {
3036 statusbar(_
3037 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
3038 didmsg = 1;
3039 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003040}
3041
Chris Allegrettadab017e2002-04-23 10:56:06 +00003042#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00003043void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00003044{
Chris Allegretta6df90f52002-07-19 01:08:59 +00003045 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00003046
Chris Allegretta658399a2001-06-14 02:54:22 +00003047 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003048 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00003049
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003050 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00003051 case TOGGLE_SUSPEND_KEY:
3052 signal_init();
3053 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003054#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003055 case TOGGLE_MOUSE_KEY:
3056 mouse_init();
3057 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003058#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003059 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00003060 wclear(bottomwin);
3061 wrefresh(bottomwin);
3062 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00003063 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00003064 edit_refresh();
3065 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00003066 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00003067 case TOGGLE_DOS_KEY:
3068 UNSET(MAC_FILE);
3069 break;
3070 case TOGGLE_MAC_KEY:
3071 UNSET(DOS_FILE);
3072 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003073#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003074 case TOGGLE_SYNTAX_KEY:
3075 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003076 break;
3077#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003078 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003079
Chris Allegretta6df90f52002-07-19 01:08:59 +00003080 /* We are assuming here that shortcut_init() above didn't free and
3081 * reallocate the toggles. */
3082 enabled = ISSET(which->flag);
3083 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3084 enabled = !enabled;
3085 statusbar("%s %s", which->desc,
3086 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003087}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003088#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003089
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003090int main(int argc, char *argv[])
3091{
3092 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003093 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003094 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003095 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003096 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003097 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003098 int kbinput; /* Input from keyboard */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003099 int meta;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003100
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003101#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003102 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003103#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003104#ifdef _POSIX_VDISABLE
3105 struct termios term;
3106#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003107#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003108 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003109 {"help", 0, 0, 'h'},
3110#ifdef ENABLE_MULTIBUFFER
3111 {"multibuffer", 0, 0, 'F'},
3112#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003113#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003114#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003115 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003116#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003117 {"ignorercfiles", 0, 0, 'I'},
3118#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003119#ifndef DISABLE_JUSTIFY
3120 {"quotestr", 1, 0, 'Q'},
3121#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003122#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003123 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003124#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003125 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003126 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003127#ifdef ENABLE_COLOR
3128 {"syntax", 1, 0, 'Y'},
3129#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003130 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003131 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003132 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003133#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003134 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003135#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003136#ifndef DISABLE_OPERATINGDIR
3137 {"operatingdir", 1, 0, 'o'},
3138#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003139 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003140#ifndef DISABLE_WRAPJUSTIFY
3141 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003142#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003143#ifndef DISABLE_SPELLER
3144 {"speller", 1, 0, 's'},
3145#endif
3146 {"tempfile", 0, 0, 't'},
3147 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003148#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003149 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003150#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003151 {"nohelp", 0, 0, 'x'},
3152 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003153#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003154 {"backup", 0, 0, 'B'},
3155 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003156 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003157 {"mac", 0, 0, 'M'},
3158 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003159 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003160 {"autoindent", 0, 0, 'i'},
3161 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003162#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003163 {0, 0, 0, 0}
3164 };
3165#endif
3166
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003167#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003168 setlocale(LC_ALL, "");
3169 bindtextdomain(PACKAGE, LOCALEDIR);
3170 textdomain(PACKAGE);
3171#endif
3172
Chris Allegretta7662c862003-01-13 01:35:15 +00003173#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003174 /* if we don't have rcfile support, we're root, and
3175 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003176 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003177 SET(NO_WRAP);
3178#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003179
3180#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003181 while ((optchr = getopt_long(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003182 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003183#else
3184 while ((optchr =
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003185 getopt(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003186#endif
3187
3188 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003189
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003190 case 'a':
3191 case 'b':
3192 case 'e':
3193 case 'f':
3194 case 'g':
3195 case 'j':
3196 /* Pico compatibility flags */
3197 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003198#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003199 case 'B':
3200 SET(BACKUP_FILE);
3201 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003202 case 'D':
3203 SET(DOS_FILE);
3204 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003205 case 'E':
3206 backup_dir = mallocstrcpy(backup_dir, optarg);
3207 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003208#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003209#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003210 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003211 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003212 break;
3213#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003214#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003215#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003216 case 'H':
3217 SET(HISTORYLOG);
3218 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003219#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003220 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003221 SET(NO_RCFILE);
3222 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003223#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003224#ifndef NANO_SMALL
3225 case 'M':
3226 SET(MAC_FILE);
3227 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003228 case 'N':
3229 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003230 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003231#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003232#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003233 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003234 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003235 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003236#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003237#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003238 case 'R':
3239 SET(USE_REGEXP);
3240 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003241#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003242#ifndef NANO_SMALL
3243 case 'S':
3244 SET(SMOOTHSCROLL);
3245 break;
3246#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003247 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003248 {
3249 int i;
3250 char *first_error;
3251
Chris Allegretta7662c862003-01-13 01:35:15 +00003252 /* Using strtol() instead of atoi() lets us accept 0
3253 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003254 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003255 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003256 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003257 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003258 tabsize = i;
3259 if (tabsize <= 0) {
3260 fprintf(stderr, _("Tab size is too small for nano...\n"));
3261 exit(1);
3262 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003263 }
3264 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003265 case 'V':
3266 version();
3267 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003268#ifdef ENABLE_COLOR
3269 case 'Y':
3270 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3271 break;
3272#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003273 case 'c':
3274 SET(CONSTUPDATE);
3275 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003276 case 'd':
3277 SET(REBIND_DELETE);
3278 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003279#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003280 case 'i':
3281 SET(AUTOINDENT);
3282 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003283 case 'k':
3284 SET(CUT_TO_END);
3285 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003286#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003287 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003288 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003289 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003290#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003291 case 'm':
3292 SET(USE_MOUSE);
3293 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003294#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003295#ifndef DISABLE_OPERATINGDIR
3296 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003297 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003298 break;
3299#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003300 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003301 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003302 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003303#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003304 case 'r':
3305 {
3306 int i;
3307 char *first_error;
3308
Chris Allegretta7662c862003-01-13 01:35:15 +00003309 /* Using strtol() instead of atoi() lets us accept 0
3310 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003311 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003312 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003313 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003314 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003315 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003316 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003317 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003318 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003319#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003320#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003321 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003322 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003323 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003324#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003325 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003326 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003327 break;
3328 case 'v':
3329 SET(VIEW_MODE);
3330 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003331#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003332 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003333 SET(NO_WRAP);
3334 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003335#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003336 case 'x':
3337 SET(NO_HELP);
3338 break;
3339 case 'z':
3340 SET(SUSPEND);
3341 break;
3342 default:
3343 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003344 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003345 }
3346
Chris Allegretta7662c862003-01-13 01:35:15 +00003347/* We've read through the command line options. Now back up the flags
3348 and values that are set, and read the rcfile(s). If the values
3349 haven't changed afterward, restore the backed-up values. */
3350#ifdef ENABLE_NANORC
3351 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003352#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003353 char *operating_dir_cpy = operating_dir;
3354#endif
3355#ifndef DISABLE_WRAPPING
3356 int wrap_at_cpy = wrap_at;
3357#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003358#ifndef NANO_SMALL
3359 char *backup_dir_cpy = backup_dir;
3360#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003361#ifndef DISABLE_JUSTIFY
3362 char *quotestr_cpy = quotestr;
3363#endif
3364#ifndef DISABLE_SPELLER
3365 char *alt_speller_cpy = alt_speller;
3366#endif
3367 int tabsize_cpy = tabsize;
3368 long flags_cpy = flags;
3369
Chris Allegretta5ec68622003-02-05 02:39:34 +00003370#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003371 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003372#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003373#ifndef NANO_SMALL
3374 backup_dir = NULL;
3375#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003376#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003377 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003378#endif
3379#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003380 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003381#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003382
3383 do_rcfile();
3384
3385#ifndef DISABLE_OPERATINGDIR
3386 if (operating_dir_cpy != NULL) {
3387 free(operating_dir);
3388 operating_dir = operating_dir_cpy;
3389 }
3390#endif
3391#ifndef DISABLE_WRAPPING
3392 if (fill_flag_used)
3393 wrap_at = wrap_at_cpy;
3394#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003395#ifndef NANO_SMALL
3396 if (backup_dir_cpy != NULL) {
3397 free(backup_dir);
3398 backup_dir = backup_dir_cpy;
3399 }
3400#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003401#ifndef DISABLE_JUSTIFY
3402 if (quotestr_cpy != NULL) {
3403 free(quotestr);
3404 quotestr = quotestr_cpy;
3405 }
3406#endif
3407#ifndef DISABLE_SPELLER
3408 if (alt_speller_cpy != NULL) {
3409 free(alt_speller);
3410 alt_speller = alt_speller_cpy;
3411 }
3412#endif
3413 if (tabsize_cpy > 0)
3414 tabsize = tabsize_cpy;
3415 flags |= flags_cpy;
3416 }
3417#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003418 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003419 SET(NO_WRAP);
3420#endif
3421#endif /* ENABLE_NANORC */
3422
Chris Allegrettad8451932003-03-11 03:50:40 +00003423#ifndef NANO_SMALL
3424 history_init();
3425#ifdef ENABLE_NANORC
3426 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3427 load_history();
3428#endif
3429#endif
3430
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003431#ifndef NANO_SMALL
3432 /* Set up the backup directory. This entails making sure it exists
3433 * and is a directory, so that backup files will be saved there. */
3434 init_backup_dir();
3435#endif
3436
Chris Allegretta7662c862003-01-13 01:35:15 +00003437#ifndef DISABLE_OPERATINGDIR
3438 /* Set up the operating directory. This entails chdir()ing there,
3439 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003440 init_operating_dir();
3441#endif
3442
Chris Allegretta7662c862003-01-13 01:35:15 +00003443#ifndef DISABLE_JUSTIFY
3444 if (quotestr == NULL)
3445#ifdef HAVE_REGEX_H
3446 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3447#else
3448 quotestr = mallocstrcpy(NULL, "> ");
3449#endif
3450#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003451
Chris Allegretta7662c862003-01-13 01:35:15 +00003452 if (tabsize == -1)
3453 tabsize = 8;
3454
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003455 /* Clear the filename we'll be using */
3456 filename = charalloc(1);
3457 filename[0] = '\0';
3458
Chris Allegretta7662c862003-01-13 01:35:15 +00003459 /* If there's a +LINE flag, it is the first non-option argument. */
3460 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3461 startline = atoi(&argv[optind][1]);
3462 optind++;
3463 }
3464 if (0 < optind && optind < argc)
3465 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003466
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003467 /* See if there's a non-option in argv (first non-option is the
3468 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003469 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003470 /* Look for the +line flag... */
3471 if (argv[optind][0] == '+') {
3472 startline = atoi(&argv[optind][1]);
3473 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003474 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003475 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003476 } else
3477 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003478 }
3479
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003480 /* Termios initialization stuff: Back up the old settings so that
3481 * they can be restored, disable SIGINT on ^C and SIGQUIT on ^\,
3482 * since we need them for Cancel and Replace, and disable
3483 * implementation-defined input processing. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003484 tcgetattr(0, &oldterm);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003485#ifdef _POSIX_VDISABLE
3486 term = oldterm;
3487 term.c_cc[VINTR] = _POSIX_VDISABLE;
3488 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3489 term.c_lflag &= ~IEXTEN;
3490 tcsetattr(0, TCSANOW, &term);
3491#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003492
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003493 /* Curses initialization stuff: Start curses, save the state of the
3494 * the terminal mode, disable translation of carriage return (^M)
3495 * into newline (^J) so we can catch the Enter key and use ^J for
3496 * Justify, turn the keypad on for the windows that read input, put
3497 * the terminal in cbreak mode (read one character at a time and
3498 * interpret the special control keys) if we can selectively disable
3499 * the special control keys or raw mode (read one character at a
3500 * time and don't interpret the special control keys) if we
3501 * can't, and turn off echoing of characters as they're typed. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003502 initscr();
3503 savetty();
3504 nonl();
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003505 keypad(edit, TRUE);
3506 keypad(bottomwin, TRUE);
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003507#ifdef _POSIX_VDISABLE
3508 cbreak();
3509#else
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003510 raw();
3511#endif
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003512 noecho();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003513
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003514 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003515 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003516 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003517
3518 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003519 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003520
3521#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003522 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003523#endif
3524
Chris Allegretta2a42af12000-09-12 23:02:49 +00003525 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003526#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003527 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003528#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003529
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003530#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003531 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003532#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003533 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003534 display_main_list();
3535
3536#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003537 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003538#endif
3539
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003540 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003541#ifdef ENABLE_MULTIBUFFER
3542 /* If we're using multibuffers and more than one file is specified
3543 on the command line, load them all and switch to the first one
3544 afterward */
3545 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3546 for (optind++; optind < argc; optind++) {
3547 add_open_file(1);
3548 new_file();
3549 filename = mallocstrcpy(filename, argv[optind]);
3550 open_file(filename, 0, 0);
3551 load_file(0);
3552 }
3553 open_nextfile_void();
3554 }
3555#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003556
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003557 titlebar(NULL);
3558
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003559 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003560 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003561
Chris Allegretta7662c862003-01-13 01:35:15 +00003562 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003563 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003564
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003565 /* SHUT UP GCC! */
3566 startline = 0;
3567 fill_flag_used = 0;
3568 keyhandled = 0;
3569
Chris Allegretta7662c862003-01-13 01:35:15 +00003570 /* This variable should be initialized after the sigsetjmp(), so we
3571 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003572 modify_control_seq = 0;
3573
Robert Siemborski6967eec2000-07-08 14:23:32 +00003574 edit_refresh();
3575 reset_cursor();
3576
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003577 while (1) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003578 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003579
Chris Allegrettad26ab912003-01-28 01:16:47 +00003580 if (ISSET(CONSTUPDATE))
3581 do_cursorpos(1);
3582
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003583#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003584 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003585#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003586
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003587 kbinput = get_kbinput(edit, &meta);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003588#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003589 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003590#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003591 if (meta == 1) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003592 /* Check for the metaval and misc defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003593 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003594 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
3595 (s->misc != NANO_NO_KEY && kbinput == s->misc)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003596 if (ISSET(VIEW_MODE) && !s->viewok)
3597 print_view_warning();
3598 else {
3599 if (s->func != do_cut_text)
3600 UNSET(KEEP_CUTBUFFER);
3601 s->func();
3602 }
3603 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003604 }
3605#ifndef NANO_SMALL
3606 if (!keyhandled)
3607 /* And for toggle switches */
3608 for (t = toggles; t != NULL; t = t->next)
3609 if (kbinput == t->val) {
3610 UNSET(KEEP_CUTBUFFER);
3611 do_toggle(t);
3612 keyhandled = 1;
3613 }
3614#endif
3615#ifdef DEBUG
3616 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3617 kbinput);
3618#endif
3619 }
3620
3621 /* Look through the main shortcut list to see if we've hit a
3622 shortcut key or function key */
3623
3624 if (!keyhandled)
3625#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3626 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3627#else
3628 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3629#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003630 if ((s->val != NANO_NO_KEY && kbinput == s->val) ||
3631 (s->func_key != NANO_NO_KEY && kbinput == s->func_key)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003632 if (ISSET(VIEW_MODE) && !s->viewok)
3633 print_view_warning();
3634 else {
3635 if (s->func != do_cut_text)
3636 UNSET(KEEP_CUTBUFFER);
3637 s->func();
3638 }
3639 keyhandled = 1;
3640 /* Break out explicitly once we successfully handle
3641 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003642 break;
3643 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003644 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003645
3646 if (!keyhandled)
3647 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003648
3649#ifdef _POSIX_VDISABLE
3650 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003651 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003652 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003653 if (kbinput == NANO_CONTROL_S)
3654 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003655#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003656 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3657 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003658 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003659 keyhandled = 1;
3660
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003661 /* Catch ^Z by hand when triggered also */
3662 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003663 if (ISSET(SUSPEND))
3664 do_suspend(0);
3665 keyhandled = 1;
3666 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003667
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003668 /* Last gasp, stuff that's not in the main lists */
3669 if (!keyhandled)
3670 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003671#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003672 case KEY_MOUSE:
3673 do_mouse();
3674 break;
3675#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003676
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003677 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3678 * have been handled before we
3679 * got here */
3680 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003681 break;
3682 default:
3683#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003684 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003685#endif
3686 /* We no longer stop unhandled sequences so that people with
3687 odd character sets can type... */
3688
Chris Allegretta7662c862003-01-13 01:35:15 +00003689 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003690 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003691 else
3692 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003693 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003694
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003695 reset_cursor();
3696 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003697 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003698 assert(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003699}