blob: 16cdd427b1fc138ee24606fc5fec05ac29e3064d [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>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/stat.h>
32#include <sys/ioctl.h>
33#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000034#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000035#include <errno.h>
36#include <ctype.h>
37#include <locale.h>
38#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000039#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000040#include "proto.h"
41#include "nano.h"
42
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000043#ifdef HAVE_TERMIOS_H
44#include <termios.h>
45#endif
46
47#ifdef HAVE_TERMIO_H
48#include <termio.h>
49#endif
50
51#ifdef HAVE_GETOPT_H
52#include <getopt.h>
53#endif
54
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000055#ifndef NANO_SMALL
56#include <setjmp.h>
57#endif
58
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000060static ssize_t fill = 0; /* Fill - where to wrap lines,
61 basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000062#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000063#ifndef DISABLE_WRAPPING
David Lawrence Ramseyce62e822004-08-05 22:10:22 +000064static bool same_line_wrap = FALSE; /* Whether wrapped text should
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000065 be prepended to the next
66 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000067#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000068
Chris Allegretta6df90f52002-07-19 01:08:59 +000069static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000070static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000071
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000072#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000073static sigjmp_buf jmpbuf; /* Used to return to mainloop after
74 SIGWINCH */
David Lawrence Ramsey22fac782004-08-05 15:16:19 +000075static int pid; /* The PID of the newly forked process
76 * in open_pipe(). It must be global
77 * because the signal handler needs
78 * it. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000079#endif
Chris Allegretta08020882001-01-29 23:37:54 +000080
David Lawrence Ramseyda141062004-05-25 19:41:11 +000081/* What we do when we're all set to exit. */
82void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000084 if (!ISSET(NO_HELP))
85 blank_bottombars();
86 else
87 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000088
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000089 wrefresh(bottomwin);
90 endwin();
91
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000092 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000093 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094
Chris Allegrettad8451932003-03-11 03:50:40 +000095#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
96 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
97 save_history();
98#endif
99
Chris Allegretta6232d662002-05-12 19:52:15 +0000100#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000101 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000102#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000103
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000104 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105}
106
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000107/* Die (gracefully?). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000108void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000109{
110 va_list ap;
111
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000112 endwin();
113 curses_ended = TRUE;
114
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000115 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000116 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000117
Chris Allegretta6df90f52002-07-19 01:08:59 +0000118 va_start(ap, msg);
119 vfprintf(stderr, msg, ap);
120 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000121
Chris Allegretta32da4562002-01-02 15:12:21 +0000122 /* save the currently loaded file if it's been modified */
123 if (ISSET(MODIFIED))
124 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000125
Chris Allegretta355fbe52001-07-14 19:32:47 +0000126#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000127 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000128 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000129 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000130
131 tmp = open_files;
132
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000133 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000134 open_files = open_files->prev;
135
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000136 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000137
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000138 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000139 currently loaded file), don't save it again */
140 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000141 /* make sure open_files->fileage and fileage, and
142 open_files->filebot and filebot, are in sync; they
143 might not be if lines have been cut from the top or
144 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000145 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000146 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000147 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000148 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000149 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000151 open_files = open_files->next;
152 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153 }
154#endif
155
Chris Allegretta6df90f52002-07-19 01:08:59 +0000156 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000157}
158
Chris Allegretta6df90f52002-07-19 01:08:59 +0000159void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000160{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000161 char *ret;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000162 bool failed = TRUE;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000163
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000164 /* If we're using restricted mode, don't write any emergency backup
165 * files, since that would allow reading from or writing to files
166 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000167 if (ISSET(RESTRICTED))
168 return;
169
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170 /* If we can't save, we have REAL bad problems, but we might as well
171 TRY. */
172 if (die_filename[0] == '\0')
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000173 die_filename = "nano";
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000175 ret = get_next_filename(die_filename);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000176 if (ret[0] != '\0')
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000177 failed = -1 == write_file(ret, TRUE, FALSE, TRUE);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000178
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000179 if (!failed)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000180 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000181 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000182 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000183
184 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000185}
186
Chris Allegrettae61e8302001-01-14 05:18:27 +0000187/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000188 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000189void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000190{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000191 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000192}
193
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000194void print_view_warning(void)
195{
196 statusbar(_("Key illegal in VIEW mode"));
197}
198
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000199/* Initialize global variables -- no better way for now. If
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000200 * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
201void global_init(bool save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000202{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000203 current_x = 0;
204 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000205
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000206 editwinrows = LINES - 5 + no_help();
207 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000208 die_too_small();
209
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000210 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000211 if (!save_cutbuffer)
212 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 current = NULL;
214 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000216 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000217 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000218
Chris Allegretta6fe61492001-05-21 12:56:25 +0000219#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000220 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000221 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000222 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000223 if (fill < 0)
224 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000225#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000226
Chris Allegretta88b09152001-05-17 11:35:43 +0000227 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000228 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000229 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000230}
231
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000232void window_init(void)
233{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000234 editwinrows = LINES - 5 + no_help();
235 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000236 die_too_small();
237
Chris Allegretta1a128af2003-01-26 04:15:56 +0000238 if (topwin != NULL)
239 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000240 if (edit != NULL)
241 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000242 if (bottomwin != NULL)
243 delwin(bottomwin);
244
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000245 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000247 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
249
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000250 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251 keypad(edit, TRUE);
252 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000253}
254
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000255#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256void mouse_init(void)
257{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000259 mousemask(BUTTON1_RELEASED, NULL);
260 mouseinterval(50);
261 } else
262 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000263}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000264#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000265
266#ifndef DISABLE_HELP
267/* This function allocates help_text, and stores the help string in it.
268 * help_text should be NULL initially. */
269void help_init(void)
270{
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000271 size_t allocsize = 1; /* Space needed for help_text. */
272 const char *htx; /* Untranslated help message. */
273 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000274 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000275#ifndef NANO_SMALL
276 const toggle *t;
277#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000278
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000279 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000280 if (currshortcut == whereis_list || currshortcut == replace_list
281 || currshortcut == replace_list_2)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000282 htx = N_("Search Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000283 "Enter the words or characters you would like to search "
284 "for, then hit enter. If there is a match for the text you "
285 "entered, the screen will be updated to the location of the "
286 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000287 "The previous search string will be shown in brackets after "
288 "the Search: prompt. Hitting Enter without entering any text "
289 "will perform the previous search.\n\n The following function "
290 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000291 else if (currshortcut == goto_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000292 htx = N_("Go To Line Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000293 "Enter the line number that you wish to go to and hit "
294 "Enter. If there are fewer lines of text than the "
295 "number you entered, you will be brought to the last line "
296 "of the file.\n\n The following function keys are "
297 "available in Go To Line mode:\n\n");
298 else if (currshortcut == insertfile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000299 htx = N_("Insert File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000300 "Type in the name of a file to be inserted into the current "
301 "file buffer at the current cursor location.\n\n "
302 "If you have compiled nano with multiple file buffer "
303 "support, and enable multiple buffers with the -F "
304 "or --multibuffer command line flags, the Meta-F toggle, or "
305 "a nanorc file, inserting a file will cause it to be "
306 "loaded into a separate buffer (use Meta-< and > to switch "
307 "between file buffers).\n\n If you need another blank "
308 "buffer, do not enter any filename, or type in a "
309 "nonexistent filename at the prompt and press "
310 "Enter.\n\n The following function keys are "
311 "available in Insert File mode:\n\n");
312 else if (currshortcut == writefile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000313 htx = N_("Write File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000314 "Type the name that you wish to save the current file "
315 "as and hit Enter to save the file.\n\n If you have "
316 "selected text with Ctrl-^, you will be prompted to "
317 "save only the selected portion to a separate file. To "
318 "reduce the chance of overwriting the current file with "
319 "just a portion of it, the current filename is not the "
320 "default in this mode.\n\n The following function keys "
321 "are available in Write File mode:\n\n");
322#ifndef DISABLE_BROWSER
323 else if (currshortcut == browser_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000324 htx = N_("File Browser Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000325 "The file browser is used to visually browse the "
326 "directory structure to select a file for reading "
327 "or writing. You may use the arrow keys or Page Up/"
328 "Down to browse through the files, and S or Enter to "
329 "choose the selected file or enter the selected "
330 "directory. To move up one level, select the directory "
331 "called \"..\" at the top of the file list.\n\n The "
332 "following function keys are available in the file "
333 "browser:\n\n");
334 else if (currshortcut == gotodir_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000335 htx = N_("Browser Go To Directory Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000336 "Enter the name of the directory you would like to "
337 "browse to.\n\n If tab completion has not been disabled, "
338 "you can use the TAB key to (attempt to) automatically "
339 "complete the directory name.\n\n The following function "
340 "keys are available in Browser Go To Directory mode:\n\n");
341#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000342#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000343 else if (currshortcut == spell_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000344 htx = N_("Spell Check Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000345 "The spell checker checks the spelling of all text "
346 "in the current file. When an unknown word is "
347 "encountered, it is highlighted and a replacement can "
348 "be edited. It will then prompt to replace every "
349 "instance of the given misspelled word in the "
350 "current file.\n\n The following other functions are "
351 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000352#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000353#ifndef NANO_SMALL
354 else if (currshortcut == extcmd_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000355 htx = N_("External Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000356 "This menu allows you to insert the output of a command "
357 "run by the shell into the current buffer (or a new "
358 "buffer in multibuffer mode).\n\n The following keys are "
359 "available in this mode:\n\n");
360#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000361 else
362 /* Default to the main help list. */
363 htx = N_(" nano help text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000364 "The nano editor is designed to emulate the functionality and "
365 "ease-of-use of the UW Pico text editor. There are four main "
366 "sections of the editor: The top line shows the program "
367 "version, the current filename being edited, and whether "
368 "or not the file has been modified. Next is the main editor "
369 "window showing the file being edited. The status line is "
370 "the third line from the bottom and shows important messages. "
371 "The bottom two lines show the most commonly used shortcuts "
372 "in the editor.\n\n "
373 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000374 "sequences are notated with a caret (^) symbol and can be "
375 "entered either by using the Control (Ctrl) key or pressing the "
376 "Esc key twice. Escape-key sequences are notated with the Meta "
377 "(M) symbol and can be entered using either the Esc, Alt or "
378 "Meta key depending on your keyboard setup. Also, pressing Esc "
379 "twice and then typing a three-digit number from 000 to 255 "
380 "will enter the character with the corresponding ASCII code. "
381 "The following keystrokes are available in the main editor "
382 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000383
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000384 htx = _(htx);
385
386 allocsize += strlen(htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000387
388 /* The space needed for the shortcut lists, at most COLS characters,
389 * plus '\n'. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000390 allocsize += (COLS < 21 ? 21 : COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000391
392#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000393 /* If we're on the main list, we also count the toggle help text.
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000394 * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
395 * plus translated text, plus '\n'. */
Chris Allegretta3a784062003-02-10 02:32:58 +0000396 if (currshortcut == main_list) {
397 size_t endislen = strlen(_("enable/disable"));
398
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000399 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000400 allocsize += 8 + strlen(t->desc) + endislen;
401 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000402#endif /* !NANO_SMALL */
403
404 /* help_text has been freed and set to NULL unless the user resized
405 * while in the help screen. */
406 free(help_text);
407
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000408 /* Allocate space for the help text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000409 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000410
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000411 /* Now add the text we want. */
412 strcpy(help_text, htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000413 ptr = help_text + strlen(help_text);
414
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000415 /* Now add our shortcut info. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000416 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000417 bool meta_shortcut = FALSE;
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000418 /* TRUE if the character in s->metaval is shown in the
419 * first column. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000420
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000421 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000422#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000423 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000424 ptr += sprintf(ptr, "%.7s", _("Up"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000425 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000426#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000427 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000428 ptr += sprintf(ptr, "^%.6s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000429 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000430 ptr += sprintf(ptr, "^?");
431 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000432 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000433 }
434#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000435 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000436 meta_shortcut = TRUE;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000437 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000438 ptr += sprintf(ptr, "M-%.5s", _("Space"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000439 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000440 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000441 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000442#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000443
444 *(ptr++) = '\t';
445
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000446 if (s->funcval != NANO_NO_KEY)
447 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000448
449 *(ptr++) = '\t';
450
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000451 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
452 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000453 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
454 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000455
456 *(ptr++) = '\t';
457
458 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000459 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000460 }
461
462#ifndef NANO_SMALL
463 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000464 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000465 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000466 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000467 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000468 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000469 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000470 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000471#endif /* !NANO_SMALL */
472
473 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000474 * help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000475 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000476}
477#endif
478
479/* Create a new filestruct node. Note that we specifically do not set
480 * prevnode->next equal to the new line. */
481filestruct *make_new_node(filestruct *prevnode)
482{
483 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
484
485 newnode->data = NULL;
486 newnode->prev = prevnode;
487 newnode->next = NULL;
488 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
489
490 return newnode;
491}
492
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000493/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000494filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000495{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000496 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000497
Chris Allegretta6df90f52002-07-19 01:08:59 +0000498 assert(src != NULL);
499
Chris Allegretta88b09152001-05-17 11:35:43 +0000500 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000501 dst->next = src->next;
502 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000503 strcpy(dst->data, src->data);
504 dst->lineno = src->lineno;
505
506 return dst;
507}
508
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000509/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000510void splice_node(filestruct *begin, filestruct *newnode, filestruct
511 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000512{
513 if (newnode != NULL) {
514 newnode->next = end;
515 newnode->prev = begin;
516 }
517 if (begin != NULL)
518 begin->next = newnode;
519 if (end != NULL)
520 end->prev = newnode;
521}
522
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000523/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000524void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000525{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000526 assert(fileptr != NULL);
527
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000528 if (fileptr->prev != NULL)
529 fileptr->prev->next = fileptr->next;
530
531 if (fileptr->next != NULL)
532 fileptr->next->prev = fileptr->prev;
533}
534
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000535/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000536void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000537{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000538 if (fileptr != NULL) {
539 if (fileptr->data != NULL)
540 free(fileptr->data);
541 free(fileptr);
542 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543}
544
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000545/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 filestruct *head; /* copy of src, top of the copied list */
549 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000550
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000552
Chris Allegretta6df90f52002-07-19 01:08:59 +0000553 prev = copy_node(src);
554 prev->prev = NULL;
555 head = prev;
556 src = src->next;
557 while (src != NULL) {
558 prev->next = copy_node(src);
559 prev->next->prev = prev;
560 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000561
Chris Allegretta6df90f52002-07-19 01:08:59 +0000562 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000563 }
564
Chris Allegretta6df90f52002-07-19 01:08:59 +0000565 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000566 return head;
567}
568
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000569/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000570void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000572 if (src != NULL) {
573 while (src->next != NULL) {
574 src = src->next;
575 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000576#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000577 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578#endif
579 }
580 delete_node(src);
581#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000582 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583#endif
584 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000585}
586
Chris Allegretta6df90f52002-07-19 01:08:59 +0000587void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000588{
589 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000590 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000591
Chris Allegretta6df90f52002-07-19 01:08:59 +0000592 assert(fileage == NULL || fileage != fileage->next);
593 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000595}
596
Chris Allegretta6df90f52002-07-19 01:08:59 +0000597void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000598{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000599 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000600 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000601 else {
602 int lineno = fileptr->prev->lineno;
603
604 assert(fileptr != fileptr->next);
605 for (; fileptr != NULL; fileptr = fileptr->next)
606 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000607 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000608}
609
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000610/* Print one usage string to the screen. This cuts down on duplicate
611 * strings to translate and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000612 * translatable (the flag names). */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000613void print1opt(const char *shortflag, const char *longflag, const char
614 *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000615{
616 printf(" %s\t", shortflag);
617 if (strlen(shortflag) < 8)
618 printf("\t");
619
620#ifdef HAVE_GETOPT_LONG
621 printf("%s\t", longflag);
622 if (strlen(longflag) < 8)
623 printf("\t\t");
624 else if (strlen(longflag) < 16)
625 printf("\t");
626#endif
627
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000628 printf("%s\n", _(desc));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000629}
630
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000631void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000632{
633#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000634 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
635 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000636#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000637 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
638 printf(_("Option\t\tMeaning\n"));
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +0000639#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000640
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000641 print1opt("-h, -?", "--help", N_("Show this message"));
642 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000643#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000644 print1opt("-A", "--smarthome", N_("Enable smart home key"));
645 print1opt("-B", "--backup", N_("Backup existing files on save"));
646 print1opt("-D", "--dos", N_("Write file in DOS format"));
647 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000648#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000649#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000650 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000651#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000652#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000653#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000654 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000655#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000656 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000657#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000658#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000659 print1opt("-M", "--mac", N_("Write file in Mac format"));
660 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000661#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000662#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000663 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000664#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000665#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000666 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000667#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000668#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000669 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000670#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000671 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
672 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000673#ifdef ENABLE_COLOR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000674 print1opt(_("-Y [str]"), _("--syntax [str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000675#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000676 print1opt("-Z", "--restricted", N_("Restricted mode"));
677 print1opt("-c", "--const", N_("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000678#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000679 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
680 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
681 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000682#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000683 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000684#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000685 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000686#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000687#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000688 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000689#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000690 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000691#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000692 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000693#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000694#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000695 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000696#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000697 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
698 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000699#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000700 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000701#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000702 print1opt("-x", "--nohelp", N_("Don't show help window"));
703 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000704
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000705 /* This is a special case. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000706 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000707
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000708 exit(0);
709}
710
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000711void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000712{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000713 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000714 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000715 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000716 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000717 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000718
Chris Allegrettae6600372003-01-17 03:39:41 +0000719#ifndef ENABLE_NLS
720 printf(" --disable-nls");
721#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000722#ifdef DEBUG
723 printf(" --enable-debug");
724#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000725#ifdef NANO_EXTRA
726 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000727#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000728#ifdef NANO_SMALL
729 printf(" --enable-tiny");
730#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000731#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000732 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000733#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000734#ifdef DISABLE_HELP
735 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000736#endif
737#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000738 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000739#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000740#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000741 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000742#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000743#ifdef DISABLE_OPERATINGDIR
744 printf(" --disable-operatingdir");
745#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000746#ifdef DISABLE_SPELLER
747 printf(" --disable-speller");
748#endif
749#ifdef DISABLE_TABCOMP
750 printf(" --disable-tabcomp");
751#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000752#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000753#ifdef DISABLE_WRAPPING
754 printf(" --disable-wrapping");
755#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000756#ifdef DISABLE_ROOTWRAP
757 printf(" --disable-wrapping-as-root");
758#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000759#ifdef ENABLE_COLOR
760 printf(" --enable-color");
761#endif
762#ifdef ENABLE_MULTIBUFFER
763 printf(" --enable-multibuffer");
764#endif
765#ifdef ENABLE_NANORC
766 printf(" --enable-nanorc");
767#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000768#ifdef USE_SLANG
769 printf(" --with-slang");
770#endif
771 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000772}
773
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000774int no_help(void)
775{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000776 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000777}
778
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000779void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000780{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000781 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000782}
783
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000784#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000785RETSIGTYPE cancel_fork(int signal)
786{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000787 if (kill(pid, SIGKILL) == -1)
788 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000789}
790
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000791/* Return TRUE on success. */
792bool open_pipe(const char *command)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000793{
794 int fd[2];
795 FILE *f;
796 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000797 /* Original and temporary handlers for
798 * SIGINT. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000799 bool sig_failed = FALSE;
800 /* sig_failed means that sigaction() failed without changing the
801 * signal handlers.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000802 *
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000803 * We use this variable since it is important to put things back
804 * when we finish, even if we get errors. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000805
806 /* Make our pipes. */
807
808 if (pipe(fd) == -1) {
809 statusbar(_("Could not pipe"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000810 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000811 }
812
813 /* Fork a child. */
814
815 if ((pid = fork()) == 0) {
816 close(fd[0]);
817 dup2(fd[1], fileno(stdout));
818 dup2(fd[1], fileno(stderr));
819 /* If execl() returns at all, there was an error. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000820
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000821 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000822 exit(0);
823 }
824
825 /* Else continue as parent. */
826
827 close(fd[1]);
828
829 if (pid == -1) {
830 close(fd[0]);
831 statusbar(_("Could not fork"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000832 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000833 }
834
835 /* Before we start reading the forked command's output, we set
836 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000837
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000838 /* Enable interpretation of the special control keys so that we get
839 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000840 enable_signals();
841
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000842 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000843 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000844 nperror("sigaction");
845 } else {
846 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000847 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000848 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000849 nperror("sigaction");
850 }
851 }
852 /* Note that now oldaction is the previous SIGINT signal handler,
853 * to be restored later. */
854
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000855 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000856 if (f == NULL)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000857 nperror("fdopen");
David Lawrence Ramsey00d77982004-08-07 21:27:37 +0000858
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000859 read_file(f, "stdin", FALSE);
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000860 /* If multibuffer mode is on, we could be here in view mode. If so,
861 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000862 if (!ISSET(VIEW_MODE))
863 set_modified();
864
865 if (wait(NULL) == -1)
866 nperror("wait");
867
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000868 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000869 nperror("sigaction");
870
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000871 /* Disable interpretation of the special control keys so that we can
872 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000873 disable_signals();
874
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000875 return TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000876}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000877#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000878
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000879#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000880void do_mouse(void)
881{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000882 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000883
David Lawrence Ramsey4d44d2d2004-08-01 22:35:31 +0000884 if (!get_mouseinput(&mouse_x, &mouse_y, TRUE)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000885 /* Click in the edit window to move the cursor, but only when
886 we're not in a subfunction. */
887 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000888 bool sameline;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000889 /* Did they click on the line with the cursor? If they
890 clicked on the cursor, we set the mark. */
891 size_t xcur;
892 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000893
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000894 /* Subtract out size of topwin. Perhaps we need a constant
895 somewhere? */
896 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000897
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000898 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000899
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000900 /* Move to where the click occurred. */
901 for (; current_y < mouse_y && current->next != NULL; current_y++)
902 current = current->next;
903 for (; current_y > mouse_y && current->prev != NULL; current_y--)
904 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000905
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000906 xcur = actual_x(current->data, get_page_start(xplustabs()) +
907 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000908
David Lawrence Ramsey00d77982004-08-07 21:27:37 +0000909#ifndef NANO_SMALL
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000910 /* Selecting where the cursor is toggles the mark, as does
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000911 selecting beyond the line length with the cursor at the
912 end of the line. */
913 if (sameline && xcur == current_x) {
914 if (ISSET(VIEW_MODE)) {
915 print_view_warning();
916 return;
917 }
918 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000919 }
David Lawrence Ramsey00d77982004-08-07 21:27:37 +0000920#endif
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000921
922 current_x = xcur;
923 placewewant = xplustabs();
924 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000925 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000926 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000927 /* FIXME: If we clicked on a location in the statusbar, the cursor
928 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000929}
930#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000931
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000932/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000933void do_char(char ch)
934{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000935 size_t current_len = strlen(current->data);
936#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000937 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000938 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +0000939 * update_line()? */
940#endif
941
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000942 if (ch == '\0') /* Null to newline, if needed. */
943 ch = '\n';
944 else if (ch == '\n') { /* Newline to Enter, if needed. */
945 do_enter();
946 return;
947 }
948
949 assert(current != NULL && current->data != NULL);
950
951 /* When a character is inserted on the current magicline, it means
952 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000953 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000954 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000955
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000956 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000957 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000958 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000959 charmove(&current->data[current_x + 1], &current->data[current_x],
960 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000961 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000962 totsize++;
963 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000964
Chris Allegretta6df90f52002-07-19 01:08:59 +0000965#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000966 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000967 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000968 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000969#endif
970
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000971 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000972
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000973#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000974 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +0000975 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000976 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000977#endif
978
Chris Allegretta6df90f52002-07-19 01:08:59 +0000979#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000980 /* If color syntaxes are turned on, we need to call
981 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000982 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000983 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000984#endif
985
986#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000987 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000988 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000989 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000990#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000991 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000992}
993
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000994void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000995{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000996 int *v_kbinput = NULL; /* Used to hold verbatim input. */
997 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000998 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000999
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001000 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001001
1002 v_kbinput = get_verbatim_kbinput(edit, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001003
1004 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1005 * off afterwards, so that if constant cursor position display is
1006 * on, it will be updated properly. */
1007 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001008 for (i = 0; i < v_len; i++)
1009 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001010 UNSET(DISABLE_CURPOS);
1011
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001012 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001013}
1014
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001015void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001016{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001017 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001018 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001019 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001020 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001021}
1022
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001023void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001024{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001025 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001026 /* Do we have to call edit_refresh(), or can we get away with
1027 * update_line()? */
1028
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001029 assert(current != NULL && current->data != NULL && current_x <=
1030 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001031
1032 placewewant = xplustabs();
1033
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001034 if (current->data[current_x] != '\0') {
1035 size_t linelen = strlen(current->data + current_x);
1036
1037 assert(current_x < strlen(current->data));
1038
1039 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001040 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001041 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001042
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001043 null_at(&current->data, linelen + current_x - 1);
1044#ifndef NANO_SMALL
1045 if (current_x < mark_beginx && mark_beginbuf == current)
1046 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001047#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001048 } else if (current != filebot && (current->next != filebot ||
1049 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001050 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001051 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001052 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001053
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001054 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001055
1056 /* If we're deleting at the end of a line, we need to call
1057 * edit_refresh(). */
1058 if (current->data[current_x] == '\0')
1059 do_refresh = TRUE;
1060
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001061 current->data = charealloc(current->data, current_x +
1062 strlen(foo->data) + 1);
1063 strcpy(current->data + current_x, foo->data);
1064#ifndef NANO_SMALL
1065 if (mark_beginbuf == current->next) {
1066 mark_beginx += current_x;
1067 mark_beginbuf = current;
1068 }
1069#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001070 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001071 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001072
1073 unlink_node(foo);
1074 delete_node(foo);
1075 renumber(current);
1076 totlines--;
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001077#ifndef DISABLE_WRAPPING
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001078 wrap_reset();
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001079#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001080 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001081 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001082
1083 totsize--;
1084 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001085
1086#ifdef ENABLE_COLOR
1087 /* If color syntaxes are turned on, we need to call
1088 * edit_refresh(). */
1089 if (ISSET(COLOR_SYNTAX))
1090 do_refresh = TRUE;
1091#endif
1092
1093 if (do_refresh)
1094 edit_refresh();
1095 else
1096 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001097}
1098
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001099void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001100{
1101 do_char('\t');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001102}
1103
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001104/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001105void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001106{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001107 filestruct *newnode = make_new_node(current);
1108 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001109
Chris Allegretta6df90f52002-07-19 01:08:59 +00001110 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001111
Chris Allegrettaff989832001-09-17 13:48:00 +00001112#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001113 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001114 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001115 /* If we are breaking the line in the indentation, the new
1116 * indentation should have only current_x characters, and
1117 * current_x should not change. */
1118 extra = indent_length(current->data);
1119 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001120 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001121 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001122 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001123#endif
1124 newnode->data = charalloc(strlen(current->data + current_x) +
1125 extra + 1);
1126 strcpy(&newnode->data[extra], current->data + current_x);
1127#ifndef NANO_SMALL
1128 if (ISSET(AUTOINDENT))
1129 strncpy(newnode->data, current->data, extra);
1130#endif
1131 null_at(&current->data, current_x);
1132#ifndef NANO_SMALL
1133 if (current == mark_beginbuf && current_x < mark_beginx) {
1134 mark_beginbuf = newnode;
1135 mark_beginx += extra - current_x;
1136 }
1137#endif
1138 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001139
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001140 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001141 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001142 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001143
1144 totsize++;
1145 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001146 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001147
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001148 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001149
1150 totlines++;
1151 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001152 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001153}
1154
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001155#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001156void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001157{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001158 size_t old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001159 const filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001160 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001161
Chris Allegretta6df90f52002-07-19 01:08:59 +00001162 /* Skip letters in this word first. */
1163 while (current->data[current_x] != '\0' &&
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001164 isalnum((int)current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001165 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001166
Chris Allegretta6df90f52002-07-19 01:08:59 +00001167 for (; current != NULL; current = current->next) {
1168 while (current->data[current_x] != '\0' &&
1169 !isalnum((int)current->data[current_x]))
1170 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001171
Chris Allegretta6df90f52002-07-19 01:08:59 +00001172 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173 break;
1174
Chris Allegretta6df90f52002-07-19 01:08:59 +00001175 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001176 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001177 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001179
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001181
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001182 /* Refresh the screen. If current has run off the bottom, this
1183 * call puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001184 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001185}
1186
Chris Allegretta6df90f52002-07-19 01:08:59 +00001187/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001188void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001189{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001190 size_t old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001191 const filestruct *current_save = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001192 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001193
Chris Allegretta6df90f52002-07-19 01:08:59 +00001194 /* Skip letters in this word first. */
1195 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1196 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001197
Chris Allegretta6df90f52002-07-19 01:08:59 +00001198 for (; current != NULL; current = current->prev) {
1199 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1200 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001201
Chris Allegretta6df90f52002-07-19 01:08:59 +00001202 if (current_x >= 0)
1203 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001204
Chris Allegretta6df90f52002-07-19 01:08:59 +00001205 if (current->prev != NULL)
1206 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001207 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001208
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001209 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001210 current = fileage;
1211 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001212 } else {
1213 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1214 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001215 }
1216
Chris Allegretta76e291b2001-10-14 19:05:10 +00001217 placewewant = xplustabs();
1218
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001219 /* Refresh the screen. If current has run off the top, this call
1220 * puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001221 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001222}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001223
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001224void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001225{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001226 TOGGLE(MARK_ISSET);
1227 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001228 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001229 mark_beginbuf = current;
1230 mark_beginx = current_x;
1231 } else {
1232 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001233 edit_refresh();
1234 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001235}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001236#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001237
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001238#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001239void wrap_reset(void)
1240{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001241 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001242}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001243#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001244
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001245#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001246/* We wrap the given line. Precondition: we assume the cursor has been
1247 * moved forward since the last typed character. Return value: whether
1248 * we wrapped. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001249bool do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001250{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001251 size_t len = strlen(inptr->data);
1252 /* Length of the line we wrap. */
1253 size_t i = 0;
1254 /* Generic loop variable. */
1255 int wrap_loc = -1;
1256 /* Index of inptr->data where we wrap. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001257 int word_back = -1;
1258#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001259 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001260 /* Indentation to prepend to the new line. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001261 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001262#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001263 const char *after_break; /* Text after the wrap point. */
1264 size_t after_break_len; /* strlen(after_break) */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001265 bool wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001266 const char *wrap_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001267 /* The next line, minus indentation. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001268 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1269 char *newline = NULL; /* The line we create. */
1270 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001271
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001272/* There are three steps. First, we decide where to wrap. Then, we
1273 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001274
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001275/* Step 1, finding where to wrap. We are going to add a new line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001276 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001277 * location of this replacement.
1278 *
1279 * Where should we break the line? We need the last "legal wrap point"
1280 * such that the last word before it ended at or before fill. If there
1281 * is no such point, we settle for the first legal wrap point.
1282 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001283 * A "legal wrap point" is a whitespace character that is not followed
1284 * by whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001285 *
1286 * If there is no legal wrap point or we found the last character of the
1287 * line, we should return without wrapping.
1288 *
1289 * Note that the initial indentation does not count as a legal wrap
1290 * point if we are going to auto-indent!
1291 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001292 * Note that the code below could be optimized, by not calling
1293 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001294
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001295#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001296 if (ISSET(AUTOINDENT))
1297 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001298#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001299 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001300 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001301 /* Record where the last word ended. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001302 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001303 word_back = i;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001304 /* If we have found a "legal wrap point" and the current word
1305 * extends too far, then we stop. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001306 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001307 break;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001308 /* We record the latest "legal wrap point". */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001309 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001310 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001311 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001312 if (i == len)
1313 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001314
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001315 /* Step 2, making the new wrap line. It will consist of indentation
1316 * + after_break + " " + wrap_line (although indentation and
1317 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001318
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001319 /* after_break is the text that will be moved to the next line. */
1320 after_break = inptr->data + wrap_loc + 1;
1321 after_break_len = len - wrap_loc - 1;
1322 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001323
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001324 /* new_line_len will later be increased by the lengths of indentation
1325 * and wrap_line. */
1326 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001327
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001328 /* We prepend the wrapped text to the next line, if the flag is set,
1329 * and there is a next line, and prepending would not make the line
1330 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001331 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001332 wrap_line = inptr->next->data;
1333 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001334
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001335 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001336 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001337 wrapping = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001338 new_line_len += (1 + wrap_line_len);
1339 }
1340 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001341
Chris Allegrettaff989832001-09-17 13:48:00 +00001342#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001343 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001344 /* Indentation comes from the next line if wrapping, else from
1345 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001346 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001347 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001348 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001349 /* The wrap_line text should not duplicate indentation.
1350 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001351 wrap_line += indent_len;
1352 else
1353 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001354 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001355#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001356
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001357 /* Now we allocate the new line and copy into it. */
1358 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001359 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001360 *newline = '\0';
1361
1362#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001363 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001364 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001365 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001366 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001367 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001368#endif
1369 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001370 new_line_len += after_break_len;
1371 /* We end the old line after wrap_loc. Note that this does not eat
1372 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001373 null_at(&inptr->data, wrap_loc + 1);
1374 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001375 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001376 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001377 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001378 * in a tab or a space, we don't add a space and decrement
1379 * totsize to account for that. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001380 if (!isblank(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001381 strcat(newline, " ");
1382 else
1383 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001384 strcat(newline, wrap_line);
1385 free(inptr->next->data);
1386 inptr->next->data = newline;
1387 } else {
1388 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001389
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001390 /* In this case, the file size changes by +1 for the new line,
1391 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001392#ifndef NANO_SMALL
1393 totsize += indent_len;
1394#endif
1395 totlines++;
1396 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001397 temp->prev = inptr;
1398 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001399 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001400 /* If temp->next is NULL, then temp is the last line of the
1401 * file, so we must set filebot. */
1402 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001403 temp->next->prev = temp;
1404 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001405 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001406 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001407
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001408 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1409 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001410
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001411 /* Later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001412 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001413
1414 /* Each line knows its line number. We recalculate these if we
1415 * inserted a new line. */
1416 if (!wrapping)
1417 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001418
Chris Allegretta6df90f52002-07-19 01:08:59 +00001419 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001421 current = current->next;
1422 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001423#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001424 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001425#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001426 wrap_loc + 1;
1427 wrap_reset();
1428 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001429 }
1430
Chris Allegretta6df90f52002-07-19 01:08:59 +00001431#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001432 /* If the mark was on this line after the wrap point, we move it
1433 * down. If it was on the next line and we wrapped, we move it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001434 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001435 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1436 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001437 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001438 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001439 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001440#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001441
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001442 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001443}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001444#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001445
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001446#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001447/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001448 * return FALSE if the user cancels. */
1449bool do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001450{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001451 char *save_search;
1452 char *save_replace;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001453 size_t current_x_save = current_x;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001454 filestruct *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001455 filestruct *edittop_save = edittop;
1456 /* Save where we are. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001457 bool accepted = TRUE;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001458 /* The return value. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001459 bool reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001460#ifndef NANO_SMALL
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001461 bool case_sens_set = ISSET(CASE_SENSITIVE);
1462 bool mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001463
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001464 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001465 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001466 UNSET(MARK_ISSET);
1467#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001468 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001469 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001470
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001471 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001472 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001473 save_search = last_search;
1474 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001475
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001476 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001477 last_search = mallocstrcpy(NULL, word);
1478 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001479
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001480 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001481 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001482 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001483
1484 search_last_line = FALSE;
1485
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001486 /* Find the first whole-word occurrence of word. */
1487 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001488 if (is_whole_word(current_x, current->data, word)) {
1489 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001490
Chris Allegretta6df90f52002-07-19 01:08:59 +00001491 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001492
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001493 /* Allow the replace word to be corrected. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001494 accepted = -1 != statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001495#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001496 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001497#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001498 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001499
Chris Allegretta6df90f52002-07-19 01:08:59 +00001500 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001501
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001502 if (accepted && strcmp(word, answer) != 0) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001503 search_last_line = FALSE;
1504 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001505 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001506 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001507
1508 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001509 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001510
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001511 /* Restore the search/replace strings. */
1512 free(last_search);
1513 last_search = save_search;
1514 free(last_replace);
1515 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001516
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001517 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001518 current = current_save;
1519 current_x = current_x_save;
1520 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001521
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001522 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001523 if (reverse_search_set)
1524 SET(REVERSE_SEARCH);
1525
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001526#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001527 if (!case_sens_set)
1528 UNSET(CASE_SENSITIVE);
1529
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001530 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001531 if (mark_set)
1532 SET(MARK_ISSET);
1533#endif
1534
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001535 return accepted;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001536}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001537
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001538/* Integrated spell checking using 'spell' program. Return value: NULL
1539 * for normal termination, otherwise the error string. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001540const char *do_int_speller(const char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001541{
Chris Allegretta271e9722000-11-10 18:15:43 +00001542 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001543 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001544 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001545 pid_t pid_spell, pid_sort, pid_uniq;
1546 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001547
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001548 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001549 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1550 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001551
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001552 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001553
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001554 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001555 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001556
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001557 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001558
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001559 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001560
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001561 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001562 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1563 goto close_pipes_and_exit;
1564
1565 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1566 goto close_pipes_and_exit;
1567
Chris Allegretta271e9722000-11-10 18:15:43 +00001568 close(tempfile_fd);
1569
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001570 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001571 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1572 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001573
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001574 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001575
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001576 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001577 execlp("spell", "spell", NULL);
1578
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001579 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001580 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001581 }
1582
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001583 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001584 close(spell_fd[1]);
1585
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001586 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001587 if ((pid_sort = fork()) == 0) {
1588
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001589 /* Child continues (i.e, future spell process). Replace the
1590 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001591 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1592 goto close_pipes_and_exit;
1593
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001594 close(spell_fd[0]);
1595
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001596 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001597 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1598 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001599
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001600 close(sort_fd[1]);
1601
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001602 /* Start sort program. Use -f to remove mixed case without
1603 * having to have ANOTHER pipe for tr. If this isn't portable,
1604 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001605 execlp("sort", "sort", "-f", NULL);
1606
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001607 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001608 exit(1);
1609 }
1610
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001611 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001612 close(sort_fd[1]);
1613
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001614 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001615 if ((pid_uniq = fork()) == 0) {
1616
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001617 /* Child continues (i.e, future uniq process). Replace the
1618 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001619 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1620 goto close_pipes_and_exit;
1621
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001622 close(sort_fd[0]);
1623
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001624 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001625 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1626 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001627
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001628 close(uniq_fd[1]);
1629
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001630 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001631 execlp("uniq", "uniq", NULL);
1632
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001633 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001634 exit(1);
1635 }
1636
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001637 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001638 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001639
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001640 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001641 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1642 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001643 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001644 }
1645
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001646 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001647 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1648 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001649 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001650 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001651
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001652 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001653 read_buff_read = 0;
1654 read_buff_size = pipe_buff_size + 1;
1655 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001656
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001657 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001658 read_buff_read += bytesread;
1659 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001660 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001661 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001662
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001663 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001664
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001665 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001666 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001667
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001668 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001669 read_buff_word = read_buff_ptr = read_buff;
1670
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001671 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001672
1673 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001674 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001675 if (read_buff_word != read_buff_ptr) {
1676 if (!do_int_spell_fix(read_buff_word)) {
1677 read_buff_word = read_buff_ptr;
1678 break;
1679 }
1680 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001681 read_buff_word = read_buff_ptr + 1;
1682 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001683 read_buff_ptr++;
1684 }
1685
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001686 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001687 if (read_buff_word != read_buff_ptr)
1688 do_int_spell_fix(read_buff_word);
1689
Chris Allegretta271e9722000-11-10 18:15:43 +00001690 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001691 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001692 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001693
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001694 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001695 waitpid(pid_spell, &spell_status, 0);
1696 waitpid(pid_sort, &sort_status, 0);
1697 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001698
Chris Allegretta334a9402002-12-16 04:25:53 +00001699 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1700 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001701
Chris Allegretta334a9402002-12-16 04:25:53 +00001702 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1703 return _("Error invoking \"sort -f\"");
1704
1705 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1706 return _("Error invoking \"uniq\"");
1707
1708 /* Otherwise... */
1709 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001710
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001711 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001712
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001713 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001714 close(tempfile_fd);
1715 close(spell_fd[0]);
1716 close(spell_fd[1]);
1717 close(sort_fd[0]);
1718 close(sort_fd[1]);
1719 close(uniq_fd[0]);
1720 close(uniq_fd[1]);
1721 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001722}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001723
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001724/* External spell checking. Return value: NULL for normal termination,
1725 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001726const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001727{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001728 int alt_spell_status, lineno_cur = current->lineno;
David Lawrence Ramsey360093a2004-07-28 20:53:55 +00001729 int x_cur = current_x, y_cur = current_y;
1730 size_t pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001731 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001732 char *ptr;
1733 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001734 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001735#ifndef NANO_SMALL
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001736 bool mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001737 int mbb_lineno_cur = 0;
1738 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001739 * the alternate spell command. The line that mark_beginbuf
1740 * points to will be freed, so we save the line number and
1741 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001742
1743 if (mark_set) {
1744 mbb_lineno_cur = mark_beginbuf->lineno;
1745 UNSET(MARK_ISSET);
1746 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001747#endif
1748
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001749 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001750
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001751 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001752 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001753 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001754
Chris Allegrettae434b452001-01-27 19:25:00 +00001755 spellargs[0] = strtok(alt_speller, " ");
1756 while ((ptr = strtok(NULL, " ")) != NULL) {
1757 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001758 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001759 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001760 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001761 spellargs[arglen - 1] = NULL;
1762 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001763 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001764
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001765 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001766 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001767 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001768 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001769
1770 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001771 exit(1);
1772 }
1773
1774 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001775 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001776 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001777
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001778 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001779 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001780
Chris Allegretta334a9402002-12-16 04:25:53 +00001781 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1782 char *altspell_error = NULL;
1783 char *invoke_error = _("Could not invoke \"%s\"");
1784 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1785
1786 altspell_error = charalloc(msglen);
1787 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1788 return altspell_error;
1789 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001790
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001791 refresh();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001792
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001793#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001794 if (mark_set) {
1795 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1796 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001797 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001798 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001799 SET(MARK_ISSET);
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001800 } else {
1801#endif
1802 /* Only reload the temp file if it isn't a marked selection. */
1803 free_filestruct(fileage);
1804 terminal_init();
1805 global_init(TRUE);
1806 open_file(tempfile_name, FALSE, TRUE);
1807#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001808 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001809#endif
1810
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001811 /* Go back to the old position, mark the file as modified, and make
1812 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001813 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001814 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001815 clearok(topwin, FALSE);
1816 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001817
Chris Allegretta334a9402002-12-16 04:25:53 +00001818 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001819}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001820
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001821void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001822{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001823 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001824 char *temp = safe_tempnam(0, "nano.");
1825 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001826
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001827 if (temp == NULL) {
1828 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001829 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00001830 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001831
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001832#ifndef NANO_SMALL
1833 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001834 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001835 else
1836#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001837 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001838
1839 if (i == -1) {
David Lawrence Ramsey95e39e52004-08-12 02:52:14 +00001840 statusbar(_("Error writing temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001841 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001842 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001843 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001844
Chris Allegrettae1f14522001-09-19 03:19:43 +00001845#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001846 /* Update the current open_files entry before spell-checking, in
1847 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001848 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001849#endif
1850
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001851 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1852 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001853 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001854 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001855
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001856 if (spell_msg != NULL)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001857 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1858 strerror(errno));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001859 else
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001860 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00001861}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001862#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001863
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001864#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001865/* The "indentation" of a line is the whitespace between the quote part
1866 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001867size_t indent_length(const char *line)
1868{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001869 size_t len = 0;
1870
1871 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001872 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001873 line++;
1874 len++;
1875 }
1876 return len;
1877}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001878#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001879
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001880#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001881/* justify_format() replaces Tab by Space and multiple spaces by 1
1882 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001883 * counts as a space.
1884 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001885 * justify_format() might make line->data shorter, and change the actual
1886 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001887 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001888 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001889 * skip should be at most strlen(line->data). The character at
1890 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001891void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001892{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001893 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001894
Chris Allegretta6df90f52002-07-19 01:08:59 +00001895 /* These four asserts are assumptions about the input data. */
1896 assert(line != NULL);
1897 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001898 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001899 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001900
Chris Allegretta6df90f52002-07-19 01:08:59 +00001901 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001902 for (front = back; ; front++) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001903 bool remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001904 /* Do we want to remove this space? */
1905
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001906 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001907 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001908
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001909 /* These tests are safe since line->data + skip is not a
1910 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001911 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001912 const char *bob = front - 2;
1913
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001914 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001915 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001916 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001917 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001918 break;
1919 }
1920 if (strchr(brackets, *bob) == NULL)
1921 break;
1922 }
1923 }
1924
1925 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001926 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001927 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001928#ifndef NANO_SMALL
1929 if (mark_beginbuf == line && back - line->data < mark_beginx)
1930 mark_beginx--;
1931#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001932 if (*front == '\0')
1933 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001934 } else {
1935 *back = *front;
1936 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001937 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001938 if (*front == '\0')
1939 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001940 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001941
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001942 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001943 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001944
Chris Allegretta6df90f52002-07-19 01:08:59 +00001945 /* Now back is the new end of line->data. */
1946 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001947 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001948 null_at(&line->data, back - line->data);
1949#ifndef NANO_SMALL
1950 if (mark_beginbuf == line && back - line->data < mark_beginx)
1951 mark_beginx = back - line->data;
1952#endif
1953 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001954}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001955
1956/* The "quote part" of a line is the largest initial substring matching
1957 * the quote string. This function returns the length of the quote part
1958 * of the given line.
1959 *
1960 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1961 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001962size_t quote_length(const char *line)
1963{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001964#ifdef HAVE_REGEX_H
1965 regmatch_t matches;
1966 int rc = regexec(&quotereg, line, 1, &matches, 0);
1967
1968 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1969 return 0;
1970 /* matches.rm_so should be 0, since the quote string should start
1971 * with the caret ^. */
1972 return matches.rm_eo;
1973#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001974 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001975
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001976 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001977 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001978 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001979 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001980#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001981}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001982
Chris Allegretta6df90f52002-07-19 01:08:59 +00001983/* a_line and b_line are lines of text. The quotation part of a_line is
1984 * the first a_quote characters. Check that the quotation part of
1985 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001986bool quotes_match(const char *a_line, size_t a_quote, const char
1987 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001988{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001989 /* Here is the assumption about a_quote: */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001990 assert(a_quote == quote_length(a_line));
1991 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001992 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001993}
1994
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001995/* We assume a_line and b_line have no quote part. Then, we return
1996 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001997bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001998 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001999{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002000 assert(a_indent == indent_length(a_line));
2001 assert(b_indent == indent_length(b_line));
2002
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002003 return b_indent <= a_indent &&
2004 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002005}
2006
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002007/* Is foo the beginning of a paragraph?
2008 *
2009 * A line of text consists of a "quote part", followed by an
2010 * "indentation part", followed by text. The functions quote_length()
2011 * and indent_length() calculate these parts.
2012 *
2013 * A line is "part of a paragraph" if it has a part not in the quote
2014 * part or the indentation.
2015 *
2016 * A line is "the beginning of a paragraph" if it is part of a
2017 * paragraph and
2018 * 1) it is the top line of the file, or
2019 * 2) the line above it is not part of a paragraph, or
2020 * 3) the line above it does not have precisely the same quote
2021 * part, or
2022 * 4) the indentation of this line is not an initial substring of
2023 * the indentation of the previous line, or
2024 * 5) this line has no quote part and some indentation, and
2025 * AUTOINDENT is not set.
2026 * The reason for number 5) is that if AUTOINDENT is not set, then an
2027 * indented line is expected to start a paragraph, like in books.
2028 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2029 * turned on. */
2030bool begpar(const filestruct *const foo)
2031{
2032 size_t quote_len;
2033 size_t indent_len;
2034 size_t temp_id_len;
2035
2036 /* Case 1). */
2037 if (foo->prev == NULL)
2038 return TRUE;
2039
2040 quote_len = quote_length(foo->data);
2041 indent_len = indent_length(foo->data + quote_len);
2042
2043 /* Not part of a paragraph. */
2044 if (foo->data[quote_len + indent_len] == '\0')
2045 return FALSE;
2046
2047 /* Case 3). */
2048 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2049 return TRUE;
2050
2051 temp_id_len = indent_length(foo->prev->data + quote_len);
2052
2053 /* Case 2) or 5) or 4). */
2054 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2055 (quote_len == 0 && indent_len > 0
2056#ifndef NANO_SMALL
2057 && !ISSET(AUTOINDENT)
2058#endif
2059 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2060 foo->data + quote_len, indent_len))
2061 return TRUE;
2062
2063 return FALSE;
2064}
2065
2066/* We find the last beginning-of-paragraph line before the current
2067 * line. */
2068void do_para_begin(void)
2069{
2070 const filestruct *old_current = current;
2071 const size_t old_pww = placewewant;
2072
2073 current_x = 0;
2074 placewewant = 0;
2075
2076 if (current->prev != NULL) {
2077 do {
2078 current = current->prev;
2079 } while (!begpar(current));
2080 }
2081
2082 edit_redraw(old_current, old_pww);
2083}
2084
2085bool inpar(const char *str)
2086{
2087 size_t quote_len = quote_length(str);
2088
2089 return str[quote_len + indent_length(str + quote_len)] != '\0';
2090}
2091
2092/* A line is the last line of a paragraph if it is in a paragraph, and
2093 * the next line isn't, or is the beginning of a paragraph. We move
2094 * down to the end of a paragraph, then one line farther. */
2095void do_para_end(void)
2096{
2097 const filestruct *const old_current = current;
2098 const size_t old_pww = placewewant;
2099
2100 current_x = 0;
2101 placewewant = 0;
2102
2103 while (current->next != NULL && !inpar(current->data))
2104 current = current->next;
2105
2106 while (current->next != NULL && inpar(current->next->data) &&
2107 !begpar(current->next))
2108 current = current->next;
2109
2110 if (current->next != NULL)
2111 current = current->next;
2112
2113 edit_redraw(old_current, old_pww);
2114}
2115
Chris Allegretta6df90f52002-07-19 01:08:59 +00002116/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002117 * buffer, not allowing them to be concatenated. We assume there are
2118 * enough lines after first_line. We leave copies of the lines in
2119 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002120filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2121 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002122{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002123 /* We put the original lines, not copies, into the cutbuffer, just
2124 * out of a misguided sense of consistency, so if you uncut, you get
2125 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002126 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002127
2128 set_modified();
2129 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002130 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002131 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002132
Chris Allegretta908f7702003-01-15 11:18:58 +00002133 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002134 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002135 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002136 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002137 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002138 edittop = bob;
2139#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002140 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002141 mark_beginbuf = bob;
2142#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002143
Chris Allegretta908f7702003-01-15 11:18:58 +00002144 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002145 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002146 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002147 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002148 }
2149 return first_line;
2150}
2151
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002152/* Is it possible to break line at or before goal? */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002153bool breakable(const char *line, int goal)
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002154{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002155 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002156 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002157 return TRUE;
2158
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002159 if (is_cntrl_char(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002160 goal -= 2;
2161 else
2162 goal -= 1;
2163 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002164 /* If goal is not negative, the whole line (one word) was short
2165 * enough. */
2166 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002167}
2168
Chris Allegretta6df90f52002-07-19 01:08:59 +00002169/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002170 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002171 * such space, and force is TRUE, then we find the first space. Anyway,
2172 * we then take the last space in that group of spaces. The terminating
2173 * '\0' counts as a space. */
2174int break_line(const char *line, int goal, bool force)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002175{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002176 /* Note that we use int instead of size_t, since goal is at most
2177 * COLS, the screen width, which will always be reasonably small. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002178 int space_loc = -1;
2179 /* Current tentative return value. Index of the last space we
2180 * found with short enough display width. */
2181 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002182 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002183
2184 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002185 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002186 if (*line == ' ')
2187 space_loc = cur_loc;
2188 assert(*line != '\t');
2189
Chris Allegrettacf287c82002-07-20 13:57:41 +00002190 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002191 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002192 else
2193 goal--;
2194 }
2195 if (goal >= 0)
2196 /* In fact, the whole line displays shorter than goal. */
2197 return cur_loc;
2198 if (space_loc == -1) {
2199 /* No space found short enough. */
2200 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002201 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002202 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002203 return cur_loc;
2204 return -1;
2205 }
2206 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002207 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002208 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2209 *(line - cur_loc + space_loc + 1) == '\0')
2210 space_loc++;
2211 return space_loc;
2212}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002213
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002214/* Find the beginning of the current paragraph if we're in one, or the
2215 * beginning of the next paragraph if we're not. Afterwards, save the
2216 * quote length and paragraph length in *quote and *par. Return FALSE
2217 * if we found a paragraph, or TRUE if there was an error or we didn't
2218 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002219 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002220 * See the comment at begpar() for more about when a line is the
2221 * beginning of a paragraph. */
2222bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002223{
2224 size_t quote_len;
2225 /* Length of the initial quotation of the paragraph we
2226 * search. */
2227 size_t par_len;
2228 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002229 size_t indent_len;
2230 /* Generic indentation length. */
2231 filestruct *line;
2232 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002233
2234#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002235 if (quoterc != 0) {
2236 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2237 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002238 }
2239#endif
2240
2241 /* Here is an assumption that is always true anyway. */
2242 assert(current != NULL);
2243
2244 current_x = 0;
2245
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002246 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002247 indent_len = indent_length(current->data + quote_len);
2248
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002249 /* Here we find the first line of the paragraph to search. If the
2250 * current line is in a paragraph, then we move back to the first
2251 * line of the paragraph. Otherwise, we move to the first line that
2252 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002253 if (current->data[quote_len + indent_len] != '\0') {
2254 /* This line is part of a paragraph. So we must search back to
2255 * the first line of this paragraph. First we check items 1)
2256 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002257 while (current->prev != NULL && quotes_match(current->data,
2258 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002259 size_t temp_id_len =
2260 indent_length(current->prev->data + quote_len);
2261 /* The indentation length of the previous line. */
2262
2263 /* Is this line the beginning of a paragraph, according to
2264 * items 2), 5), or 4) above? If so, stop. */
2265 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002266 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002267#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002268 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002269#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002270 ) || !indents_match(current->prev->data + quote_len,
2271 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002272 break;
2273 indent_len = temp_id_len;
2274 current = current->prev;
2275 current_y--;
2276 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002277 } else {
2278 /* This line is not part of a paragraph. Move down until we get
2279 * to a non "blank" line. */
2280 do {
2281 /* There is no next paragraph, so nothing to move to. */
2282 if (current->next == NULL) {
2283 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002284 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002285 }
2286 current = current->next;
2287 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002288 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002289 indent_len = indent_length(current->data + quote_len);
2290 } while (current->data[quote_len + indent_len] == '\0');
2291 }
2292
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002293 /* Now current is the first line of the paragraph, and quote_len is
2294 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002295
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002296 /* Next step, compute par_len, the number of lines in this
2297 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002298 line = current;
2299 par_len = 1;
2300 indent_len = indent_length(line->data + quote_len);
2301
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002302 while (line->next != NULL &&
2303 quotes_match(current->data, quote_len, line->next->data)) {
2304 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002305
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002306 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002307 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002308 line->next->data[quote_len + temp_id_len] == '\0' ||
2309 (quote_len == 0 && temp_id_len > 0
2310#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002311 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002312#endif
2313 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002314 break;
2315 indent_len = temp_id_len;
2316 line = line->next;
2317 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002318 }
2319
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002320 /* Now par_len is the number of lines in this paragraph. We should
2321 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002322
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002323 /* Save the values of quote_len and par_len. */
2324 assert(quote != NULL && par != NULL);
2325 *quote = quote_len;
2326 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002327
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002328 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002329}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002330
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002331/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2332 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002333void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002334{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002335 filestruct *first_par_line = NULL;
2336 /* Will be the first line of the resulting justified paragraph.
2337 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002338 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002339 /* Will be the last line of the result, also for uncut. */
2340 filestruct *cutbuffer_save = cutbuffer;
2341 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002342 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002343 * original to restore it later. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002344 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002345 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002346 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002347 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002348
2349 /* We save these global variables to be restored if the user
2350 * unjustifies. Note we don't need to save totlines. */
2351 int current_x_save = current_x;
2352 int current_y_save = current_y;
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002353 long flags_save = flags;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002354 long totsize_save = totsize;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002355 filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002356 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002357#ifndef NANO_SMALL
2358 filestruct *mark_beginbuf_save = mark_beginbuf;
2359 int mark_beginx_save = mark_beginx;
2360#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002361 int kbinput;
2362 int meta_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002363
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002364 /* If we're justifying the entire file, start at the beginning. */
2365 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002366 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002367
2368 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002369
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002370 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002371 size_t quote_len;
2372 /* Length of the initial quotation of the paragraph we
2373 * justify. */
2374 size_t par_len;
2375 /* Number of lines in that paragraph. */
2376
2377 /* Find the first line of the paragraph to be justified. That
2378 * is the start of this paragraph if we're in one, or the start
2379 * of the next otherwise. Save the quote length and paragraph
2380 * length (number of lines). Don't refresh the screen yet
2381 * (since we'll do that after we justify). If the search failed
2382 * and we're justifying the whole file, move the last line of
2383 * the text we're justifying to just before the magicline, which
2384 * is where it'll be anyway if we've searched the entire file,
2385 * and break out of the loop; otherwise, refresh the screen and
2386 * get out. */
2387 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002388 if (full_justify) {
2389 /* This should be safe in the event of filebot->prev's
2390 * being NULL, since only last_par_line->next is used if
2391 * we eventually unjustify. */
2392 last_par_line = filebot->prev;
2393 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002394 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002395 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002396 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002397 }
2398 }
2399
2400 /* Next step, we loop through the lines of this paragraph,
2401 * justifying each one individually. */
2402 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002403 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002404 size_t line_len;
2405 size_t display_len;
2406 /* The width of current in screen columns. */
2407 int break_pos;
2408 /* Where we will break the line. */
2409
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002410 /* We'll be moving to the next line after justifying the
2411 * current line in almost all cases, so allow changing the
2412 * spacing at the ends of justified lines by default. */
2413 allow_respacing = TRUE;
2414
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002415 indent_len = quote_len + indent_length(current->data +
2416 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002417
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002418 /* If we haven't already done it, copy the original
2419 * paragraph to the cutbuffer for unjustification. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002420 if (first_par_line == NULL)
2421 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002422 filebot->lineno - current->lineno : par_len, quote_len);
2423
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002424 /* Now we call justify_format() on the current line of the
2425 * paragraph, which will remove excess spaces from it and
2426 * change tabs to spaces. */
2427 justify_format(current, quote_len +
2428 indent_length(current->data + quote_len));
2429
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002430 line_len = strlen(current->data);
2431 display_len = strlenpt(current->data);
2432
2433 if (display_len > fill) {
2434 /* The line is too long. Try to wrap it to the next. */
2435 break_pos = break_line(current->data + indent_len,
2436 fill - strnlenpt(current->data, indent_len), TRUE);
2437 if (break_pos == -1 || break_pos + indent_len == line_len)
2438 /* We can't break the line, or don't need to, so
2439 * just go on to the next. */
2440 goto continue_loc;
2441 break_pos += indent_len;
2442 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002443 if (par_len == 1) {
2444 /* There is no next line in this paragraph. We make
2445 * a new line and copy text after break_pos into
2446 * it. */
2447 splice_node(current, make_new_node(current), current->next);
2448 /* In a non-quoted paragraph, we copy the indent
2449 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002450 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002451#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002452 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002453#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002454 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002455 indent_len = 0;
2456 current->next->data = charalloc(indent_len + line_len -
2457 break_pos);
2458 strncpy(current->next->data, current->data, indent_len);
2459 strcpy(current->next->data + indent_len,
2460 current->data + break_pos + 1);
2461 assert(strlen(current->next->data) ==
2462 indent_len + line_len - break_pos - 1);
2463 totlines++;
2464 totsize += indent_len;
2465 par_len++;
2466 } else {
2467 size_t next_line_len = strlen(current->next->data);
2468
2469 indent_len = quote_len +
2470 indent_length(current->next->data + quote_len);
2471 current->next->data = charealloc(current->next->data,
2472 next_line_len + line_len - break_pos + 1);
2473
2474 charmove(current->next->data + indent_len + line_len -
2475 break_pos, current->next->data + indent_len,
2476 next_line_len - indent_len + 1);
2477 strcpy(current->next->data + indent_len,
2478 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002479 current->next->data[indent_len + line_len -
2480 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002481#ifndef NANO_SMALL
2482 if (mark_beginbuf == current->next) {
2483 if (mark_beginx < indent_len)
2484 mark_beginx = indent_len;
2485 mark_beginx += line_len - break_pos;
2486 }
2487#endif
2488 }
2489#ifndef NANO_SMALL
2490 if (mark_beginbuf == current && mark_beginx > break_pos) {
2491 mark_beginbuf = current->next;
2492 mark_beginx -= break_pos + 1 - indent_len;
2493 }
2494#endif
2495 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002496
2497 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002498 current = current->next;
2499 } else if (display_len < fill && par_len > 1) {
2500 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002501
2502 indent_len = quote_len +
2503 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002504 /* If we can't pull a word from the next line up to this
2505 * one, just go on. */
2506 if (!breakable(current->next->data + indent_len,
2507 fill - display_len - 1))
2508 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002509
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002510 break_pos = break_line(current->next->data + indent_len,
2511 fill - display_len - 1, FALSE);
2512 assert(break_pos != -1);
2513
2514 current->data = charealloc(current->data,
2515 line_len + break_pos + 2);
2516 current->data[line_len] = ' ';
2517 strncpy(current->data + line_len + 1,
2518 current->next->data + indent_len, break_pos);
2519 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002520#ifndef NANO_SMALL
2521 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002522 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002523 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002524 if (mark_beginx <= indent_len)
2525 mark_beginx = line_len + 1;
2526 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002527 mark_beginx = line_len + 1 + mark_beginx -
2528 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002529 } else
2530 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002531 }
2532#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002533 next_line_len = strlen(current->next->data);
2534 if (indent_len + break_pos == next_line_len) {
2535 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002536
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002537 /* Don't destroy edittop! */
2538 if (line == edittop)
2539 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002540
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002541 unlink_node(line);
2542 delete_node(line);
2543 totlines--;
2544 totsize -= indent_len;
2545 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002546
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002547 /* Don't go to the next line. Accordingly, don't
2548 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002549 * previous justified line, so that we don't end up
2550 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002551 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002552 } else {
2553 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002554 current->next->data + indent_len + break_pos + 1,
2555 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002556 null_at(&current->next->data, next_line_len - break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002557
2558 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002559 current = current->next;
2560 }
2561 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002562 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002563 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002564 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002565
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002566 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002567 * current line. If the justified line was not the last
2568 * line of the paragraph, add a space to the end of it to
2569 * replace the one removed or left out by justify_format().
2570 * If it was the last line of the paragraph, and
2571 * justify_format() left a space on the end of it, remove
2572 * the space. */
2573 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002574 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002575
2576 if (par_len > 1) {
2577 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002578 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002579 current->prev->data[prev_line_len] = ' ';
2580 current->prev->data[prev_line_len + 1] = '\0';
2581 totsize++;
2582 } else if (par_len == 1 &&
2583 current->prev->data[prev_line_len - 1] == ' ') {
2584 current->prev->data = charealloc(current->prev->data,
2585 prev_line_len);
2586 current->prev->data[prev_line_len - 1] = '\0';
2587 totsize--;
2588 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002589 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002590 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002591
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002592 /* We've just justified a paragraph. If we're not justifying the
2593 * entire file, break out of the loop. Otherwise, continue the
2594 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002595 if (!full_justify)
2596 break;
2597
2598 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002599
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002600 /* We are now done justifying the paragraph or the file, so clean
2601 * up. totlines, totsize, and current_y have been maintained above.
2602 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002603 * fileage, and renumber() since edit_refresh() needs the line
2604 * numbers to be right (but only do the last two if we actually
2605 * justified something). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002606 last_par_line = current->prev;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002607 if (first_par_line != NULL) {
2608 if (first_par_line->prev == NULL)
2609 fileage = first_par_line;
2610 renumber(first_par_line);
2611 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002612
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002613 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002614
Chris Allegretta9149e612000-11-27 00:23:41 +00002615 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002616 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002617 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002618 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002619
Chris Allegretta6df90f52002-07-19 01:08:59 +00002620 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002621 * keystroke and return. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002622 kbinput = get_kbinput(edit, &meta_key);
Chris Allegretta5f071802001-05-06 02:34:31 +00002623
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002624#ifndef DISABLE_MOUSE
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002625 /* If it was a mouse click, parse it with do_mouse() and it might
2626 * become the unjustify key. Else give it back to the input
2627 * stream. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002628 if (kbinput == KEY_MOUSE) {
2629 do_mouse();
2630 kbinput = get_kbinput(edit, &meta_key);
2631 }
2632#endif
2633
2634 if (meta_key || (kbinput != NANO_UNJUSTIFY_KEY &&
2635 kbinput != NANO_UNJUSTIFY_FKEY)) {
2636 ungetch(kbinput);
2637 if (meta_key)
2638 ungetch(NANO_CONTROL_3);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002639 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002640 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002641 /* Else restore the justify we just did (ungrateful user!). */
2642 filestruct *cutbottom = get_cutbottom();
2643
Chris Allegretta6df90f52002-07-19 01:08:59 +00002644 current = current_save;
2645 current_x = current_x_save;
2646 current_y = current_y_save;
2647 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002648
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002649 /* Splice the cutbuffer back into the file, but only if we
2650 * actually justified something. */
2651 if (first_par_line != NULL) {
2652 cutbottom->next = last_par_line->next;
2653 cutbottom->next->prev = cutbottom;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002654 /* The line numbers after the end of the paragraph have been
2655 * changed, so we change them back. */
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002656 renumber(cutbottom->next);
2657 if (first_par_line->prev != NULL) {
2658 cutbuffer->prev = first_par_line->prev;
2659 cutbuffer->prev->next = cutbuffer;
2660 } else
2661 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002662
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002663 last_par_line->next = NULL;
2664 free_filestruct(first_par_line);
2665 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002666
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002667 /* Restore global variables from before the justify. */
2668 totsize = totsize_save;
2669 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002670#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002671 mark_beginbuf = mark_beginbuf_save;
2672 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002673#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002674 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002675 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002676 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002677 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002678 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002679
Chris Allegretta6df90f52002-07-19 01:08:59 +00002680 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002681 /* Note that now cutbottom is invalid, but that's okay. */
2682 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002683 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002684 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002685 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002686}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002687
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002688void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002689{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002690 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002691}
2692
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002693void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002694{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002695 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002696}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002697#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002698
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002699void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002700{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002701 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002702
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002703 if (!ISSET(MODIFIED))
2704 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002705 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002706 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002707 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002708 i = do_yesno(FALSE,
2709 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2710
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002711#ifdef DEBUG
2712 dump_buffer(fileage);
2713#endif
2714
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002715 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002716#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002717 /* Exit only if there are no more open buffers. */
2718 if (close_open_file() != 0)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002719#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002720 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002721 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002722 statusbar(_("Cancelled"));
2723
2724 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002725}
2726
2727void signal_init(void)
2728{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002729 /* Trap SIGINT and SIGQUIT because we want them to do useful
2730 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002731 memset(&act, 0, sizeof(struct sigaction));
2732 act.sa_handler = SIG_IGN;
2733 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002734 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002735
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002736 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002737 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002738 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002739 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002740
2741#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002742 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002743 act.sa_handler = handle_sigwinch;
2744 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002745 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002746#endif
2747
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002748 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002749 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002750 act.sa_handler = SIG_IGN;
2751 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002752 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002753 /* Block all other signals in the suspend and continue handlers.
2754 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002755 sigfillset(&act.sa_mask);
2756
2757 act.sa_handler = do_suspend;
2758 sigaction(SIGTSTP, &act, NULL);
2759
2760 act.sa_handler = do_cont;
2761 sigaction(SIGCONT, &act, NULL);
2762 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002763}
2764
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002765/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002766RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002767{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002768 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002769}
2770
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002771/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002772RETSIGTYPE do_suspend(int signal)
2773{
2774 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002775 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002776 fflush(stdout);
2777
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002778 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002779 tcsetattr(0, TCSANOW, &oldterm);
2780
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002781 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002782 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002783 act.sa_handler = handle_hupterm;
2784 sigaction(SIGHUP, &act, NULL);
2785 sigaction(SIGTERM, &act, NULL);
2786
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002787 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002788 kill(0, SIGSTOP);
2789}
2790
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002791/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002792RETSIGTYPE do_cont(int signal)
2793{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002794#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002795 /* Perhaps the user resized the window while we slept. Handle it
2796 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002797 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002798#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002799 /* Just update the screen. */
2800 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002801#endif
2802}
2803
2804#ifndef NANO_SMALL
2805void handle_sigwinch(int s)
2806{
2807 const char *tty = ttyname(0);
2808 int fd;
2809 int result = 0;
2810 struct winsize win;
2811
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002812 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002813 return;
2814 fd = open(tty, O_RDWR);
2815 if (fd == -1)
2816 return;
2817 result = ioctl(fd, TIOCGWINSZ, &win);
2818 close(fd);
2819 if (result == -1)
2820 return;
2821
2822 /* Could check whether the COLS or LINES changed, and return
2823 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2824 * variables, and in some cases ncurses has already updated them.
2825 * But not in all cases, argh. */
2826 COLS = win.ws_col;
2827 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002828 editwinrows = LINES - 5 + no_help();
2829 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002830 die_too_small();
2831
2832#ifndef DISABLE_WRAPJUSTIFY
2833 fill = wrap_at;
2834 if (fill <= 0)
2835 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002836 if (fill < 0)
2837 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002838#endif
2839
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002840 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002841 memset(hblank, ' ', COLS);
2842 hblank[COLS] = '\0';
2843
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002844#ifdef USE_SLANG
2845 /* Slang curses emulation brain damage, part 1: If we just do what
2846 * curses does here, it'll only work properly if the resize made the
2847 * window smaller. Do what mutt does: Leave and immediately reenter
2848 * Slang screen management mode. */
2849 SLsmg_reset_smg();
2850 SLsmg_init_smg();
2851#else
2852 /* Do the equivalent of what Minimum Profit does: Leave and
2853 * immediately reenter curses mode. */
2854 endwin();
2855 refresh();
2856#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002857
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002858 /* Restore the terminal to its previous state. */
2859 terminal_init();
2860
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002861 /* Do the equivalent of what both mutt and Minimum Profit do:
2862 * Reinitialize all the windows based on the new screen
2863 * dimensions. */
2864 window_init();
2865
2866 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002867 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002868 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002869 total_refresh();
2870
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002871 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002872 curs_set(1);
2873
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002874 /* Reset all the input routines that rely on character sequences. */
2875 reset_kbinput();
2876
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002877 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002878 siglongjmp(jmpbuf, 1);
2879}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002880
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002881void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002882{
2883 sigset_t winch;
2884 sigemptyset(&winch);
2885 sigaddset(&winch, SIGWINCH);
2886 if (allow)
2887 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2888 else
2889 sigprocmask(SIG_BLOCK, &winch, NULL);
2890}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002891#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002892
Chris Allegrettadab017e2002-04-23 10:56:06 +00002893#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002894void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002895{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002896 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002897
Chris Allegretta658399a2001-06-14 02:54:22 +00002898 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002899 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002900
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002901 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002902 case TOGGLE_SUSPEND_KEY:
2903 signal_init();
2904 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002905#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002906 case TOGGLE_MOUSE_KEY:
2907 mouse_init();
2908 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002909#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002910 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002911 blank_statusbar();
2912 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002913 wrefresh(bottomwin);
2914 window_init();
2915 edit_refresh();
2916 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002917 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002918 case TOGGLE_DOS_KEY:
2919 UNSET(MAC_FILE);
2920 break;
2921 case TOGGLE_MAC_KEY:
2922 UNSET(DOS_FILE);
2923 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002924#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002925 case TOGGLE_SYNTAX_KEY:
2926 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002927 break;
2928#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002929#ifdef ENABLE_NANORC
2930 case TOGGLE_WHITESPACE_KEY:
2931 edit_refresh();
2932 break;
2933#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002934 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002935
Chris Allegretta6df90f52002-07-19 01:08:59 +00002936 /* We are assuming here that shortcut_init() above didn't free and
2937 * reallocate the toggles. */
2938 enabled = ISSET(which->flag);
2939 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2940 enabled = !enabled;
2941 statusbar("%s %s", which->desc,
2942 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002943}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002944#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002945
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002946void disable_signals(void)
2947{
2948 struct termios term;
2949
2950 tcgetattr(0, &term);
2951 term.c_lflag &= ~ISIG;
2952 tcsetattr(0, TCSANOW, &term);
2953}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002954
2955#ifndef NANO_SMALL
2956void enable_signals(void)
2957{
2958 struct termios term;
2959
2960 tcgetattr(0, &term);
2961 term.c_lflag |= ISIG;
2962 tcsetattr(0, TCSANOW, &term);
2963}
2964#endif
2965
2966void disable_flow_control(void)
2967{
2968 struct termios term;
2969
2970 tcgetattr(0, &term);
2971 term.c_iflag &= ~(IXON|IXOFF);
2972 tcsetattr(0, TCSANOW, &term);
2973}
2974
2975void enable_flow_control(void)
2976{
2977 struct termios term;
2978
2979 tcgetattr(0, &term);
2980 term.c_iflag |= (IXON|IXOFF);
2981 tcsetattr(0, TCSANOW, &term);
2982}
2983
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002984/* Set up the terminal state. Put the terminal in cbreak mode (read one
2985 * character at a time and interpret the special control keys), disable
2986 * translation of carriage return (^M) into newline (^J) so that we can
2987 * tell the difference between the Enter key and Ctrl-J, and disable
2988 * echoing of characters as they're typed. Finally, disable
2989 * interpretation of the special control keys, and if we're not in
2990 * preserve mode, disable interpretation of the flow control characters
2991 * too. */
2992void terminal_init(void)
2993{
2994 cbreak();
2995 nonl();
2996 noecho();
2997 disable_signals();
2998 if (!ISSET(PRESERVE))
2999 disable_flow_control();
3000}
3001
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003002int main(int argc, char *argv[])
3003{
3004 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003005 int startline = 0; /* Line to try and start at */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003006#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003007 bool fill_flag_used = FALSE; /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003008#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003009 const shortcut *s;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003010 bool keyhandled = FALSE; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003011 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003012 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003013
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003014#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003015 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003016#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003017#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003018 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003019 {"help", 0, 0, 'h'},
3020#ifdef ENABLE_MULTIBUFFER
3021 {"multibuffer", 0, 0, 'F'},
3022#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003023#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003024#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003025 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003026#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003027 {"ignorercfiles", 0, 0, 'I'},
3028#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003029#ifndef DISABLE_JUSTIFY
3030 {"quotestr", 1, 0, 'Q'},
3031#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003032#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003033 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003034#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003035 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003036 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003037#ifdef ENABLE_COLOR
3038 {"syntax", 1, 0, 'Y'},
3039#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003040 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003041 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003042 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003043#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003044 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003045#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003046#ifndef DISABLE_OPERATINGDIR
3047 {"operatingdir", 1, 0, 'o'},
3048#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003049 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003050#ifndef DISABLE_WRAPJUSTIFY
3051 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003052#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003053#ifndef DISABLE_SPELLER
3054 {"speller", 1, 0, 's'},
3055#endif
3056 {"tempfile", 0, 0, 't'},
3057 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003058#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003059 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003060#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003061 {"nohelp", 0, 0, 'x'},
3062 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003063#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003064 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003065 {"backup", 0, 0, 'B'},
3066 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003067 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003068 {"mac", 0, 0, 'M'},
3069 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003070 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003071 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003072 {"autoindent", 0, 0, 'i'},
3073 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003074#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003075 {0, 0, 0, 0}
3076 };
3077#endif
3078
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003079 setlocale(LC_ALL, "");
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003080#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003081 bindtextdomain(PACKAGE, LOCALEDIR);
3082 textdomain(PACKAGE);
3083#endif
3084
Chris Allegretta7662c862003-01-13 01:35:15 +00003085#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003086 /* if we don't have rcfile support, we're root, and
3087 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003088 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003089 SET(NO_WRAP);
3090#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003091
Chris Allegretta6df90f52002-07-19 01:08:59 +00003092 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003093#ifdef HAVE_GETOPT_LONG
3094 getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
3095#else
3096 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003097#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003098 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003099
3100 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003101 case 'a':
3102 case 'b':
3103 case 'e':
3104 case 'f':
3105 case 'g':
3106 case 'j':
3107 /* Pico compatibility flags. */
3108 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003109#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003110 case 'A':
3111 SET(SMART_HOME);
3112 break;
3113 case 'B':
3114 SET(BACKUP_FILE);
3115 break;
3116 case 'D':
3117 SET(DOS_FILE);
3118 break;
3119 case 'E':
3120 backup_dir = mallocstrcpy(backup_dir, optarg);
3121 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003122#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003123#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003124 case 'F':
3125 SET(MULTIBUFFER);
3126 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003127#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003128#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003129#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003130 case 'H':
3131 SET(HISTORYLOG);
3132 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003133#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003134 case 'I':
3135 SET(NO_RCFILE);
3136 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003137#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003138#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003139 case 'M':
3140 SET(MAC_FILE);
3141 break;
3142 case 'N':
3143 SET(NO_CONVERT);
3144 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003145#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003146#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003147 case 'Q':
3148 quotestr = mallocstrcpy(quotestr, optarg);
3149 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003150#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003151#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003152 case 'R':
3153 SET(USE_REGEXP);
3154 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003155#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003156#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003157 case 'S':
3158 SET(SMOOTHSCROLL);
3159 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003160#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003161 case 'T':
3162 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003163 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
3164 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003165 exit(1);
3166 }
3167 break;
3168 case 'V':
3169 version();
3170 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003171#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003172 case 'Y':
3173 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3174 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00003175#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003176 case 'Z':
3177 SET(RESTRICTED);
3178 break;
3179 case 'c':
3180 SET(CONSTUPDATE);
3181 break;
3182 case 'd':
3183 SET(REBIND_DELETE);
3184 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003185#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003186 case 'i':
3187 SET(AUTOINDENT);
3188 break;
3189 case 'k':
3190 SET(CUT_TO_END);
3191 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003192#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003193 case 'l':
3194 SET(NOFOLLOW_SYMLINKS);
3195 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003196#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003197 case 'm':
3198 SET(USE_MOUSE);
3199 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003200#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003201#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003202 case 'o':
3203 operating_dir = mallocstrcpy(operating_dir, optarg);
3204 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003205#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003206 case 'p':
3207 SET(PRESERVE);
3208 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003209#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003210 case 'r':
3211 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003212 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
3213 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003214 exit(1);
3215 }
3216 fill_flag_used = TRUE;
3217 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003218#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003219#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003220 case 's':
3221 alt_speller = mallocstrcpy(alt_speller, optarg);
3222 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003223#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003224 case 't':
3225 SET(TEMP_FILE);
3226 break;
3227 case 'v':
3228 SET(VIEW_MODE);
3229 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003230#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003231 case 'w':
3232 SET(NO_WRAP);
3233 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003234#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003235 case 'x':
3236 SET(NO_HELP);
3237 break;
3238 case 'z':
3239 SET(SUSPEND);
3240 break;
3241 default:
3242 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003243 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003244 }
3245
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003246 /* If the executable filename starts with 'r', we use restricted
3247 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003248 if (*(tail(argv[0])) == 'r')
3249 SET(RESTRICTED);
3250
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003251 /* If we're using restricted mode, disable suspending, backups, and
3252 * reading rcfiles, since they all would allow reading from or
3253 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003254 if (ISSET(RESTRICTED)) {
3255 UNSET(SUSPEND);
3256 UNSET(BACKUP_FILE);
3257 SET(NO_RCFILE);
3258 }
3259
Chris Allegretta7662c862003-01-13 01:35:15 +00003260/* We've read through the command line options. Now back up the flags
3261 and values that are set, and read the rcfile(s). If the values
3262 haven't changed afterward, restore the backed-up values. */
3263#ifdef ENABLE_NANORC
3264 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003265#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003266 char *operating_dir_cpy = operating_dir;
3267#endif
3268#ifndef DISABLE_WRAPPING
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003269 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003270#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003271#ifndef NANO_SMALL
3272 char *backup_dir_cpy = backup_dir;
3273#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003274#ifndef DISABLE_JUSTIFY
3275 char *quotestr_cpy = quotestr;
3276#endif
3277#ifndef DISABLE_SPELLER
3278 char *alt_speller_cpy = alt_speller;
3279#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003280 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003281 long flags_cpy = flags;
3282
Chris Allegretta5ec68622003-02-05 02:39:34 +00003283#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003284 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003285#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003286#ifndef NANO_SMALL
3287 backup_dir = NULL;
3288#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003289#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003290 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003291#endif
3292#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003293 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003294#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003295
3296 do_rcfile();
3297
3298#ifndef DISABLE_OPERATINGDIR
3299 if (operating_dir_cpy != NULL) {
3300 free(operating_dir);
3301 operating_dir = operating_dir_cpy;
3302 }
3303#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003304#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003305 if (fill_flag_used)
3306 wrap_at = wrap_at_cpy;
3307#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003308#ifndef NANO_SMALL
3309 if (backup_dir_cpy != NULL) {
3310 free(backup_dir);
3311 backup_dir = backup_dir_cpy;
3312 }
3313#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003314#ifndef DISABLE_JUSTIFY
3315 if (quotestr_cpy != NULL) {
3316 free(quotestr);
3317 quotestr = quotestr_cpy;
3318 }
3319#endif
3320#ifndef DISABLE_SPELLER
3321 if (alt_speller_cpy != NULL) {
3322 free(alt_speller);
3323 alt_speller = alt_speller_cpy;
3324 }
3325#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00003326 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00003327 tabsize = tabsize_cpy;
3328 flags |= flags_cpy;
3329 }
3330#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003331 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003332 SET(NO_WRAP);
3333#endif
3334#endif /* ENABLE_NANORC */
3335
Chris Allegrettad8451932003-03-11 03:50:40 +00003336#ifndef NANO_SMALL
3337 history_init();
3338#ifdef ENABLE_NANORC
3339 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3340 load_history();
3341#endif
3342#endif
3343
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003344#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003345 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003346 * in which case backups are disabled, since they would allow
3347 * reading from or writing to files not specified on the command
3348 * line). This entails making sure it exists and is a directory, so
3349 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003350 if (!ISSET(RESTRICTED))
3351 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003352#endif
3353
Chris Allegretta7662c862003-01-13 01:35:15 +00003354#ifndef DISABLE_OPERATINGDIR
3355 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003356 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003357 init_operating_dir();
3358#endif
3359
Chris Allegretta7662c862003-01-13 01:35:15 +00003360#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003361 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003362 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003363
3364 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003365 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003366
Chris Allegretta7662c862003-01-13 01:35:15 +00003367 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003368 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003369#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003370 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003371#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003372 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003373#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003374 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003375#ifdef HAVE_REGEX_H
3376 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
3377
3378 if (quoterc == 0) {
3379 /* We no longer need quotestr, just quotereg. */
3380 free(quotestr);
3381 quotestr = NULL;
3382 } else {
3383 size_t size = regerror(quoterc, &quotereg, NULL, 0);
3384
3385 quoteerr = charalloc(size);
3386 regerror(quoterc, &quotereg, quoteerr, size);
3387 }
3388#else
3389 quotelen = strlen(quotestr);
3390#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00003391#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003392
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003393#ifndef DISABLE_SPELLER
3394 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003395 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003396 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003397 * checking is disabled, since it would allow reading from or
3398 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003399 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003400 char *spellenv = getenv("SPELL");
3401 if (spellenv != NULL)
3402 alt_speller = mallocstrcpy(NULL, spellenv);
3403 }
3404#endif
3405
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003406#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
3407 if (whitespace == NULL)
3408 whitespace = mallocstrcpy(NULL, " ");
3409#endif
3410
Chris Allegretta7662c862003-01-13 01:35:15 +00003411 if (tabsize == -1)
3412 tabsize = 8;
3413
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003414 /* Clear the filename we'll be using */
3415 filename = charalloc(1);
3416 filename[0] = '\0';
3417
Chris Allegretta7662c862003-01-13 01:35:15 +00003418 /* If there's a +LINE flag, it is the first non-option argument. */
3419 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3420 startline = atoi(&argv[optind][1]);
3421 optind++;
3422 }
3423 if (0 < optind && optind < argc)
3424 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003425
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003426 /* See if there's a non-option in argv (first non-option is the
3427 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003428 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003429 /* Look for the +line flag... */
3430 if (argv[optind][0] == '+') {
3431 startline = atoi(&argv[optind][1]);
3432 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003433 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003434 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003435 } else
3436 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003437 }
3438
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003439 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003440 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003441
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003442 /* Curses initialization stuff: Start curses and set up the
3443 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003444 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003445 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003446
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003447 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003448 global_init(FALSE);
3449 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003450
3451 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003452 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003453
3454#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003455 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003456#endif
3457
Chris Allegretta2a42af12000-09-12 23:02:49 +00003458 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003459#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003460 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003461#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003462
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003463#ifdef DEBUG
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003464 fprintf(stderr, "Main: top and bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003465#endif
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003466 titlebar(NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003467 display_main_list();
3468
3469#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003470 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003471#endif
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003472 open_file(filename, FALSE, FALSE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003473#ifdef ENABLE_MULTIBUFFER
3474 /* If we're using multibuffers and more than one file is specified
3475 on the command line, load them all and switch to the first one
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003476 afterward. */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003477 if (optind + 1 < argc) {
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003478 bool old_multibuffer = ISSET(MULTIBUFFER), list = FALSE;
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003479 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003480 for (optind++; optind < argc; optind++) {
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003481 add_open_file(TRUE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003482 new_file();
3483 filename = mallocstrcpy(filename, argv[optind]);
David Lawrence Ramsey6b248562004-08-07 22:33:14 +00003484 titlebar(NULL);
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003485 open_file(filename, FALSE, FALSE);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003486 load_file(FALSE);
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003487 /* Display the main list with "Close" if we haven't
3488 * already. */
3489 if (!list) {
3490 shortcut_init(FALSE);
3491 list = TRUE;
3492 display_main_list();
3493 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003494 }
3495 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003496 if (!old_multibuffer)
3497 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003498 }
3499#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003500
3501 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003502 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003503
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003504#ifndef NANO_SMALL
3505 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003506 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003507#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003508
Robert Siemborski6967eec2000-07-08 14:23:32 +00003509 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00003510
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003511 while (TRUE) {
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003512 keyhandled = FALSE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003513
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00003514 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003515 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003516 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003517
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003518#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003519 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003520#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003521
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003522 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003523#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003524 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003525#endif
David Lawrence Ramsey4d44d2d2004-08-01 22:35:31 +00003526 if (meta_key) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003527 /* Check for the metaval and miscval defs... */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003528 for (s =
3529#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3530 currshortcut
3531#else
3532 main_list
3533#endif
3534 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003535 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003536 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003537 if (ISSET(VIEW_MODE) && !s->viewok)
3538 print_view_warning();
3539 else {
3540 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003541 cutbuffer_reset();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003542 s->func();
3543 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003544 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003545 }
3546#ifndef NANO_SMALL
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003547 if (!keyhandled) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003548 /* And for toggle switches */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003549 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003550 if (kbinput == t->val) {
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003551 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003552 do_toggle(t);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003553 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003554 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003555 }
3556 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003557#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003558 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003559#ifdef DEBUG
David Lawrence Ramsey331e6592004-07-27 19:40:39 +00003560 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput, kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003561#endif
3562 }
3563
3564 /* Look through the main shortcut list to see if we've hit a
3565 shortcut key or function key */
3566
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003567 if (!keyhandled) {
3568 for (s =
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003569#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003570 currshortcut
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003571#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003572 main_list
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003573#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003574 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003575 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3576 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003577 if (ISSET(VIEW_MODE) && !s->viewok)
3578 print_view_warning();
3579 else {
3580 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003581 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003582 s->func();
3583 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003584 keyhandled = TRUE;
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003585 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003586 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003587 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003588
3589 if (!keyhandled)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003590 cutbuffer_reset();
Chris Allegrettae42df732002-10-15 00:27:55 +00003591
Chris Allegrettae42df732002-10-15 00:27:55 +00003592 /* Don't even think about changing this string */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003593 if (kbinput == NANO_XON_KEY)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003594 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003595 if (kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003596 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003597 if (kbinput == NANO_XON_KEY || kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003598 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003599
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003600 /* Catch ^Z by hand when triggered also */
3601 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003602 if (ISSET(SUSPEND))
3603 do_suspend(0);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003604 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003605 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003606
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003607 /* Last gasp, stuff that's not in the main lists */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003608 if (!keyhandled) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003609 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003610#ifndef DISABLE_MOUSE
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003611 case KEY_MOUSE:
3612 do_mouse();
3613 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003614#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003615 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3616 * have been handled before we
3617 * got here */
3618 case NANO_CONTROL_5: /* Ctrl-] */
3619 break;
3620 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003621#ifdef DEBUG
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003622 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003623#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003624 /* We no longer stop unhandled sequences so that
3625 people with odd character sets can type... */
3626 if (ISSET(VIEW_MODE))
3627 print_view_warning();
3628 else
3629 do_char((char)kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003630 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003631 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003632 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003633 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003634}