blob: 4a11b1b4077dc801b132e81e64830778d22dc283 [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
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000128 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000129 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;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000205 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000206 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000207 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000208
Chris Allegretta6fe61492001-05-21 12:56:25 +0000209#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000210 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000211 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000212 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000213 if (fill < 0)
214 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000215#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000216
Chris Allegretta88b09152001-05-17 11:35:43 +0000217 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000218 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000219 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000220}
221
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000222void window_init(void)
223{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000224 editwinrows = LINES - 5 + no_help();
225 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000226 die_too_small();
227
Chris Allegretta1a128af2003-01-26 04:15:56 +0000228 if (topwin != NULL)
229 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000230 if (edit != NULL)
231 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000232 if (bottomwin != NULL)
233 delwin(bottomwin);
234
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000235 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000236 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000237 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000238 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
239
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000240 /* Turn the keypad on in the windows we'll be reading input from. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000241 keypad(edit, TRUE);
242 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000243}
244
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000245#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246void mouse_init(void)
247{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249 mousemask(BUTTON1_RELEASED, NULL);
250 mouseinterval(50);
251 } else
252 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000253}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000254#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255
256#ifndef DISABLE_HELP
257/* This function allocates help_text, and stores the help string in it.
258 * help_text should be NULL initially. */
259void help_init(void)
260{
Chris Allegretta908f7702003-01-15 11:18:58 +0000261 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000262 char *ptr = NULL;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000263 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000264#ifndef NANO_SMALL
265 const toggle *t;
266#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000267
268 /* First set up the initial help text for the current function */
269 if (currshortcut == whereis_list || currshortcut == replace_list
270 || currshortcut == replace_list_2)
271 ptr = _("Search Command Help Text\n\n "
272 "Enter the words or characters you would like to search "
273 "for, then hit enter. If there is a match for the text you "
274 "entered, the screen will be updated to the location of the "
275 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000276 "The previous search string will be shown in brackets after "
277 "the Search: prompt. Hitting Enter without entering any text "
278 "will perform the previous search.\n\n The following function "
279 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000280 else if (currshortcut == goto_list)
281 ptr = _("Go To Line Help Text\n\n "
282 "Enter the line number that you wish to go to and hit "
283 "Enter. If there are fewer lines of text than the "
284 "number you entered, you will be brought to the last line "
285 "of the file.\n\n The following function keys are "
286 "available in Go To Line mode:\n\n");
287 else if (currshortcut == insertfile_list)
288 ptr = _("Insert File Help Text\n\n "
289 "Type in the name of a file to be inserted into the current "
290 "file buffer at the current cursor location.\n\n "
291 "If you have compiled nano with multiple file buffer "
292 "support, and enable multiple buffers with the -F "
293 "or --multibuffer command line flags, the Meta-F toggle, or "
294 "a nanorc file, inserting a file will cause it to be "
295 "loaded into a separate buffer (use Meta-< and > to switch "
296 "between file buffers).\n\n If you need another blank "
297 "buffer, do not enter any filename, or type in a "
298 "nonexistent filename at the prompt and press "
299 "Enter.\n\n The following function keys are "
300 "available in Insert File mode:\n\n");
301 else if (currshortcut == writefile_list)
302 ptr = _("Write File Help Text\n\n "
303 "Type the name that you wish to save the current file "
304 "as and hit Enter to save the file.\n\n If you have "
305 "selected text with Ctrl-^, you will be prompted to "
306 "save only the selected portion to a separate file. To "
307 "reduce the chance of overwriting the current file with "
308 "just a portion of it, the current filename is not the "
309 "default in this mode.\n\n The following function keys "
310 "are available in Write File mode:\n\n");
311#ifndef DISABLE_BROWSER
312 else if (currshortcut == browser_list)
313 ptr = _("File Browser Help Text\n\n "
314 "The file browser is used to visually browse the "
315 "directory structure to select a file for reading "
316 "or writing. You may use the arrow keys or Page Up/"
317 "Down to browse through the files, and S or Enter to "
318 "choose the selected file or enter the selected "
319 "directory. To move up one level, select the directory "
320 "called \"..\" at the top of the file list.\n\n The "
321 "following function keys are available in the file "
322 "browser:\n\n");
323 else if (currshortcut == gotodir_list)
324 ptr = _("Browser Go To Directory Help Text\n\n "
325 "Enter the name of the directory you would like to "
326 "browse to.\n\n If tab completion has not been disabled, "
327 "you can use the TAB key to (attempt to) automatically "
328 "complete the directory name.\n\n The following function "
329 "keys are available in Browser Go To Directory mode:\n\n");
330#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000331#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000332 else if (currshortcut == spell_list)
333 ptr = _("Spell Check Help Text\n\n "
334 "The spell checker checks the spelling of all text "
335 "in the current file. When an unknown word is "
336 "encountered, it is highlighted and a replacement can "
337 "be edited. It will then prompt to replace every "
338 "instance of the given misspelled word in the "
339 "current file.\n\n The following other functions are "
340 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000341#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000342#ifndef NANO_SMALL
343 else if (currshortcut == extcmd_list)
344 ptr = _("External Command Help Text\n\n "
345 "This menu allows you to insert the output of a command "
346 "run by the shell into the current buffer (or a new "
347 "buffer in multibuffer mode).\n\n The following keys are "
348 "available in this mode:\n\n");
349#endif
350 else /* Default to the main help list */
351 ptr = _(" nano help text\n\n "
352 "The nano editor is designed to emulate the functionality and "
353 "ease-of-use of the UW Pico text editor. There are four main "
354 "sections of the editor: The top line shows the program "
355 "version, the current filename being edited, and whether "
356 "or not the file has been modified. Next is the main editor "
357 "window showing the file being edited. The status line is "
358 "the third line from the bottom and shows important messages. "
359 "The bottom two lines show the most commonly used shortcuts "
360 "in the editor.\n\n "
361 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000362 "sequences are notated with a caret (^) symbol and can be "
363 "entered either by using the Control (Ctrl) key or pressing the "
364 "Esc key twice. Escape-key sequences are notated with the Meta "
365 "(M) symbol and can be entered using either the Esc, Alt or "
366 "Meta key depending on your keyboard setup. Also, pressing Esc "
367 "twice and then typing a three-digit number from 000 to 255 "
368 "will enter the character with the corresponding ASCII code. "
369 "The following keystrokes are available in the main editor "
370 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000371
Chris Allegretta908f7702003-01-15 11:18:58 +0000372 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000373
374 /* The space needed for the shortcut lists, at most COLS characters,
375 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000376 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000377
378#ifndef NANO_SMALL
379 /* If we're on the main list, we also count the toggle help text.
380 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
381 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000382 if (currshortcut == main_list) {
383 size_t endislen = strlen(_("enable/disable"));
384
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000385 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000386 allocsize += 8 + strlen(t->desc) + endislen;
387 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000388#endif /* !NANO_SMALL */
389
390 /* help_text has been freed and set to NULL unless the user resized
391 * while in the help screen. */
392 free(help_text);
393
394 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000395 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000396
397 /* Now add the text we want */
398 strcpy(help_text, ptr);
399 ptr = help_text + strlen(help_text);
400
401 /* Now add our shortcut info */
402 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000403 /* true if the character in s->metaval is shown in first column */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000404 int meta_shortcut = 0;
405
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000406 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000407#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000408 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000409 ptr += sprintf(ptr, "%.2s", _("Up"));
410 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000411#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000412 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000413 ptr += sprintf(ptr, "^%.5s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000414 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000415 ptr += sprintf(ptr, "^?");
416 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000417 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000418 }
419#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000420 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000421 meta_shortcut = 1;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000422 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000423 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
424 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000425 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000426 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000427#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000428
429 *(ptr++) = '\t';
430
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000431 if (s->funcval != NANO_NO_KEY)
432 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000433
434 *(ptr++) = '\t';
435
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000436 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
437 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000438 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
439 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000440
441 *(ptr++) = '\t';
442
443 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000444 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000445 }
446
447#ifndef NANO_SMALL
448 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000449 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000450 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000451 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000452 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000453 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000454 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000455 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000456#endif /* !NANO_SMALL */
457
458 /* If all went well, we didn't overwrite the allocated space for
459 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000460 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000461}
462#endif
463
464/* Create a new filestruct node. Note that we specifically do not set
465 * prevnode->next equal to the new line. */
466filestruct *make_new_node(filestruct *prevnode)
467{
468 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
469
470 newnode->data = NULL;
471 newnode->prev = prevnode;
472 newnode->next = NULL;
473 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
474
475 return newnode;
476}
477
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000478/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000479filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000480{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000481 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000482
Chris Allegretta6df90f52002-07-19 01:08:59 +0000483 assert(src != NULL);
484
Chris Allegretta88b09152001-05-17 11:35:43 +0000485 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000486 dst->next = src->next;
487 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000488 strcpy(dst->data, src->data);
489 dst->lineno = src->lineno;
490
491 return dst;
492}
493
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000494/* Splice a node into an existing filestruct. */
495void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
496{
497 if (newnode != NULL) {
498 newnode->next = end;
499 newnode->prev = begin;
500 }
501 if (begin != NULL)
502 begin->next = newnode;
503 if (end != NULL)
504 end->prev = newnode;
505}
506
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000507/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000508void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000509{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000510 assert(fileptr != NULL);
511
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000512 if (fileptr->prev != NULL)
513 fileptr->prev->next = fileptr->next;
514
515 if (fileptr->next != NULL)
516 fileptr->next->prev = fileptr->prev;
517}
518
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000519/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000520void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000521{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522 if (fileptr != NULL) {
523 if (fileptr->data != NULL)
524 free(fileptr->data);
525 free(fileptr);
526 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000527}
528
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000529/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000531{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000532 filestruct *head; /* copy of src, top of the copied list */
533 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000534
Chris Allegretta6df90f52002-07-19 01:08:59 +0000535 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000536
Chris Allegretta6df90f52002-07-19 01:08:59 +0000537 prev = copy_node(src);
538 prev->prev = NULL;
539 head = prev;
540 src = src->next;
541 while (src != NULL) {
542 prev->next = copy_node(src);
543 prev->next->prev = prev;
544 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000545
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547 }
548
Chris Allegretta6df90f52002-07-19 01:08:59 +0000549 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000550 return head;
551}
552
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000553/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000554void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000555{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000556 if (src != NULL) {
557 while (src->next != NULL) {
558 src = src->next;
559 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000560#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000561 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000562#endif
563 }
564 delete_node(src);
565#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000566 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000567#endif
568 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000569}
570
Chris Allegretta6df90f52002-07-19 01:08:59 +0000571void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000572{
573 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000574 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000575
Chris Allegretta6df90f52002-07-19 01:08:59 +0000576 assert(fileage == NULL || fileage != fileage->next);
577 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000578 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000579}
580
Chris Allegretta6df90f52002-07-19 01:08:59 +0000581void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000582{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000583 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000584 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000585 else {
586 int lineno = fileptr->prev->lineno;
587
588 assert(fileptr != fileptr->next);
589 for (; fileptr != NULL; fileptr = fileptr->next)
590 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000591 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000592}
593
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000594/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000595 * strings to translate and takes out the parts that shouldn't be
596 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000597void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000598 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000599{
600 printf(" %s\t", shortflag);
601 if (strlen(shortflag) < 8)
602 printf("\t");
603
604#ifdef HAVE_GETOPT_LONG
605 printf("%s\t", longflag);
606 if (strlen(longflag) < 8)
607 printf("\t\t");
608 else if (strlen(longflag) < 16)
609 printf("\t");
610#endif
611
612 printf("%s\n", desc);
613}
614
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000615void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000616{
617#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000618 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
619 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000620#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000621 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
622 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000623#endif /* HAVE_GETOPT_LONG */
624
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000625 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000626 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000627#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000628 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000629 print1opt("-D", "--dos", _("Write file in DOS format"));
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +0000630 print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000631#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000632#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000633 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000634#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000635#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000636#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000637 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000638#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000639 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
640#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000641#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000642 print1opt("-M", "--mac", _("Write file in Mac format"));
643 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000644#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000645#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000646 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000647#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000648#ifdef HAVE_REGEX_H
649 print1opt("-R", "--regexp", _("Do regular expression searches"));
650#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000651#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000652 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000653#endif
David Lawrence Ramseya7c93642004-02-25 03:19:29 +0000654 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), _("Set width of a tab in cols to #cols"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000655 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000656#ifdef ENABLE_COLOR
657 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
658#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000659 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000660#ifndef NANO_SMALL
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000661 print1opt("-d", "--rebinddelete", _("Fix Backspace/Delete confusion problem"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000662 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
663 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000664#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000665 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000666#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000667 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000668#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000669#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000670 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000671#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000672 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000673#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000674 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000675#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000676#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000677 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000678#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000679 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
680 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000681#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000682 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000683#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000684 print1opt("-x", "--nohelp", _("Don't show help window"));
685 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000686
687 /* this is a special case */
688 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000689
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000690 exit(0);
691}
692
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000693void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000694{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000695 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000696 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000697 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000698 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000699 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000700
Chris Allegrettae6600372003-01-17 03:39:41 +0000701#ifndef ENABLE_NLS
702 printf(" --disable-nls");
703#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000704#ifdef DEBUG
705 printf(" --enable-debug");
706#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000707#ifdef NANO_EXTRA
708 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000709#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000710#ifdef NANO_SMALL
711 printf(" --enable-tiny");
712#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000713#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000714 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000715#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000716#ifdef DISABLE_HELP
717 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000718#endif
719#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000720 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000721#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000722#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000723 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000724#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000725#ifdef DISABLE_OPERATINGDIR
726 printf(" --disable-operatingdir");
727#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000728#ifdef DISABLE_SPELLER
729 printf(" --disable-speller");
730#endif
731#ifdef DISABLE_TABCOMP
732 printf(" --disable-tabcomp");
733#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000734#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000735#ifdef DISABLE_WRAPPING
736 printf(" --disable-wrapping");
737#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000738#ifdef DISABLE_ROOTWRAP
739 printf(" --disable-wrapping-as-root");
740#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000741#ifdef ENABLE_COLOR
742 printf(" --enable-color");
743#endif
744#ifdef ENABLE_MULTIBUFFER
745 printf(" --enable-multibuffer");
746#endif
747#ifdef ENABLE_NANORC
748 printf(" --enable-nanorc");
749#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000750#ifdef USE_SLANG
751 printf(" --with-slang");
752#endif
753 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000754}
755
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000756/* Stuff we do when we abort from programs and want to clean up the
757 * screen. This doesn't do much right now. */
758void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000759{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000760 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000761}
762
763int no_help(void)
764{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000765 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000766}
767
Chris Allegrettad865da12002-07-29 23:46:38 +0000768#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000769void nano_disabled_msg(void)
770{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000771 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000772}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000773#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000774
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000775#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000776static int pid; /* This is the PID of the newly forked process
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000777 * below. It must be global since the signal
778 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000779RETSIGTYPE cancel_fork(int signal)
780{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000781 if (kill(pid, SIGKILL) == -1)
782 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000783}
784
785int open_pipe(const char *command)
786{
787 int fd[2];
788 FILE *f;
789 struct sigaction oldaction, newaction;
790 /* original and temporary handlers for SIGINT */
791#ifdef _POSIX_VDISABLE
792 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000793#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000794 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000795 /* cancel_sigs == 1 means that sigaction() failed without changing
796 * the signal handlers. cancel_sigs == 2 means the signal handler
797 * was changed, but the tcsetattr didn't succeed.
798 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000799 * I use this variable since it is important to put things back when
800 * we finish, even if we get errors. */
801
802 /* Make our pipes. */
803
804 if (pipe(fd) == -1) {
805 statusbar(_("Could not pipe"));
806 return 1;
807 }
808
809 /* Fork a child. */
810
811 if ((pid = fork()) == 0) {
812 close(fd[0]);
813 dup2(fd[1], fileno(stdout));
814 dup2(fd[1], fileno(stderr));
815 /* If execl() returns at all, there was an error. */
816
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000817 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000818 exit(0);
819 }
820
821 /* Else continue as parent. */
822
823 close(fd[1]);
824
825 if (pid == -1) {
826 close(fd[0]);
827 statusbar(_("Could not fork"));
828 return 1;
829 }
830
831 /* Before we start reading the forked command's output, we set
832 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000833 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000834 cancel_sigs = 1;
835 nperror("sigaction");
836 } else {
837 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000838 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000839 cancel_sigs = 1;
840 nperror("sigaction");
841 }
842 }
843 /* Note that now oldaction is the previous SIGINT signal handler,
844 * to be restored later. */
845
846 /* See if the platform supports disabling individual control
847 * characters. */
848#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000849 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000850 cancel_sigs = 2;
851 nperror("tcgetattr");
852 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000853 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000854 newterm = term;
855 /* Grab oldterm's VINTR key :-) */
856 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
857 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
858 cancel_sigs = 2;
859 nperror("tcsetattr");
860 }
861 }
862#endif /* _POSIX_VDISABLE */
863
864 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000865 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000866 nperror("fdopen");
867
868 read_file(f, "stdin", 0);
869 /* if multibuffer mode is on, we could be here in view mode; if so,
870 don't set the modification flag */
871 if (!ISSET(VIEW_MODE))
872 set_modified();
873
874 if (wait(NULL) == -1)
875 nperror("wait");
876
877#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000878 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000879 nperror("tcsetattr");
880#endif /* _POSIX_VDISABLE */
881
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000882 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000883 nperror("sigaction");
884
885 return 0;
886}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000887#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000888
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000889#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000890void do_mouse(void)
891{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000892 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000893
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000894 if (get_mouseinput(&mouse_x, &mouse_y, 1) == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000895
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000896 /* Click in the edit window to move the cursor, but only when
897 we're not in a subfunction. */
898 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
899 int sameline;
900 /* Did they click on the line with the cursor? If they
901 clicked on the cursor, we set the mark. */
902 size_t xcur;
903 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000904
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000905 /* Subtract out size of topwin. Perhaps we need a constant
906 somewhere? */
907 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000908
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000909 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000910
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000911 /* Move to where the click occurred. */
912 for (; current_y < mouse_y && current->next != NULL; current_y++)
913 current = current->next;
914 for (; current_y > mouse_y && current->prev != NULL; current_y--)
915 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000916
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000917 xcur = actual_x(current->data, get_page_start(xplustabs()) +
918 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000919
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000920 /* Selecting where the cursor is toggles the mark. As does
921 selecting beyond the line length with the cursor at the
922 end of the line. */
923 if (sameline && xcur == current_x) {
924 if (ISSET(VIEW_MODE)) {
925 print_view_warning();
926 return;
927 }
928 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000929 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000930
931 current_x = xcur;
932 placewewant = xplustabs();
933 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000934 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000935 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000936 /* FIXME: If we clicked on a location in the statusbar, the cursor
937 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000938}
939#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000940
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000941/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000942void do_char(char ch)
943{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000944 size_t current_len = strlen(current->data);
945#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000946 int refresh = FALSE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000947 /* Do we have to run edit_refresh(), or can we get away with
948 * update_line()? */
949#endif
950
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000951 if (ch == '\0') /* Null to newline, if needed. */
952 ch = '\n';
953 else if (ch == '\n') { /* Newline to Enter, if needed. */
954 do_enter();
955 return;
956 }
957
958 assert(current != NULL && current->data != NULL);
959
960 /* When a character is inserted on the current magicline, it means
961 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000962 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000963 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000964
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000965 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000966 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000967 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000968 charmove(&current->data[current_x + 1], &current->data[current_x],
969 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000970 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000971 totsize++;
972 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000973
Chris Allegretta6df90f52002-07-19 01:08:59 +0000974#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000975 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000977 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000978#endif
979
Chris Allegretta6df90f52002-07-19 01:08:59 +0000980 do_right();
981
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000982#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +0000983 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +0000984 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000985#endif
986
Chris Allegretta6df90f52002-07-19 01:08:59 +0000987#ifdef ENABLE_COLOR
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000988 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000989 refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000990#endif
991
992#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
993 if (refresh)
994 edit_refresh();
995#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000996}
997
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000998int do_verbatim_input(void)
999{
David Lawrence Ramseyee383db2004-02-06 03:07:10 +00001000 int *verbatim_kbinput; /* Used to hold verbatim input. */
1001 int verbatim_len; /* Length of verbatim input. */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001002 int i;
1003
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001004 statusbar(_("Verbatim input"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00001005 verbatim_kbinput = get_verbatim_kbinput(edit, &verbatim_len, 1);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001006
1007 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1008 * off afterwards, so that if constant cursor position display is
1009 * on, it will be updated properly. */
1010 SET(DISABLE_CURPOS);
1011 for (i = 0; i < verbatim_len; i++)
David Lawrence Ramsey815cba82004-02-07 03:07:01 +00001012 do_char((char)verbatim_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001013 UNSET(DISABLE_CURPOS);
1014
1015 free(verbatim_kbinput);
1016
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001017 return 1;
1018}
1019
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001020int do_backspace(void)
1021{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001022 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001023 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001024 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001025 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001026 return 1;
1027}
1028
1029int do_delete(void)
1030{
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001031 assert(current != NULL && current->data != NULL && current_x <=
1032 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001033
1034 placewewant = xplustabs();
1035
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001036 if (current->data[current_x] != '\0') {
1037 size_t linelen = strlen(current->data + current_x);
1038
1039 assert(current_x < strlen(current->data));
1040
1041 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001042 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001043 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001044
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001045 null_at(&current->data, linelen + current_x - 1);
1046#ifndef NANO_SMALL
1047 if (current_x < mark_beginx && mark_beginbuf == current)
1048 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001049#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001050 } else if (current != filebot && (current->next != filebot ||
1051 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001052 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001053 * becomes the new magic line then. */
1054 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001055
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001056 assert(current_x == strlen(current->data));
1057 current->data = charealloc(current->data, current_x +
1058 strlen(foo->data) + 1);
1059 strcpy(current->data + current_x, foo->data);
1060#ifndef NANO_SMALL
1061 if (mark_beginbuf == current->next) {
1062 mark_beginx += current_x;
1063 mark_beginbuf = current;
1064 }
1065#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001066 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001067 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001068
1069 unlink_node(foo);
1070 delete_node(foo);
1071 renumber(current);
1072 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001073 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001074 } else
1075 return 0;
1076
1077 totsize--;
1078 set_modified();
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001079 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001080 return 1;
1081}
1082
1083int do_tab(void)
1084{
1085 do_char('\t');
1086 return 1;
1087}
1088
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001089/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001090int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001091{
Chris Allegrettae3167732001-03-18 16:59:34 +00001092 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001093 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001094
Chris Allegretta6df90f52002-07-19 01:08:59 +00001095 newnode = make_new_node(current);
1096 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001097 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001098
Chris Allegrettaff989832001-09-17 13:48:00 +00001099#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001100 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001101 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001102 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001103 const char *spc = current->data;
1104
1105 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001106 extra++;
1107 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001108 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001109 /* If current_x < extra, then we are breaking the line in the
1110 * indentation. Autoindenting should add only current_x
1111 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001112 if (current_x < extra)
1113 extra = current_x;
1114 else
1115 current_x = extra;
1116 totsize += extra;
1117
1118 newnode->data = charalloc(strlen(tmp) + extra + 1);
1119 strncpy(newnode->data, current->data, extra);
1120 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001121 } else
1122#endif
1123 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001124 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001125 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001126 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001127 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001128 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001129
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001130 if (current->next == NULL)
Chris Allegrettae3167732001-03-18 16:59:34 +00001131 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001132 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001133
1134 totsize++;
1135 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001136 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001137 align(&current->data);
1138
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001139 /* The logic here is as follows:
1140 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001141 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001142 * -> otherwise, we want simply to redraw the screen and update
1143 * where we think the cursor is.
1144 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001145 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001146#ifndef NANO_SMALL
1147 if (ISSET(SMOOTHSCROLL))
1148 edit_update(current, NONE);
1149 else
1150#endif
1151 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001152 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001153 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001154 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001155 edit_refresh();
1156 update_cursor();
1157 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001158
1159 totlines++;
1160 set_modified();
1161
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001162 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001163 return 1;
1164}
1165
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001166#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001167int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001170
Chris Allegretta6df90f52002-07-19 01:08:59 +00001171 /* Skip letters in this word first. */
1172 while (current->data[current_x] != '\0' &&
1173 isalnum((int)current->data[current_x]))
1174 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 for (; current != NULL; current = current->next) {
1177 while (current->data[current_x] != '\0' &&
1178 !isalnum((int)current->data[current_x]))
1179 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180
Chris Allegretta6df90f52002-07-19 01:08:59 +00001181 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182 break;
1183
Chris Allegretta6df90f52002-07-19 01:08:59 +00001184 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001185 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001186 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001188
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001190
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001191 /* Refresh the screen. If current has run off the bottom, this
1192 * call puts it at the center line. */
1193 edit_refresh();
1194
Chris Allegretta6232d662002-05-12 19:52:15 +00001195 return 0;
1196}
1197
Chris Allegretta6df90f52002-07-19 01:08:59 +00001198/* The same thing for backwards. */
1199int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001200{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001201 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001202
Chris Allegretta6df90f52002-07-19 01:08:59 +00001203 /* Skip letters in this word first. */
1204 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1205 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001206
Chris Allegretta6df90f52002-07-19 01:08:59 +00001207 for (; current != NULL; current = current->prev) {
1208 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1209 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001210
Chris Allegretta6df90f52002-07-19 01:08:59 +00001211 if (current_x >= 0)
1212 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001213
Chris Allegretta6df90f52002-07-19 01:08:59 +00001214 if (current->prev != NULL)
1215 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001216 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001217
Chris Allegretta6df90f52002-07-19 01:08:59 +00001218 if (current != NULL) {
1219 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1220 current_x--;
1221 } else {
1222 current = fileage;
1223 current_x = 0;
1224 }
1225
Chris Allegretta76e291b2001-10-14 19:05:10 +00001226 placewewant = xplustabs();
1227
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001228 /* Refresh the screen. If current has run off the top, this call
1229 * puts it at the center line. */
1230 edit_refresh();
1231
Chris Allegretta6232d662002-05-12 19:52:15 +00001232 return 0;
1233}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001234#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001235
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001236int do_mark(void)
1237{
1238#ifdef NANO_SMALL
1239 nano_disabled_msg();
1240#else
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001241 TOGGLE(MARK_ISSET);
1242 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001243 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001244 mark_beginbuf = current;
1245 mark_beginx = current_x;
1246 } else {
1247 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001248 edit_refresh();
1249 }
1250#endif
1251 return 1;
1252}
1253
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001254#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001255void wrap_reset(void)
1256{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001257 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001258}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001259#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001260
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001261#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001262/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001263 * moved forward since the last typed character. Return value:
1264 * whether we wrapped. */
1265int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001266{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001267 size_t len = strlen(inptr->data); /* length of the line we wrap */
1268 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001269 int wrap_loc = -1; /* index of inptr->data where we wrap */
1270 int word_back = -1;
1271#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001272 const char *indentation = NULL;
1273 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001274 int indent_len = 0; /* strlen(indentation) */
1275#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001276 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001277 int after_break_len; /* strlen(after_break) */
1278 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001279 const char *wrap_line = NULL;
1280 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001281 int wrap_line_len = 0; /* strlen(wrap_line) */
1282 char *newline = NULL; /* the line we create */
1283 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001284
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001285/* There are three steps. First, we decide where to wrap. Then, we
1286 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001287
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001288/* Step 1, finding where to wrap. We are going to add a new-line
1289 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001290 * location of this replacement.
1291 *
1292 * Where should we break the line? We need the last "legal wrap point"
1293 * such that the last word before it ended at or before fill. If there
1294 * is no such point, we settle for the first legal wrap point.
1295 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001296 * A "legal wrap point" is a white-space character that is not followed by
1297 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001298 *
1299 * If there is no legal wrap point or we found the last character of the
1300 * line, we should return without wrapping.
1301 *
1302 * Note that the initial indentation does not count as a legal wrap
1303 * point if we are going to auto-indent!
1304 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001305 * Note that the code below could be optimised, by not calling strnlenpt()
1306 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001307
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001308#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001309 if (ISSET(AUTOINDENT))
1310 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001311#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001312 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001313 for (; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001314 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001315 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001316 word_back = i;
1317 /* if we have found a "legal wrap point" and the current word
1318 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001319 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001320 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001321 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001322 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001323 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001324 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001325 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001326 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001327
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001328/* Step 2, making the new wrap line. It will consist of indentation +
1329 * after_break + " " + wrap_line (although indentation and wrap_line are
1330 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001331
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001332 /* after_break is the text that will be moved to the next line. */
1333 after_break = inptr->data + wrap_loc + 1;
1334 after_break_len = len - wrap_loc - 1;
1335 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001336
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001337 /* new_line_len will later be increased by the lengths of indentation
1338 * and wrap_line. */
1339 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001340
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001341 /* We prepend the wrapped text to the next line, if the flag is set,
1342 * and there is a next line, and prepending would not make the line
1343 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001344 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001345 wrap_line = inptr->next->data;
1346 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001347
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001348 /* +1 for the space between after_break and wrap_line */
1349 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1350 wrapping = 1;
1351 new_line_len += (1 + wrap_line_len);
1352 }
1353 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001354
Chris Allegrettaff989832001-09-17 13:48:00 +00001355#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001356 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001357 /* Indentation comes from the next line if wrapping, else from
1358 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001359 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001360 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001361 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001362 /* The wrap_line text should not duplicate indentation.
1363 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001364 wrap_line += indent_len;
1365 else
1366 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001367 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001368#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001369
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001370 /* Now we allocate the new line and copy into it. */
1371 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1372 *newline = '\0';
1373
1374#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001375 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001376 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001377 newline[indent_len] = '\0';
1378 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001379#endif
1380 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001381 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001382 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001383 null_at(&inptr->data, wrap_loc + 1);
1384 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001385 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001386 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001387 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001388 * in a tab or a space, we don't add a space and decrement
1389 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001390 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001391 strcat(newline, " ");
1392 else
1393 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394 strcat(newline, wrap_line);
1395 free(inptr->next->data);
1396 inptr->next->data = newline;
1397 } else {
1398 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001399
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001400 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001401 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001402#ifndef NANO_SMALL
1403 totsize += indent_len;
1404#endif
1405 totlines++;
1406 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001407 temp->prev = inptr;
1408 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001409 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001410 /* If temp->next is NULL, then temp is the last line of the
1411 * file, so we must set filebot. */
1412 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001413 temp->next->prev = temp;
1414 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001415 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001416 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001417
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001418/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1419 * other sundry things. */
1420
1421 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001422 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001423
1424 /* Each line knows its line number. We recalculate these if we
1425 * inserted a new line. */
1426 if (!wrapping)
1427 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001428
Chris Allegretta6df90f52002-07-19 01:08:59 +00001429 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001430 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001431 current = current->next;
1432 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001433#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001434 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001435#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001436 wrap_loc + 1;
1437 wrap_reset();
1438 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001439 }
1440
Chris Allegretta6df90f52002-07-19 01:08:59 +00001441#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001442 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001443 * If it was on the next line and we wrapped, we must move it
1444 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001445 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1446 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001447 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001448 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001449 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001450#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001451
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001452 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001453 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001454
1455 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001456}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001457#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001458
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001459#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001460/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001461 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001462int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001463{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001464 char *save_search;
1465 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001466 filestruct *current_save = current;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001467 size_t current_x_save = current_x;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001468 filestruct *edittop_save = edittop;
1469 /* Save where we are. */
1470 int i = 0;
1471 /* The return value. */
1472 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001473#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001474 int case_sens_set = ISSET(CASE_SENSITIVE);
1475 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001476
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001477 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001478 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001479 UNSET(MARK_ISSET);
1480#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001481 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001482 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001483
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001484 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001485 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001486 save_search = last_search;
1487 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001488
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001489 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001490 last_search = mallocstrcpy(NULL, word);
1491 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001492
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001493 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001494 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001495 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001496
1497 search_last_line = FALSE;
1498
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001499 /* Find the first whole-word occurrence of word. */
1500 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001501 if (is_whole_word(current_x, current->data, word)) {
1502 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001503
Chris Allegretta6df90f52002-07-19 01:08:59 +00001504 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001505
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001506 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001507 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001508#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001509 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001510#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001511 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001512
Chris Allegretta6df90f52002-07-19 01:08:59 +00001513 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001514
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001515 if (i != -1 && strcmp(word, answer)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001516 search_last_line = FALSE;
1517 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001518 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001519 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001520
1521 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001522 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001523
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001524 /* Restore the search/replace strings. */
1525 free(last_search);
1526 last_search = save_search;
1527 free(last_replace);
1528 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001529
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001530 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001531 current = current_save;
1532 current_x = current_x_save;
1533 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001534
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001535 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001536 if (reverse_search_set)
1537 SET(REVERSE_SEARCH);
1538
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001539#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001540 if (!case_sens_set)
1541 UNSET(CASE_SENSITIVE);
1542
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001543 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001544 if (mark_set)
1545 SET(MARK_ISSET);
1546#endif
1547
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001548 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001549}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001550
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001551/* Integrated spell checking using 'spell' program. Return value: NULL
1552 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001553char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001554{
Chris Allegretta271e9722000-11-10 18:15:43 +00001555 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001556 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001557 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001558 pid_t pid_spell, pid_sort, pid_uniq;
1559 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001560
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001561 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001562 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1563 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001564
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001565 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001566
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001567 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001568 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001569
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001570 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001571
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001572 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001573
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001574 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001575 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1576 goto close_pipes_and_exit;
1577
1578 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1579 goto close_pipes_and_exit;
1580
Chris Allegretta271e9722000-11-10 18:15:43 +00001581 close(tempfile_fd);
1582
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001583 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001584 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1585 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001586
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001587 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001588
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001589 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001590 execlp("spell", "spell", NULL);
1591
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001592 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001593 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001594 }
1595
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001596 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001597 close(spell_fd[1]);
1598
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001599 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001600 if ((pid_sort = fork()) == 0) {
1601
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001602 /* Child continues (i.e, future spell process). Replace the
1603 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001604 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1605 goto close_pipes_and_exit;
1606
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001607 close(spell_fd[0]);
1608
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001609 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001610 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1611 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001612
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001613 close(sort_fd[1]);
1614
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001615 /* Start sort program. Use -f to remove mixed case without
1616 * having to have ANOTHER pipe for tr. If this isn't portable,
1617 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001618 execlp("sort", "sort", "-f", NULL);
1619
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001620 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001621 exit(1);
1622 }
1623
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001624 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001625 close(sort_fd[1]);
1626
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001627 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001628 if ((pid_uniq = fork()) == 0) {
1629
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001630 /* Child continues (i.e, future uniq process). Replace the
1631 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001632 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1633 goto close_pipes_and_exit;
1634
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001635 close(sort_fd[0]);
1636
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001637 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001638 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1639 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001640
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001641 close(uniq_fd[1]);
1642
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001643 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001644 execlp("uniq", "uniq", NULL);
1645
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001646 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001647 exit(1);
1648 }
1649
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001650 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001651 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001652
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001653 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001654 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1655 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001656 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001657 }
1658
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001659 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001660 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1661 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001662 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001663 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001664
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001665 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001666 read_buff_read = 0;
1667 read_buff_size = pipe_buff_size + 1;
1668 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001669
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001670 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001671 read_buff_read += bytesread;
1672 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001673 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001674 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001675
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001676 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001677
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001678 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001679 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001680
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001681 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001682 read_buff_word = read_buff_ptr = read_buff;
1683
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001684 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001685
1686 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001687 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001688 if (read_buff_word != read_buff_ptr) {
1689 if (!do_int_spell_fix(read_buff_word)) {
1690 read_buff_word = read_buff_ptr;
1691 break;
1692 }
1693 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001694 read_buff_word = read_buff_ptr + 1;
1695 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001696 read_buff_ptr++;
1697 }
1698
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001699 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001700 if (read_buff_word != read_buff_ptr)
1701 do_int_spell_fix(read_buff_word);
1702
Chris Allegretta271e9722000-11-10 18:15:43 +00001703 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001704 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001705 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001706
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001707 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001708 waitpid(pid_spell, &spell_status, 0);
1709 waitpid(pid_sort, &sort_status, 0);
1710 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001711
Chris Allegretta334a9402002-12-16 04:25:53 +00001712 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1713 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001714
Chris Allegretta334a9402002-12-16 04:25:53 +00001715 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1716 return _("Error invoking \"sort -f\"");
1717
1718 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1719 return _("Error invoking \"uniq\"");
1720
1721 /* Otherwise... */
1722 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001723
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001724 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001725
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001726 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001727 close(tempfile_fd);
1728 close(spell_fd[0]);
1729 close(spell_fd[1]);
1730 close(sort_fd[0]);
1731 close(sort_fd[1]);
1732 close(uniq_fd[0]);
1733 close(uniq_fd[1]);
1734 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001735}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001736
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001737/* External spell checking. Return value: NULL for normal termination,
1738 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001739char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001740{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001741 int alt_spell_status, lineno_cur = current->lineno;
1742 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001743 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001744 char *ptr;
1745 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001746 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001747#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001748 int mark_set = ISSET(MARK_ISSET);
1749 int mbb_lineno_cur = 0;
1750 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001751 * the alternate spell command. The line that mark_beginbuf
1752 * points to will be freed, so we save the line number and
1753 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001754
1755 if (mark_set) {
1756 mbb_lineno_cur = mark_beginbuf->lineno;
1757 UNSET(MARK_ISSET);
1758 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001759#endif
1760
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001761 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001762
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001763 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001764 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001765 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001766
Chris Allegrettae434b452001-01-27 19:25:00 +00001767 spellargs[0] = strtok(alt_speller, " ");
1768 while ((ptr = strtok(NULL, " ")) != NULL) {
1769 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001770 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001771 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001772 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001773 spellargs[arglen - 1] = NULL;
1774 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001775 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001776
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001777 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001778 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001779 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001780 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001781
1782 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001783 exit(1);
1784 }
1785
1786 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001787 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001788 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001789
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001790 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001791 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001792
Chris Allegretta334a9402002-12-16 04:25:53 +00001793 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1794 char *altspell_error = NULL;
1795 char *invoke_error = _("Could not invoke \"%s\"");
1796 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1797
1798 altspell_error = charalloc(msglen);
1799 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1800 return altspell_error;
1801 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001802
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001803 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001804#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001805 if (!mark_set) {
1806 /* Only reload the temp file if it isn't a marked selection. */
1807#endif
1808 free_filestruct(fileage);
1809 global_init(1);
1810 open_file(tempfile_name, 0, 1);
1811#ifndef NANO_SMALL
1812 }
1813
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001814 if (mark_set) {
1815 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1816 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001817 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001818 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001819 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001820 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001821#endif
1822
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001823 /* Go back to the old position, mark the file as modified, and make
1824 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001825 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001826 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001827 clearok(topwin, FALSE);
1828 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001829
Chris Allegretta334a9402002-12-16 04:25:53 +00001830 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001831}
1832#endif
1833
1834int do_spell(void)
1835{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001836#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001837 nano_disabled_msg();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001838 return 1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001839#else
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001840 int i;
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001841 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001842
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001843 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001844 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001845 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001846 return 0;
1847 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001848
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001849#ifndef NANO_SMALL
1850 if (ISSET(MARK_ISSET))
1851 i = write_marked(temp, 1, 0, 0);
1852 else
1853#endif
1854 i = write_file(temp, 1, 0, 0);
1855
1856 if (i == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001857 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001858 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001859 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001860 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001861
Chris Allegrettae1f14522001-09-19 03:19:43 +00001862#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001863 /* Update the current open_files entry before spell-checking, in
1864 * case any problems occur. */
Chris Allegretta48b06702002-02-22 04:30:50 +00001865 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001866#endif
1867
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001868 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001869 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001870 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001871 spell_msg = do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001872 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001873 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001874
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001875 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001876 statusbar(_("Spell checking failed: %s"), spell_msg);
1877 return 0;
1878 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001879
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001880 statusbar(_("Finished checking spelling"));
1881 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001882#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001883}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001884
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001885#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001886/* The "indentation" of a line is the white-space between the quote part
1887 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001888size_t indent_length(const char *line)
1889{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001890 size_t len = 0;
1891
1892 assert(line != NULL);
1893 while (*line == ' ' || *line == '\t') {
1894 line++;
1895 len++;
1896 }
1897 return len;
1898}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001899#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001900
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001901#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00001902/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
1903 * it maintains 2 after a . ! or ?). Note the terminating \0
1904 * counts as a space.
1905 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001906 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001907 * returns 1, otherwise returns 0.
1908 *
1909 * If changes_allowed, justify_format() might make line->data
1910 * shorter, and change the actual pointer with null_at().
1911 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001912 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001913 * skip should be at most strlen(line->data). The skip+1st character must
1914 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001915int justify_format(int changes_allowed, filestruct *line, size_t skip)
1916{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001917 const char *punct = ".?!";
1918 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001919 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001920
Chris Allegretta6df90f52002-07-19 01:08:59 +00001921 /* These four asserts are assumptions about the input data. */
1922 assert(line != NULL);
1923 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001924 assert(skip < strlen(line->data));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001925 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001926
Chris Allegretta6df90f52002-07-19 01:08:59 +00001927 back = line->data + skip;
1928 front = back;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001929 for (front = back; ; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001930 int remove_space = 0;
1931 /* Do we want to remove this space? */
1932
Chris Allegretta6df90f52002-07-19 01:08:59 +00001933 if (*front == '\t') {
1934 if (!changes_allowed)
1935 return 1;
1936 *front = ' ';
1937 }
1938 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001939 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001940 const char *bob = front - 2;
1941
1942 remove_space = 1;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001943 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001944 if (strchr(punct, *bob) != NULL) {
1945 remove_space = 0;
1946 break;
1947 }
1948 if (strchr(brackets, *bob) == NULL)
1949 break;
1950 }
1951 }
1952
1953 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001954 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001955 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001956 if (!changes_allowed)
1957 return 1;
1958#ifndef NANO_SMALL
1959 if (mark_beginbuf == line && back - line->data < mark_beginx)
1960 mark_beginx--;
1961#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001962 if (*front == '\0')
1963 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001964 } else {
1965 *back = *front;
1966 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001967 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001968 if (*front == '\0')
1969 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001970 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001971
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001972 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001973 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001974
1975 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001976 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001977
1978 /* Now back is the new end of line->data. */
1979 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001980 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001981 null_at(&line->data, back - line->data);
1982#ifndef NANO_SMALL
1983 if (mark_beginbuf == line && back - line->data < mark_beginx)
1984 mark_beginx = back - line->data;
1985#endif
1986 }
1987 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001988}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001989
1990/* The "quote part" of a line is the largest initial substring matching
1991 * the quote string. This function returns the length of the quote part
1992 * of the given line.
1993 *
1994 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1995 * quotestr. */
1996#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001997size_t quote_length(const char *line, const regex_t *qreg)
1998{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001999 regmatch_t matches;
2000 int rc = regexec(qreg, line, 1, &matches, 0);
2001
2002 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2003 return 0;
2004 /* matches.rm_so should be 0, since the quote string should start with
2005 * the caret ^. */
2006 return matches.rm_eo;
2007}
2008#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002009size_t quote_length(const char *line)
2010{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002011 size_t qdepth = 0;
2012 size_t qlen = strlen(quotestr);
2013
2014 /* Compute quote depth level */
2015 while (!strcmp(line + qdepth, quotestr))
2016 qdepth += qlen;
2017 return qdepth;
2018}
2019#endif /* !HAVE_REGEX_H */
2020
Chris Allegretta6df90f52002-07-19 01:08:59 +00002021/* a_line and b_line are lines of text. The quotation part of a_line is
2022 * the first a_quote characters. Check that the quotation part of
2023 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002024int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002025 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002026{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002027 /* Here is the assumption about a_quote: */
2028 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002029 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002030 !strncmp(a_line, b_line, a_quote);
2031}
2032
2033/* We assume a_line and b_line have no quote part. Then, we return whether
2034 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002035size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002036 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002037{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002038 assert(a_indent == indent_length(a_line));
2039 assert(b_indent == indent_length(b_line));
2040
2041 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2042}
2043
2044/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002045 * buffer, not allowing them to be concatenated. We assume there are
2046 * enough lines after first_line. We leave copies of the lines in
2047 * place, too. We return the new copy of first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002048filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002049 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002050{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002051 /* We put the original lines, not copies, into the cut buffer, just
2052 * out of a misguided sense of consistency, so if you un-cut, you
2053 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002054 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002055
2056 set_modified();
2057 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002058 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002059 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002060
Chris Allegretta908f7702003-01-15 11:18:58 +00002061 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002062 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002063 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002064 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002065 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002066 edittop = bob;
2067#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002068 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002069 mark_beginbuf = bob;
2070#endif
2071 justify_format(1, bob,
2072 quote_len + indent_length(bob->data + quote_len));
2073
Chris Allegretta908f7702003-01-15 11:18:58 +00002074 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002075 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002076 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002077 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002078 }
2079 return first_line;
2080}
2081
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002082/* Is it possible to break line at or before goal? */
2083int breakable(const char *line, int goal)
2084{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002085 for (; *line != '\0' && goal >= 0; line++) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002086 if (*line == ' ' || *line == '\t')
2087 return TRUE;
2088
2089 if (is_cntrl_char(*line) != 0)
2090 goal -= 2;
2091 else
2092 goal -= 1;
2093 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002094 /* If goal is not negative, the whole line (one word) was short
2095 * enough. */
2096 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002097}
2098
Chris Allegretta6df90f52002-07-19 01:08:59 +00002099/* We are trying to break a chunk off line. We find the last space such
2100 * that the display length to there is at most goal + 1. If there is
2101 * no such space, and force is not 0, then we find the first space.
2102 * Anyway, we then take the last space in that group of spaces. The
2103 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002104int break_line(const char *line, int goal, int force)
2105{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002106 /* Note that we use int instead of size_t, since goal is at most COLS,
2107 * the screen width, which will always be reasonably small. */
2108 int space_loc = -1;
2109 /* Current tentative return value. Index of the last space we
2110 * found with short enough display width. */
2111 int cur_loc = 0;
2112 /* Current index in line */
2113
2114 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002115 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002116 if (*line == ' ')
2117 space_loc = cur_loc;
2118 assert(*line != '\t');
2119
Chris Allegrettacf287c82002-07-20 13:57:41 +00002120 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002121 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002122 else
2123 goal--;
2124 }
2125 if (goal >= 0)
2126 /* In fact, the whole line displays shorter than goal. */
2127 return cur_loc;
2128 if (space_loc == -1) {
2129 /* No space found short enough. */
2130 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002131 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002132 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002133 return cur_loc;
2134 return -1;
2135 }
2136 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002137 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002138 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2139 *(line - cur_loc + space_loc + 1) == '\0')
2140 space_loc++;
2141 return space_loc;
2142}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002143
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002144/* Search a paragraph. If search_type is 0, search for the beginning of
2145 * the current paragraph or, if we're at the end of it, the beginning of
2146 * the next paragraph. If search_type is 1, search for the beginning of
2147 * the current paragraph or, if we're already there, the beginning of
2148 * the previous paragraph. If search_type is 2, search for the end of
2149 * the current paragraph or, if we're already there, the end of the next
2150 * paragraph. Afterwards, save the quote length, paragraph length, and
2151 * indentation length in *quote, *par, and *indent if they aren't NULL,
2152 * and refresh the screen if do_refresh is nonzero. Return 0 if we
2153 * found a paragraph, or 1 if there was an error or we didn't find a
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002154 * paragraph.
2155 *
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002156 * To explain the searching algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002157 * phrases about paragraphs and quotation:
2158 * A line of text consists of a "quote part", followed by an
2159 * "indentation part", followed by text. The functions quote_length()
2160 * and indent_length() calculate these parts.
2161 *
2162 * A line is "part of a paragraph" if it has a part not in the quote
2163 * part or the indentation.
2164 *
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002165 * A line is "the beginning of a paragraph" if it is part of a
2166 * paragraph and
Chris Allegretta6df90f52002-07-19 01:08:59 +00002167 * 1) it is the top line of the file, or
2168 * 2) the line above it is not part of a paragraph, or
2169 * 3) the line above it does not have precisely the same quote
2170 * part, or
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002171 * 4) the indentation of this line is not an initial substring of
2172 * the indentation of the previous line, or
Chris Allegretta6df90f52002-07-19 01:08:59 +00002173 * 5) this line has no quote part and some indentation, and
2174 * AUTOINDENT is not set.
2175 * The reason for number 5) is that if AUTOINDENT is not set, then an
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002176 * indented line is expected to start a paragraph, like in books.
2177 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2178 * turned on.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002179 *
2180 * A contiguous set of lines is a "paragraph" if each line is part of
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002181 * a paragraph and only the first line is the beginning of a
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002182 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002183int do_para_search(int search_type, size_t *quote, size_t *par, size_t
2184 *indent, int do_refresh)
2185{
2186 size_t quote_len;
2187 /* Length of the initial quotation of the paragraph we
2188 * search. */
2189 size_t par_len;
2190 /* Number of lines in that paragraph. */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002191
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002192 /* We save this global variable to see if we're where we started
2193 * when searching for the beginning of the paragraph. */
2194 filestruct *current_save = current;
2195
2196 size_t indent_len; /* Generic indentation length. */
2197 filestruct *line; /* Generic line of text. */
2198
2199 static int do_restart = 1;
2200 /* Whether we're restarting when searching for the beginning
2201 * line of the paragraph. */
2202
2203#ifdef HAVE_REGEX_H
2204 regex_t qreg; /* qreg is the compiled quotation regexp. We no
2205 * longer care about quotestr. */
2206 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2207
2208 if (rc != 0) {
2209 size_t size = regerror(rc, &qreg, NULL, 0);
2210 char *strerror = charalloc(size);
2211
2212 regerror(rc, &qreg, strerror, size);
2213 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2214 free(strerror);
2215 return 1;
2216 }
2217#endif
2218
2219 /* Here is an assumption that is always true anyway. */
2220 assert(current != NULL);
2221
2222 current_x = 0;
2223
2224 restart_para_search:
2225/* Here we find the first line of the paragraph to search. If the
2226 * current line is in a paragraph, then we move back to the first line.
2227 * Otherwise we move to the first line that is in a paragraph. */
2228 quote_len = quote_length(IFREG(current->data, &qreg));
2229 indent_len = indent_length(current->data + quote_len);
2230
2231 if (current->data[quote_len + indent_len] != '\0') {
2232 /* This line is part of a paragraph. So we must search back to
2233 * the first line of this paragraph. First we check items 1)
2234 * and 3) above. */
2235 while (current->prev != NULL && quotes_match(current->data,
2236 quote_len, IFREG(current->prev->data, &qreg))) {
2237 size_t temp_id_len =
2238 indent_length(current->prev->data + quote_len);
2239 /* The indentation length of the previous line. */
2240
2241 /* Is this line the beginning of a paragraph, according to
2242 * items 2), 5), or 4) above? If so, stop. */
2243 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2244 (quote_len == 0 && indent_len > 0
2245#ifndef NANO_SMALL
2246 && !ISSET(AUTOINDENT)
2247#endif
2248 ) ||
2249 !indents_match(current->prev->data + quote_len,
2250 temp_id_len, current->data + quote_len, indent_len))
2251 break;
2252 indent_len = temp_id_len;
2253 current = current->prev;
2254 current_y--;
2255 }
2256 } else if (search_type == 1) {
2257 /* This line is not part of a paragraph. Move up until we get
2258 * to a non "blank" line, and then move down once. */
2259 do {
2260 /* There is no previous paragraph, so nothing to move to. */
2261 if (current->prev == NULL) {
2262 placewewant = 0;
2263 if (do_refresh) {
2264 if (current_y < 0)
2265 edit_update(current, CENTER);
2266 else
2267 edit_refresh();
2268 }
2269#ifdef HAVE_REGEX_H
2270 if (!do_restart)
2271 regfree(&qreg);
2272#endif
2273 return 1;
2274 }
2275 current = current->prev;
2276 current_y--;
2277 quote_len = quote_length(IFREG(current->data, &qreg));
2278 indent_len = indent_length(current->data + quote_len);
2279 } while (current->data[quote_len + indent_len] == '\0');
2280 current = current->next;
2281 } else {
2282 /* This line is not part of a paragraph. Move down until we get
2283 * to a non "blank" line. */
2284 do {
2285 /* There is no next paragraph, so nothing to move to. */
2286 if (current->next == NULL) {
2287 placewewant = 0;
2288 if (do_refresh)
2289 edit_refresh();
2290#ifdef HAVE_REGEX_H
2291 regfree(&qreg);
2292#endif
2293 return 1;
2294 }
2295 current = current->next;
2296 current_y++;
2297 quote_len = quote_length(IFREG(current->data, &qreg));
2298 indent_len = indent_length(current->data + quote_len);
2299 } while (current->data[quote_len + indent_len] == '\0');
2300 }
2301
2302/* Now current is the first line of the paragraph, and quote_len is the
2303 * quotation length of that line. */
2304
2305/* Next step, compute par_len, the number of lines in this paragraph. */
2306 line = current;
2307 par_len = 1;
2308 indent_len = indent_length(line->data + quote_len);
2309
2310 while (line->next != NULL && quotes_match(current->data, quote_len,
2311 IFREG(line->next->data, &qreg))) {
2312 size_t temp_id_len = indent_length(line->next->data + quote_len);
2313
2314 if (!indents_match(line->data + quote_len, indent_len,
2315 line->next->data + quote_len, temp_id_len) ||
2316 line->next->data[quote_len + temp_id_len] == '\0' ||
2317 (quote_len == 0 && temp_id_len > 0
2318#ifndef NANO_SMALL
2319 && !ISSET(AUTOINDENT)
2320#endif
2321 ))
2322 break;
2323 indent_len = temp_id_len;
2324 line = line->next;
2325 par_len++;
2326 }
2327
2328 if (search_type == 1) {
2329 /* We're on the same line we started on. Move up until we get
2330 * to a non-"blank" line, restart the search from there until we
2331 * find a line that's part of a paragraph, and search once more
2332 * so that we end up at the beginning of that paragraph. */
2333 if (current != fileage && current == current_save && do_restart) {
2334 while (current->prev != NULL) {
2335 size_t i, j = 0;
2336 current = current->prev;
2337 current_y--;
2338 /* Skip over lines consisting only of spacing
2339 * characters, as searching for the end of the paragraph
2340 * does. */
2341 for (i = 0; current->data[i] != '\0'; i++) {
2342 if (isspace(current->data[i]))
2343 j++;
2344 else {
2345 i = 0;
2346 j = 1;
2347 break;
2348 }
2349 }
2350 if (i != j && strlen(current->data) >=
2351 (quote_len + indent_len) &&
2352 current->data[quote_len + indent_len] != '\0') {
2353 do_restart = 0;
2354 break;
2355 }
2356 }
2357 goto restart_para_search;
2358 } else
2359 do_restart = 1;
2360 }
2361
2362#ifdef HAVE_REGEX_H
2363 /* We no longer need to check quotation. */
2364 regfree(&qreg);
2365#endif
2366
2367/* Now par_len is the number of lines in this paragraph. We should
2368 * never call quotes_match() or quote_length() again. */
2369
2370 /* If we're searching for the end of the paragraph, move down the
2371 * number of lines in the paragraph. */
2372 if (search_type == 2) {
2373 for (; par_len > 0; current_y++, par_len--)
2374 current = current->next;
2375 }
2376
2377 /* Refresh the screen if needed. */
2378 if (do_refresh) {
2379 if (((search_type == 0 || search_type == 2) && current_y >
2380 editwinrows - 1) || (search_type == 1 && current_y < 0))
2381 edit_update(current, CENTER);
2382 else
2383 edit_refresh();
2384 }
2385
2386 /* Save the values of quote_len, par_len, and indent_len if
2387 * needed. */
2388 if (quote != NULL)
2389 *quote = quote_len;
2390 if (par != NULL)
2391 *par = par_len;
2392 if (indent != NULL)
2393 *indent = indent_len;
2394
2395 return 0;
2396}
2397
2398int do_para_begin(void)
2399{
2400 return do_para_search(1, NULL, NULL, NULL, TRUE);
2401}
2402
2403int do_para_end(void)
2404{
2405 return do_para_search(2, NULL, NULL, NULL, TRUE);
2406}
2407#endif
2408
2409/* Justify a paragraph. */
2410int do_justify(void)
2411{
2412#ifdef DISABLE_JUSTIFY
2413 nano_disabled_msg();
2414 return 1;
2415#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002416 size_t quote_len;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002417 /* Length of the initial quotation of the paragraph we
2418 * justify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002419 size_t par_len;
2420 /* Number of lines in that paragraph. */
2421 filestruct *first_mod_line = NULL;
2422 /* Will be the first line of the resulting justified paragraph
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002423 * that differs from the original. For restoring after
2424 * uncut. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002425 filestruct *last_par_line = current;
2426 /* Will be the last line of the result, also for uncut. */
2427 filestruct *cutbuffer_save = cutbuffer;
2428 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002429 * one down are stored in the cut buffer. We back up the
2430 * original to restore it later. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002431
2432 /* We save these global variables to be restored if the user
2433 * unjustifies. Note we don't need to save totlines. */
2434 int current_x_save = current_x;
2435 int current_y_save = current_y;
2436 filestruct *current_save = current;
2437 int flags_save = flags;
2438 long totsize_save = totsize;
2439 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002440#ifndef NANO_SMALL
2441 filestruct *mark_beginbuf_save = mark_beginbuf;
2442 int mark_beginx_save = mark_beginx;
2443#endif
2444
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002445 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002446 size_t i; /* Generic loop variable. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002447
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002448 /* First, search for the beginning of the current paragraph or, if
2449 * we're at the end of it, the beginning of the next paragraph.
2450 * Save the quote length, paragraph length, and indentation length
2451 * and don't refresh the screen yet (since we'll do that after we
2452 * justify). If the search failed, refresh the screen and get
2453 * out. */
2454 if (do_para_search(0, &quote_len, &par_len, &indent_len, FALSE) != 0) {
2455 edit_refresh();
2456 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002457 }
2458
Chris Allegretta6df90f52002-07-19 01:08:59 +00002459/* Next step, we loop through the lines of this paragraph, justifying
2460 * each one individually. */
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002461 for (; par_len > 0; current_y++, par_len--) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002462 size_t line_len;
2463 size_t display_len;
2464 /* The width of current in screen columns. */
2465 int break_pos;
2466 /* Where we will break the line. */
2467
2468 indent_len = indent_length(current->data + quote_len) +
2469 quote_len;
2470 /* justify_format() removes excess spaces from the line, and
2471 * changes tabs to spaces. The first argument, 0, means don't
2472 * change the line, just say whether there are changes to be
2473 * made. If there are, we do backup_lines(), which copies the
2474 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002475 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002476 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002477 first_mod_line = backup_lines(current, par_len, quote_len);
2478
2479 line_len = strlen(current->data);
2480 display_len = strlenpt(current->data);
2481
2482 if (display_len > fill) {
2483 /* The line is too long. Try to wrap it to the next. */
2484 break_pos = break_line(current->data + indent_len,
2485 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002486 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002487 if (break_pos == -1 || break_pos + indent_len == line_len)
2488 /* We can't break the line, or don't need to, so just go
2489 * on to the next. */
2490 goto continue_loc;
2491 break_pos += indent_len;
2492 assert(break_pos < line_len);
2493 /* If we haven't backed up the paragraph, do it now. */
2494 if (first_mod_line == NULL)
2495 first_mod_line = backup_lines(current, par_len, quote_len);
2496 if (par_len == 1) {
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002497 /* There is no next line in this paragraph. We make a
2498 * new line and copy text after break_pos into it. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002499 splice_node(current, make_new_node(current),
2500 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002501 /* In a non-quoted paragraph, we copy the indent only if
2502 AUTOINDENT is turned on. */
2503 if (quote_len == 0)
2504#ifndef NANO_SMALL
2505 if (!ISSET(AUTOINDENT))
2506#endif
2507 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002508 current->next->data = charalloc(indent_len + line_len -
2509 break_pos);
2510 strncpy(current->next->data, current->data,
2511 indent_len);
2512 strcpy(current->next->data + indent_len,
2513 current->data + break_pos + 1);
2514 assert(strlen(current->next->data) ==
2515 indent_len + line_len - break_pos - 1);
2516 totlines++;
2517 totsize += indent_len;
2518 par_len++;
2519 } else {
2520 size_t next_line_len = strlen(current->next->data);
2521
2522 indent_len = quote_len +
2523 indent_length(current->next->data + quote_len);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002524 current->next->data = charealloc(current->next->data,
2525 next_line_len + line_len - break_pos + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002526
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002527 charmove(current->next->data + indent_len + line_len - break_pos,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002528 current->next->data + indent_len,
2529 next_line_len - indent_len + 1);
2530 strcpy(current->next->data + indent_len,
2531 current->data + break_pos + 1);
2532 current->next->data[indent_len + line_len - break_pos - 1]
2533 = ' ';
2534#ifndef NANO_SMALL
2535 if (mark_beginbuf == current->next) {
2536 if (mark_beginx < indent_len)
2537 mark_beginx = indent_len;
2538 mark_beginx += line_len - break_pos;
2539 }
2540#endif
2541 }
2542#ifndef NANO_SMALL
2543 if (mark_beginbuf == current && mark_beginx > break_pos) {
2544 mark_beginbuf = current->next;
2545 mark_beginx -= break_pos + 1 - indent_len;
2546 }
2547#endif
2548 null_at(&current->data, break_pos);
2549 current = current->next;
2550 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002551 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002552
2553 indent_len = quote_len +
2554 indent_length(current->next->data + quote_len);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002555 /* If we can't pull a word from the next line up to this
2556 * one, just go on. */
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002557 if (!breakable(current->next->data + indent_len,
2558 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002559 goto continue_loc;
2560
2561 /* If we haven't backed up the paragraph, do it now. */
2562 if (first_mod_line == NULL)
2563 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002564
2565 break_pos = break_line(current->next->data + indent_len,
2566 fill - display_len - 1, FALSE);
2567 assert(break_pos != -1);
2568
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002569 current->data = charealloc(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002570 line_len + break_pos + 2);
2571 current->data[line_len] = ' ';
2572 strncpy(current->data + line_len + 1,
2573 current->next->data + indent_len, break_pos);
2574 current->data[line_len + break_pos + 1] = '\0';
2575#ifndef NANO_SMALL
2576 if (mark_beginbuf == current->next) {
2577 if (mark_beginx < indent_len + break_pos) {
2578 mark_beginbuf = current;
2579 if (mark_beginx <= indent_len)
2580 mark_beginx = line_len + 1;
2581 else
2582 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2583 } else
2584 mark_beginx -= break_pos + 1;
2585 }
2586#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002587 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002588 if (indent_len + break_pos == next_line_len) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002589 filestruct *line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002590
2591 /* Don't destroy edittop! */
2592 if (line == edittop)
2593 edittop = current;
2594
Chris Allegretta6df90f52002-07-19 01:08:59 +00002595 unlink_node(line);
2596 delete_node(line);
2597 totlines--;
2598 totsize -= indent_len;
2599 current_y--;
2600 } else {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002601 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002602 current->next->data + indent_len + break_pos + 1,
2603 next_line_len - break_pos - indent_len);
2604 null_at(&current->next->data,
2605 next_line_len - break_pos);
2606 current = current->next;
2607 }
2608 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002609 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002610 current = current->next;
2611 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002612
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002613/* We are now done justifying the paragraph. There are cleanup things
2614 * to do, and we check for unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002615
2616 /* totlines, totsize, and current_y have been maintained above. We
2617 * now set last_par_line to the new end of the paragraph, update
2618 * fileage, set current_x. Also, edit_refresh() needs the line
2619 * numbers to be right, so we renumber(). */
2620 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002621 if (first_mod_line != NULL) {
2622 if (first_mod_line->prev == NULL)
2623 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002624 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002625 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002626
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002627 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002628 edit_update(current, CENTER);
2629 else
2630 edit_refresh();
2631
Chris Allegretta9149e612000-11-27 00:23:41 +00002632 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002633 /* Change the shortcut list to display the unjustify code. */
Chris Allegretta07798352000-11-27 22:58:23 +00002634 shortcut_init(1);
2635 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002636 reset_cursor();
2637
Chris Allegretta6df90f52002-07-19 01:08:59 +00002638 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002639 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002640
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002641 {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002642 int meta_key;
2643 i = get_kbinput(edit, &meta_key);
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002644#ifndef DISABLE_MOUSE
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002645 /* If it was a mouse click, parse it with do_mouse() and it
2646 * might become the unjustify key. Else give it back to the
2647 * input stream. */
2648 if (i == KEY_MOUSE)
2649 do_mouse();
2650 else
2651 ungetch(i);
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00002652 i = get_kbinput(edit, &meta_key);
Chris Allegretta5f071802001-05-06 02:34:31 +00002653#endif
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002654 }
Chris Allegretta5f071802001-05-06 02:34:31 +00002655
David Lawrence Ramseyc91696e2004-01-29 04:16:23 +00002656 if (i != NANO_UNJUSTIFY_KEY && i != NANO_UNJUSTIFY_FKEY) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002657 ungetch(i);
2658 /* Did we back up anything at all? */
2659 if (cutbuffer != cutbuffer_save)
2660 free_filestruct(cutbuffer);
2661 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002662 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002663 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002664 current = current_save;
2665 current_x = current_x_save;
2666 current_y = current_y_save;
2667 edittop = edittop_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002668 if (first_mod_line != NULL) {
2669 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002670
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002671 /* Splice the cut buffer back into the file. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002672 cutbottom->next = last_par_line->next;
2673 cutbottom->next->prev = cutbottom;
2674 /* The line numbers after the end of the paragraph have
2675 * been changed, so we change them back. */
2676 renumber(cutbottom->next);
2677 if (first_mod_line->prev != NULL) {
2678 cutbuffer->prev = first_mod_line->prev;
2679 cutbuffer->prev->next = cutbuffer;
2680 } else
2681 fileage = cutbuffer;
2682 cutbuffer = NULL;
2683
2684 last_par_line->next = NULL;
2685 free_filestruct(first_mod_line);
2686
2687 /* Restore global variables from before justify */
2688 totsize = totsize_save;
2689 totlines = filebot->lineno;
2690#ifndef NANO_SMALL
2691 mark_beginbuf = mark_beginbuf_save;
2692 mark_beginx = mark_beginx_save;
2693#endif
2694 flags = flags_save;
2695 if (!ISSET(MODIFIED)) {
2696 titlebar(NULL);
2697 wrefresh(topwin);
2698 }
2699 }
2700 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002701 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002702 cutbuffer = cutbuffer_save;
2703 blank_statusbar_refresh();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002704 /* display shortcut list with UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002705 shortcut_init(0);
2706 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002707
Chris Allegretta6df90f52002-07-19 01:08:59 +00002708 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002709#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002710}
2711
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002712int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002713{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002714 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002715
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002716 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002717
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002718#ifdef ENABLE_MULTIBUFFER
2719 if (!close_open_file()) {
2720 display_main_list();
2721 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002722 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002723 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002724#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002725 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002726 }
2727
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002728 if (ISSET(TEMP_OPT))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002729 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002730 else
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002731 i = do_yesno(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002732
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002733#ifdef DEBUG
2734 dump_buffer(fileage);
2735#endif
2736
2737 if (i == 1) {
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00002738 if (do_writeout(TRUE) > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002739
2740#ifdef ENABLE_MULTIBUFFER
2741 if (!close_open_file()) {
2742 display_main_list();
2743 return 1;
2744 }
2745 else
2746#endif
2747 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002748 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002749 } else if (i == 0) {
2750
2751#ifdef ENABLE_MULTIBUFFER
2752 if (!close_open_file()) {
2753 display_main_list();
2754 return 1;
2755 }
2756 else
2757#endif
2758 finish(0);
2759 } else
2760 statusbar(_("Cancelled"));
2761
2762 display_main_list();
2763 return 1;
2764}
2765
2766void signal_init(void)
2767{
2768#ifdef _POSIX_VDISABLE
2769 struct termios term;
2770#endif
2771
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002772 /* Trap SIGINT and SIGQUIT because we want them to do useful
2773 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002774 memset(&act, 0, sizeof(struct sigaction));
2775 act.sa_handler = SIG_IGN;
2776 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002777 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002778
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002779 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002780 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002781 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002782 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002783
2784#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002785 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002786 act.sa_handler = handle_sigwinch;
2787 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002788 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002789#endif
2790
2791#ifdef _POSIX_VDISABLE
2792 tcgetattr(0, &term);
2793
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002794 if (!ISSET(PRESERVE)) {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002795 /* Trap XOFF (^S) and XON (^Q), much to Chris' chagrin, because
2796 * we want to block them. */
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002797 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2798 term.c_cc[VSTART] = _POSIX_VDISABLE;
2799 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002800#ifdef VDSUSP
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002801 /* Trap delayed suspend (^Y) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002802 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002803#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002804
2805#endif /* _POSIX_VDISABLE */
2806
2807 if (!ISSET(SUSPEND)) {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002808 /* Trap normal suspend (^Z) so we can handle it ourselves. If
2809 * we can't trap the key, trap the signal instead. Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002810#ifdef _POSIX_VDISABLE
2811 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2812#else
2813 act.sa_handler = SIG_IGN;
2814 sigaction(SIGTSTP, &act, NULL);
2815#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002816 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002817 /* Block all other signals in the suspend and continue handlers.
2818 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002819 sigfillset(&act.sa_mask);
2820
2821 act.sa_handler = do_suspend;
2822 sigaction(SIGTSTP, &act, NULL);
2823
2824 act.sa_handler = do_cont;
2825 sigaction(SIGCONT, &act, NULL);
2826 }
2827
2828#ifdef _POSIX_VDISABLE
2829 tcsetattr(0, TCSANOW, &term);
2830#endif
2831}
2832
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002833/* Handler for SIGHUP and SIGTERM. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002834RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002835{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002836 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002837}
2838
2839/* What do we do when we catch the suspend signal */
2840RETSIGTYPE do_suspend(int signal)
2841{
2842 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002843 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002844 fflush(stdout);
2845
2846 /* Restore the terminal settings for the disabled keys */
2847 tcsetattr(0, TCSANOW, &oldterm);
2848
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002849 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
2850 suspended */
2851 act.sa_handler = handle_hupterm;
2852 sigaction(SIGHUP, &act, NULL);
2853 sigaction(SIGTERM, &act, NULL);
2854
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002855 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002856 then we could be (and were) interrupted in the middle of the call.
2857 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002858 kill(0, SIGSTOP);
2859}
2860
2861/* Restore the suspend handler when we come back into the prog */
2862RETSIGTYPE do_cont(int signal)
2863{
2864 /* Now we just update the screen instead of having to reenable the
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002865 * SIGTSTP handler. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002866 doupdate();
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002867
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002868#ifndef NANO_SMALL
2869 /* Perhaps the user resized the window while we slept. */
2870 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002871#else
2872 /* Set up the signal handlers again, so that the special control
2873 * keys all work the same as before. */
2874 signal_init();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002875#endif
2876}
2877
2878#ifndef NANO_SMALL
2879void handle_sigwinch(int s)
2880{
2881 const char *tty = ttyname(0);
2882 int fd;
2883 int result = 0;
2884 struct winsize win;
2885
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002886 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002887 return;
2888 fd = open(tty, O_RDWR);
2889 if (fd == -1)
2890 return;
2891 result = ioctl(fd, TIOCGWINSZ, &win);
2892 close(fd);
2893 if (result == -1)
2894 return;
2895
2896 /* Could check whether the COLS or LINES changed, and return
2897 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2898 * variables, and in some cases ncurses has already updated them.
2899 * But not in all cases, argh. */
2900 COLS = win.ws_col;
2901 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002902 editwinrows = LINES - 5 + no_help();
2903 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002904 die_too_small();
2905
2906#ifndef DISABLE_WRAPJUSTIFY
2907 fill = wrap_at;
2908 if (fill <= 0)
2909 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002910 if (fill < 0)
2911 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002912#endif
2913
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002914 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002915 memset(hblank, ' ', COLS);
2916 hblank[COLS] = '\0';
2917
2918#ifdef HAVE_RESIZETERM
2919 resizeterm(LINES, COLS);
2920#ifdef HAVE_WRESIZE
2921 if (wresize(topwin, 2, COLS) == ERR)
2922 die(_("Cannot resize top win"));
2923 if (mvwin(topwin, 0, 0) == ERR)
2924 die(_("Cannot move top win"));
2925 if (wresize(edit, editwinrows, COLS) == ERR)
2926 die(_("Cannot resize edit win"));
2927 if (mvwin(edit, 2, 0) == ERR)
2928 die(_("Cannot move edit win"));
2929 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2930 die(_("Cannot resize bottom win"));
2931 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2932 die(_("Cannot move bottom win"));
2933#endif /* HAVE_WRESIZE */
2934#endif /* HAVE_RESIZETERM */
2935
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002936 display_main_list();
2937 blank_statusbar();
2938 total_refresh();
2939
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002940 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002941 curs_set(1);
2942
David Lawrence Ramseyedc1ea42004-04-07 01:07:50 +00002943 /* Put the terminal in cbreak mode (read one character at a time and
2944 * interpret the special control keys) if we can selectively disable
2945 * the special control keys. */
2946#ifdef _POSIX_VDISABLE
2947 cbreak();
2948#endif
2949
David Lawrence Ramseyd7db0a62004-04-07 00:51:41 +00002950 /* Set up the signal handlers again, so that the special control
2951 * keys all work the same as before. */
2952 signal_init();
2953
David Lawrence Ramseyedc1ea42004-04-07 01:07:50 +00002954 /* Turn the keypad on in the windows we'll be reading input from. */
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +00002955 keypad(edit, TRUE);
2956 keypad(bottomwin, TRUE);
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002957
2958 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002959 siglongjmp(jmpbuf, 1);
2960}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002961
2962void allow_pending_sigwinch(int allow)
2963{
2964 sigset_t winch;
2965 sigemptyset(&winch);
2966 sigaddset(&winch, SIGWINCH);
2967 if (allow)
2968 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2969 else
2970 sigprocmask(SIG_BLOCK, &winch, NULL);
2971}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002972#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002973
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002974/* If the NumLock key has made the keypad go awry, print an error
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +00002975 * message; hopefully we can address it later. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002976void print_numlock_warning(void)
2977{
2978 static int didmsg = 0;
2979 if (!didmsg) {
2980 statusbar(_
2981 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2982 didmsg = 1;
2983 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002984}
2985
Chris Allegrettadab017e2002-04-23 10:56:06 +00002986#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002987void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002988{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002989 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002990
Chris Allegretta658399a2001-06-14 02:54:22 +00002991 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002992 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002993
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002994 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002995 case TOGGLE_SUSPEND_KEY:
2996 signal_init();
2997 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002998#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002999 case TOGGLE_MOUSE_KEY:
3000 mouse_init();
3001 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003002#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003003 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00003004 wclear(bottomwin);
3005 wrefresh(bottomwin);
3006 window_init();
3007 edit_refresh();
3008 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00003009 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00003010 case TOGGLE_DOS_KEY:
3011 UNSET(MAC_FILE);
3012 break;
3013 case TOGGLE_MAC_KEY:
3014 UNSET(DOS_FILE);
3015 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003016#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003017 case TOGGLE_SYNTAX_KEY:
3018 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003019 break;
3020#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003021 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003022
Chris Allegretta6df90f52002-07-19 01:08:59 +00003023 /* We are assuming here that shortcut_init() above didn't free and
3024 * reallocate the toggles. */
3025 enabled = ISSET(which->flag);
3026 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3027 enabled = !enabled;
3028 statusbar("%s %s", which->desc,
3029 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003030}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003031#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003032
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003033int main(int argc, char *argv[])
3034{
3035 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003036 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003037 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003038 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003039 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003040 int keyhandled = 0; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003041 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003042 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003043
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003044#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003045 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003046#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003047#ifdef _POSIX_VDISABLE
3048 struct termios term;
3049#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003050#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003051 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003052 {"help", 0, 0, 'h'},
3053#ifdef ENABLE_MULTIBUFFER
3054 {"multibuffer", 0, 0, 'F'},
3055#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003056#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003057#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003058 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003059#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003060 {"ignorercfiles", 0, 0, 'I'},
3061#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062#ifndef DISABLE_JUSTIFY
3063 {"quotestr", 1, 0, 'Q'},
3064#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003065#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003066 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003067#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003068 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003069 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003070#ifdef ENABLE_COLOR
3071 {"syntax", 1, 0, 'Y'},
3072#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003073 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003074 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003075 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003076#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003077 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003078#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003079#ifndef DISABLE_OPERATINGDIR
3080 {"operatingdir", 1, 0, 'o'},
3081#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003082 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003083#ifndef DISABLE_WRAPJUSTIFY
3084 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003085#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003086#ifndef DISABLE_SPELLER
3087 {"speller", 1, 0, 's'},
3088#endif
3089 {"tempfile", 0, 0, 't'},
3090 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003091#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003092 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003093#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003094 {"nohelp", 0, 0, 'x'},
3095 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003096#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003097 {"backup", 0, 0, 'B'},
3098 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003099 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003100 {"mac", 0, 0, 'M'},
3101 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003102 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003103 {"autoindent", 0, 0, 'i'},
3104 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003105#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003106 {0, 0, 0, 0}
3107 };
3108#endif
3109
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003110#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003111 setlocale(LC_ALL, "");
3112 bindtextdomain(PACKAGE, LOCALEDIR);
3113 textdomain(PACKAGE);
3114#endif
3115
Chris Allegretta7662c862003-01-13 01:35:15 +00003116#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003117 /* if we don't have rcfile support, we're root, and
3118 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003119 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003120 SET(NO_WRAP);
3121#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003122
3123#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003124 while ((optchr = getopt_long(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003125 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003126#else
3127 while ((optchr =
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003128 getopt(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003129#endif
3130
3131 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003132
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003133 case 'a':
3134 case 'b':
3135 case 'e':
3136 case 'f':
3137 case 'g':
3138 case 'j':
3139 /* Pico compatibility flags */
3140 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003141#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003142 case 'B':
3143 SET(BACKUP_FILE);
3144 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003145 case 'D':
3146 SET(DOS_FILE);
3147 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003148 case 'E':
3149 backup_dir = mallocstrcpy(backup_dir, optarg);
3150 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003151#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003152#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003153 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003154 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003155 break;
3156#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003157#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003158#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003159 case 'H':
3160 SET(HISTORYLOG);
3161 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003162#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003163 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003164 SET(NO_RCFILE);
3165 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003166#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003167#ifndef NANO_SMALL
3168 case 'M':
3169 SET(MAC_FILE);
3170 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003171 case 'N':
3172 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003173 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003174#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003175#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003176 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003177 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003178 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003179#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003180#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003181 case 'R':
3182 SET(USE_REGEXP);
3183 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003184#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003185#ifndef NANO_SMALL
3186 case 'S':
3187 SET(SMOOTHSCROLL);
3188 break;
3189#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003190 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003191 {
3192 int i;
3193 char *first_error;
3194
Chris Allegretta7662c862003-01-13 01:35:15 +00003195 /* Using strtol() instead of atoi() lets us accept 0
3196 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003197 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003198 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003199 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003200 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003201 tabsize = i;
3202 if (tabsize <= 0) {
3203 fprintf(stderr, _("Tab size is too small for nano...\n"));
3204 exit(1);
3205 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003206 }
3207 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003208 case 'V':
3209 version();
3210 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003211#ifdef ENABLE_COLOR
3212 case 'Y':
3213 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3214 break;
3215#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003216 case 'c':
3217 SET(CONSTUPDATE);
3218 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003219 case 'd':
3220 SET(REBIND_DELETE);
3221 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003222#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003223 case 'i':
3224 SET(AUTOINDENT);
3225 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003226 case 'k':
3227 SET(CUT_TO_END);
3228 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003229#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003230 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003231 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003232 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003233#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003234 case 'm':
3235 SET(USE_MOUSE);
3236 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003237#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003238#ifndef DISABLE_OPERATINGDIR
3239 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003240 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003241 break;
3242#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003243 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003244 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003245 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003246#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003247 case 'r':
3248 {
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 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003259 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003260 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003261 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003262#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003263#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003264 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003265 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003266 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003267#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003268 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003269 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003270 break;
3271 case 'v':
3272 SET(VIEW_MODE);
3273 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003274#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003275 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003276 SET(NO_WRAP);
3277 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003278#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003279 case 'x':
3280 SET(NO_HELP);
3281 break;
3282 case 'z':
3283 SET(SUSPEND);
3284 break;
3285 default:
3286 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003287 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003288 }
3289
Chris Allegretta7662c862003-01-13 01:35:15 +00003290/* We've read through the command line options. Now back up the flags
3291 and values that are set, and read the rcfile(s). If the values
3292 haven't changed afterward, restore the backed-up values. */
3293#ifdef ENABLE_NANORC
3294 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003295#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003296 char *operating_dir_cpy = operating_dir;
3297#endif
3298#ifndef DISABLE_WRAPPING
3299 int wrap_at_cpy = wrap_at;
3300#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003301#ifndef NANO_SMALL
3302 char *backup_dir_cpy = backup_dir;
3303#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003304#ifndef DISABLE_JUSTIFY
3305 char *quotestr_cpy = quotestr;
3306#endif
3307#ifndef DISABLE_SPELLER
3308 char *alt_speller_cpy = alt_speller;
3309#endif
3310 int tabsize_cpy = tabsize;
3311 long flags_cpy = flags;
3312
Chris Allegretta5ec68622003-02-05 02:39:34 +00003313#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003314 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003315#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003316#ifndef NANO_SMALL
3317 backup_dir = NULL;
3318#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003319#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003320 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003321#endif
3322#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003323 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003324#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003325
3326 do_rcfile();
3327
3328#ifndef DISABLE_OPERATINGDIR
3329 if (operating_dir_cpy != NULL) {
3330 free(operating_dir);
3331 operating_dir = operating_dir_cpy;
3332 }
3333#endif
3334#ifndef DISABLE_WRAPPING
3335 if (fill_flag_used)
3336 wrap_at = wrap_at_cpy;
3337#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003338#ifndef NANO_SMALL
3339 if (backup_dir_cpy != NULL) {
3340 free(backup_dir);
3341 backup_dir = backup_dir_cpy;
3342 }
3343#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003344#ifndef DISABLE_JUSTIFY
3345 if (quotestr_cpy != NULL) {
3346 free(quotestr);
3347 quotestr = quotestr_cpy;
3348 }
3349#endif
3350#ifndef DISABLE_SPELLER
3351 if (alt_speller_cpy != NULL) {
3352 free(alt_speller);
3353 alt_speller = alt_speller_cpy;
3354 }
3355#endif
3356 if (tabsize_cpy > 0)
3357 tabsize = tabsize_cpy;
3358 flags |= flags_cpy;
3359 }
3360#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003361 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003362 SET(NO_WRAP);
3363#endif
3364#endif /* ENABLE_NANORC */
3365
Chris Allegrettad8451932003-03-11 03:50:40 +00003366#ifndef NANO_SMALL
3367 history_init();
3368#ifdef ENABLE_NANORC
3369 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3370 load_history();
3371#endif
3372#endif
3373
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003374#ifndef NANO_SMALL
3375 /* Set up the backup directory. This entails making sure it exists
3376 * and is a directory, so that backup files will be saved there. */
3377 init_backup_dir();
3378#endif
3379
Chris Allegretta7662c862003-01-13 01:35:15 +00003380#ifndef DISABLE_OPERATINGDIR
3381 /* Set up the operating directory. This entails chdir()ing there,
3382 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003383 init_operating_dir();
3384#endif
3385
Chris Allegretta7662c862003-01-13 01:35:15 +00003386#ifndef DISABLE_JUSTIFY
3387 if (quotestr == NULL)
3388#ifdef HAVE_REGEX_H
3389 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3390#else
3391 quotestr = mallocstrcpy(NULL, "> ");
3392#endif
3393#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003394
Chris Allegretta7662c862003-01-13 01:35:15 +00003395 if (tabsize == -1)
3396 tabsize = 8;
3397
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003398 /* Clear the filename we'll be using */
3399 filename = charalloc(1);
3400 filename[0] = '\0';
3401
Chris Allegretta7662c862003-01-13 01:35:15 +00003402 /* If there's a +LINE flag, it is the first non-option argument. */
3403 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3404 startline = atoi(&argv[optind][1]);
3405 optind++;
3406 }
3407 if (0 < optind && optind < argc)
3408 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003409
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003410 /* See if there's a non-option in argv (first non-option is the
3411 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003412 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003413 /* Look for the +line flag... */
3414 if (argv[optind][0] == '+') {
3415 startline = atoi(&argv[optind][1]);
3416 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003417 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003418 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003419 } else
3420 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003421 }
3422
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003423 /* Termios initialization stuff: Back up the old settings so that
3424 * they can be restored, disable SIGINT on ^C and SIGQUIT on ^\,
3425 * since we need them for Cancel and Replace, and disable
3426 * implementation-defined input processing. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003427 tcgetattr(0, &oldterm);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003428#ifdef _POSIX_VDISABLE
3429 term = oldterm;
3430 term.c_cc[VINTR] = _POSIX_VDISABLE;
3431 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3432 term.c_lflag &= ~IEXTEN;
3433 tcsetattr(0, TCSANOW, &term);
3434#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003435
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003436 /* Curses initialization stuff: Start curses, save the state of the
3437 * the terminal mode, disable translation of carriage return (^M)
3438 * into newline (^J) so we can catch the Enter key and use ^J for
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +00003439 * Justify, put the terminal in cbreak mode (read one character at a
3440 * time and interpret the special control keys) if we can selectively
3441 * disable the special control keys or raw mode (read one character
3442 * at a time and don't interpret the special control keys) if we
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003443 * can't, and turn off echoing of characters as they're typed. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003444 initscr();
3445 savetty();
3446 nonl();
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003447#ifdef _POSIX_VDISABLE
3448 cbreak();
3449#else
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003450 raw();
3451#endif
David Lawrence Ramseyd03216a2004-01-28 18:21:21 +00003452 noecho();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003453
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003454 /* Set up the global variables and the shortcuts. */
Chris Allegretta56214c62001-09-27 02:46:53 +00003455 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003456 shortcut_init(0);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003457
3458 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003459 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003460
3461#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003462 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003463#endif
3464
Chris Allegretta2a42af12000-09-12 23:02:49 +00003465 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003466#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003467 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003468#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003469
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003470#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003471 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003472#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003473 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003474 display_main_list();
3475
3476#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003477 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003478#endif
3479
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003480 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003481#ifdef ENABLE_MULTIBUFFER
3482 /* If we're using multibuffers and more than one file is specified
3483 on the command line, load them all and switch to the first one
3484 afterward */
3485 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3486 for (optind++; optind < argc; optind++) {
3487 add_open_file(1);
3488 new_file();
3489 filename = mallocstrcpy(filename, argv[optind]);
3490 open_file(filename, 0, 0);
3491 load_file(0);
3492 }
3493 open_nextfile_void();
3494 }
3495#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003496
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003497 titlebar(NULL);
3498
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003499 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003500 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003501
Chris Allegretta7662c862003-01-13 01:35:15 +00003502 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003503 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003504
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003505 /* SHUT UP GCC! */
3506 startline = 0;
3507 fill_flag_used = 0;
3508 keyhandled = 0;
3509
Chris Allegretta7662c862003-01-13 01:35:15 +00003510 /* This variable should be initialized after the sigsetjmp(), so we
3511 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003512 modify_control_seq = 0;
3513
Robert Siemborski6967eec2000-07-08 14:23:32 +00003514 edit_refresh();
3515 reset_cursor();
3516
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003517 while (TRUE) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003518 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003519
Chris Allegrettad26ab912003-01-28 01:16:47 +00003520 if (ISSET(CONSTUPDATE))
3521 do_cursorpos(1);
3522
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003523#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003524 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003525#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003526
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003527 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003528#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003529 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003530#endif
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003531 if (meta_key == TRUE) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003532 /* Check for the metaval and miscval defs... */
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003533 for (s = main_list; s != NULL; s = s->next)
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003534 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003535 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003536 if (ISSET(VIEW_MODE) && !s->viewok)
3537 print_view_warning();
3538 else {
3539 if (s->func != do_cut_text)
3540 UNSET(KEEP_CUTBUFFER);
3541 s->func();
3542 }
3543 keyhandled = 1;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003544 }
3545#ifndef NANO_SMALL
3546 if (!keyhandled)
3547 /* And for toggle switches */
3548 for (t = toggles; t != NULL; t = t->next)
3549 if (kbinput == t->val) {
3550 UNSET(KEEP_CUTBUFFER);
3551 do_toggle(t);
3552 keyhandled = 1;
3553 }
3554#endif
3555#ifdef DEBUG
3556 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
3557 kbinput);
3558#endif
3559 }
3560
3561 /* Look through the main shortcut list to see if we've hit a
3562 shortcut key or function key */
3563
3564 if (!keyhandled)
3565#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3566 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
3567#else
3568 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3569#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003570 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3571 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003572 if (ISSET(VIEW_MODE) && !s->viewok)
3573 print_view_warning();
3574 else {
3575 if (s->func != do_cut_text)
3576 UNSET(KEEP_CUTBUFFER);
3577 s->func();
3578 }
3579 keyhandled = 1;
3580 /* Break out explicitly once we successfully handle
3581 a shortcut */
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003582 break;
3583 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003584 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003585
3586 if (!keyhandled)
3587 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003588
3589#ifdef _POSIX_VDISABLE
3590 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003591 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003592 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003593 if (kbinput == NANO_CONTROL_S)
3594 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003595#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003596 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3597 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003598 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003599 keyhandled = 1;
3600
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003601 /* Catch ^Z by hand when triggered also */
3602 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003603 if (ISSET(SUSPEND))
3604 do_suspend(0);
3605 keyhandled = 1;
3606 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003607
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003608 /* Last gasp, stuff that's not in the main lists */
3609 if (!keyhandled)
3610 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003611#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003612 case KEY_MOUSE:
3613 do_mouse();
3614 break;
3615#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003616
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003617 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3618 * have been handled before we
3619 * got here */
3620 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003621 break;
3622 default:
3623#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003624 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003625#endif
3626 /* We no longer stop unhandled sequences so that people with
3627 odd character sets can type... */
3628
Chris Allegretta7662c862003-01-13 01:35:15 +00003629 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003630 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003631 else
3632 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003633 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003634
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003635 reset_cursor();
3636 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003637 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003638 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003639}