blob: 07ca0c16c211e219037f9e23dcd67c6b89bf3429 [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
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00001882 * (except it maintains 2 after a character in punct followed by a
1883 * character in brackets). Note that the terminating \0 counts as a
1884 * space.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001885 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001886 * justify_format() might make line->data shorter, and change the actual
1887 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001888 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001889 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001890 * skip should be at most strlen(line->data). The character at
1891 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001892void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001893{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001894 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001895
Chris Allegretta6df90f52002-07-19 01:08:59 +00001896 /* These four asserts are assumptions about the input data. */
1897 assert(line != NULL);
1898 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001899 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001900 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001901
Chris Allegretta6df90f52002-07-19 01:08:59 +00001902 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001903 for (front = back; ; front++) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001904 bool remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001905 /* Do we want to remove this space? */
1906
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001907 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001908 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001909
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001910 /* These tests are safe since line->data + skip is not a
1911 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001912 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001913 const char *bob = front - 2;
1914
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001915 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001916 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001917 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001918 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001919 break;
1920 }
1921 if (strchr(brackets, *bob) == NULL)
1922 break;
1923 }
1924 }
1925
1926 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001927 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001928 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001929#ifndef NANO_SMALL
1930 if (mark_beginbuf == line && back - line->data < mark_beginx)
1931 mark_beginx--;
1932#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001933 if (*front == '\0')
1934 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001935 } else {
1936 *back = *front;
1937 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001938 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001939 if (*front == '\0')
1940 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001941 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001942
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001943 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001944 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001945
Chris Allegretta6df90f52002-07-19 01:08:59 +00001946 /* Now back is the new end of line->data. */
1947 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001948 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001949 null_at(&line->data, back - line->data);
1950#ifndef NANO_SMALL
1951 if (mark_beginbuf == line && back - line->data < mark_beginx)
1952 mark_beginx = back - line->data;
1953#endif
1954 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001955}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001956
1957/* The "quote part" of a line is the largest initial substring matching
1958 * the quote string. This function returns the length of the quote part
1959 * of the given line.
1960 *
1961 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1962 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001963size_t quote_length(const char *line)
1964{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001965#ifdef HAVE_REGEX_H
1966 regmatch_t matches;
1967 int rc = regexec(&quotereg, line, 1, &matches, 0);
1968
1969 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1970 return 0;
1971 /* matches.rm_so should be 0, since the quote string should start
1972 * with the caret ^. */
1973 return matches.rm_eo;
1974#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001975 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001976
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001977 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001978 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001979 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001980 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001981#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001982}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001983
Chris Allegretta6df90f52002-07-19 01:08:59 +00001984/* a_line and b_line are lines of text. The quotation part of a_line is
1985 * the first a_quote characters. Check that the quotation part of
1986 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001987bool quotes_match(const char *a_line, size_t a_quote, const char
1988 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001989{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001990 /* Here is the assumption about a_quote: */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001991 assert(a_quote == quote_length(a_line));
1992 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001993 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001994}
1995
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001996/* We assume a_line and b_line have no quote part. Then, we return
1997 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001998bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001999 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002000{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002001 assert(a_indent == indent_length(a_line));
2002 assert(b_indent == indent_length(b_line));
2003
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002004 return b_indent <= a_indent &&
2005 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002006}
2007
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002008/* Is foo the beginning of a paragraph?
2009 *
2010 * A line of text consists of a "quote part", followed by an
2011 * "indentation part", followed by text. The functions quote_length()
2012 * and indent_length() calculate these parts.
2013 *
2014 * A line is "part of a paragraph" if it has a part not in the quote
2015 * part or the indentation.
2016 *
2017 * A line is "the beginning of a paragraph" if it is part of a
2018 * paragraph and
2019 * 1) it is the top line of the file, or
2020 * 2) the line above it is not part of a paragraph, or
2021 * 3) the line above it does not have precisely the same quote
2022 * part, or
2023 * 4) the indentation of this line is not an initial substring of
2024 * the indentation of the previous line, or
2025 * 5) this line has no quote part and some indentation, and
2026 * AUTOINDENT is not set.
2027 * The reason for number 5) is that if AUTOINDENT is not set, then an
2028 * indented line is expected to start a paragraph, like in books.
2029 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2030 * turned on. */
2031bool begpar(const filestruct *const foo)
2032{
2033 size_t quote_len;
2034 size_t indent_len;
2035 size_t temp_id_len;
2036
2037 /* Case 1). */
2038 if (foo->prev == NULL)
2039 return TRUE;
2040
2041 quote_len = quote_length(foo->data);
2042 indent_len = indent_length(foo->data + quote_len);
2043
2044 /* Not part of a paragraph. */
2045 if (foo->data[quote_len + indent_len] == '\0')
2046 return FALSE;
2047
2048 /* Case 3). */
2049 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2050 return TRUE;
2051
2052 temp_id_len = indent_length(foo->prev->data + quote_len);
2053
2054 /* Case 2) or 5) or 4). */
2055 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2056 (quote_len == 0 && indent_len > 0
2057#ifndef NANO_SMALL
2058 && !ISSET(AUTOINDENT)
2059#endif
2060 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2061 foo->data + quote_len, indent_len))
2062 return TRUE;
2063
2064 return FALSE;
2065}
2066
2067/* We find the last beginning-of-paragraph line before the current
2068 * line. */
2069void do_para_begin(void)
2070{
2071 const filestruct *old_current = current;
2072 const size_t old_pww = placewewant;
2073
2074 current_x = 0;
2075 placewewant = 0;
2076
2077 if (current->prev != NULL) {
2078 do {
2079 current = current->prev;
2080 } while (!begpar(current));
2081 }
2082
2083 edit_redraw(old_current, old_pww);
2084}
2085
2086bool inpar(const char *str)
2087{
2088 size_t quote_len = quote_length(str);
2089
2090 return str[quote_len + indent_length(str + quote_len)] != '\0';
2091}
2092
2093/* A line is the last line of a paragraph if it is in a paragraph, and
2094 * the next line isn't, or is the beginning of a paragraph. We move
2095 * down to the end of a paragraph, then one line farther. */
2096void do_para_end(void)
2097{
2098 const filestruct *const old_current = current;
2099 const size_t old_pww = placewewant;
2100
2101 current_x = 0;
2102 placewewant = 0;
2103
2104 while (current->next != NULL && !inpar(current->data))
2105 current = current->next;
2106
2107 while (current->next != NULL && inpar(current->next->data) &&
2108 !begpar(current->next))
2109 current = current->next;
2110
2111 if (current->next != NULL)
2112 current = current->next;
2113
2114 edit_redraw(old_current, old_pww);
2115}
2116
Chris Allegretta6df90f52002-07-19 01:08:59 +00002117/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002118 * buffer, not allowing them to be concatenated. We assume there are
2119 * enough lines after first_line. We leave copies of the lines in
2120 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002121filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2122 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002123{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002124 /* We put the original lines, not copies, into the cutbuffer, just
2125 * out of a misguided sense of consistency, so if you uncut, you get
2126 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002127 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002128
2129 set_modified();
2130 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002131 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002132 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002133
Chris Allegretta908f7702003-01-15 11:18:58 +00002134 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002135 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002136 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002137 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002138 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002139 edittop = bob;
2140#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002141 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002142 mark_beginbuf = bob;
2143#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002144
Chris Allegretta908f7702003-01-15 11:18:58 +00002145 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002146 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002147 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002148 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002149 }
2150 return first_line;
2151}
2152
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002153/* Is it possible to break line at or before goal? */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002154bool breakable(const char *line, int goal)
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002155{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002156 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002157 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002158 return TRUE;
2159
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002160 if (is_cntrl_char(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002161 goal -= 2;
2162 else
2163 goal -= 1;
2164 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002165 /* If goal is not negative, the whole line (one word) was short
2166 * enough. */
2167 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002168}
2169
Chris Allegretta6df90f52002-07-19 01:08:59 +00002170/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002171 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002172 * such space, and force is TRUE, then we find the first space. Anyway,
2173 * we then take the last space in that group of spaces. The terminating
2174 * '\0' counts as a space. */
2175int break_line(const char *line, int goal, bool force)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002176{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002177 /* Note that we use int instead of size_t, since goal is at most
2178 * COLS, the screen width, which will always be reasonably small. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002179 int space_loc = -1;
2180 /* Current tentative return value. Index of the last space we
2181 * found with short enough display width. */
2182 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002183 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002184
2185 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002186 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002187 if (*line == ' ')
2188 space_loc = cur_loc;
2189 assert(*line != '\t');
2190
Chris Allegrettacf287c82002-07-20 13:57:41 +00002191 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002192 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002193 else
2194 goal--;
2195 }
2196 if (goal >= 0)
2197 /* In fact, the whole line displays shorter than goal. */
2198 return cur_loc;
2199 if (space_loc == -1) {
2200 /* No space found short enough. */
2201 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002202 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002203 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002204 return cur_loc;
2205 return -1;
2206 }
2207 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002208 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002209 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2210 *(line - cur_loc + space_loc + 1) == '\0')
2211 space_loc++;
2212 return space_loc;
2213}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002214
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002215/* Find the beginning of the current paragraph if we're in one, or the
2216 * beginning of the next paragraph if we're not. Afterwards, save the
2217 * quote length and paragraph length in *quote and *par. Return FALSE
2218 * if we found a paragraph, or TRUE if there was an error or we didn't
2219 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002220 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002221 * See the comment at begpar() for more about when a line is the
2222 * beginning of a paragraph. */
2223bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002224{
2225 size_t quote_len;
2226 /* Length of the initial quotation of the paragraph we
2227 * search. */
2228 size_t par_len;
2229 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002230 size_t indent_len;
2231 /* Generic indentation length. */
2232 filestruct *line;
2233 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002234
2235#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002236 if (quoterc != 0) {
2237 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2238 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002239 }
2240#endif
2241
2242 /* Here is an assumption that is always true anyway. */
2243 assert(current != NULL);
2244
2245 current_x = 0;
2246
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002247 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002248 indent_len = indent_length(current->data + quote_len);
2249
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002250 /* Here we find the first line of the paragraph to search. If the
2251 * current line is in a paragraph, then we move back to the first
2252 * line of the paragraph. Otherwise, we move to the first line that
2253 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002254 if (current->data[quote_len + indent_len] != '\0') {
2255 /* This line is part of a paragraph. So we must search back to
2256 * the first line of this paragraph. First we check items 1)
2257 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002258 while (current->prev != NULL && quotes_match(current->data,
2259 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002260 size_t temp_id_len =
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00002261 indent_length(current->prev->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002262 /* The indentation length of the previous line. */
2263
2264 /* Is this line the beginning of a paragraph, according to
2265 * items 2), 5), or 4) above? If so, stop. */
2266 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002267 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002268#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002269 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002270#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002271 ) || !indents_match(current->prev->data + quote_len,
2272 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002273 break;
2274 indent_len = temp_id_len;
2275 current = current->prev;
2276 current_y--;
2277 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002278 } else {
2279 /* This line is not part of a paragraph. Move down until we get
2280 * to a non "blank" line. */
2281 do {
2282 /* There is no next paragraph, so nothing to move to. */
2283 if (current->next == NULL) {
2284 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002285 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002286 }
2287 current = current->next;
2288 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002289 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002290 indent_len = indent_length(current->data + quote_len);
2291 } while (current->data[quote_len + indent_len] == '\0');
2292 }
2293
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002294 /* Now current is the first line of the paragraph, and quote_len is
2295 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002296
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002297 /* Next step, compute par_len, the number of lines in this
2298 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002299 line = current;
2300 par_len = 1;
2301 indent_len = indent_length(line->data + quote_len);
2302
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002303 while (line->next != NULL &&
2304 quotes_match(current->data, quote_len, line->next->data)) {
2305 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002306
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002307 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002308 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002309 line->next->data[quote_len + temp_id_len] == '\0' ||
2310 (quote_len == 0 && temp_id_len > 0
2311#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002312 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002313#endif
2314 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002315 break;
2316 indent_len = temp_id_len;
2317 line = line->next;
2318 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002319 }
2320
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002321 /* Now par_len is the number of lines in this paragraph. We should
2322 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002323
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002324 /* Save the values of quote_len and par_len. */
2325 assert(quote != NULL && par != NULL);
2326 *quote = quote_len;
2327 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002328
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002329 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002330}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002331
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002332/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2333 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002334void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002335{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002336 filestruct *first_par_line = NULL;
2337 /* Will be the first line of the resulting justified paragraph.
2338 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002339 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002340 /* Will be the last line of the result, also for uncut. */
2341 filestruct *cutbuffer_save = cutbuffer;
2342 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002343 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002344 * original to restore it later. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002345 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002346 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002347 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002348 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002349
2350 /* We save these global variables to be restored if the user
2351 * unjustifies. Note we don't need to save totlines. */
2352 int current_x_save = current_x;
2353 int current_y_save = current_y;
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002354 long flags_save = flags;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002355 long totsize_save = totsize;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002356 filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002357 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002358#ifndef NANO_SMALL
2359 filestruct *mark_beginbuf_save = mark_beginbuf;
2360 int mark_beginx_save = mark_beginx;
2361#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002362 int kbinput;
2363 int meta_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002364
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002365 /* If we're justifying the entire file, start at the beginning. */
2366 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002367 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002368
2369 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002370
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002371 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002372 size_t quote_len;
2373 /* Length of the initial quotation of the paragraph we
2374 * justify. */
2375 size_t par_len;
2376 /* Number of lines in that paragraph. */
2377
2378 /* Find the first line of the paragraph to be justified. That
2379 * is the start of this paragraph if we're in one, or the start
2380 * of the next otherwise. Save the quote length and paragraph
2381 * length (number of lines). Don't refresh the screen yet
2382 * (since we'll do that after we justify). If the search failed
2383 * and we're justifying the whole file, move the last line of
2384 * the text we're justifying to just before the magicline, which
2385 * is where it'll be anyway if we've searched the entire file,
2386 * and break out of the loop; otherwise, refresh the screen and
2387 * get out. */
2388 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002389 if (full_justify) {
2390 /* This should be safe in the event of filebot->prev's
2391 * being NULL, since only last_par_line->next is used if
2392 * we eventually unjustify. */
2393 last_par_line = filebot->prev;
2394 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002395 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002396 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002397 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002398 }
2399 }
2400
2401 /* Next step, we loop through the lines of this paragraph,
2402 * justifying each one individually. */
2403 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002404 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002405 size_t line_len;
2406 size_t display_len;
2407 /* The width of current in screen columns. */
2408 int break_pos;
2409 /* Where we will break the line. */
2410
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002411 /* We'll be moving to the next line after justifying the
2412 * current line in almost all cases, so allow changing the
2413 * spacing at the ends of justified lines by default. */
2414 allow_respacing = TRUE;
2415
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002416 indent_len = quote_len + indent_length(current->data +
2417 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002418
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002419 /* If we haven't already done it, copy the original
2420 * paragraph to the cutbuffer for unjustification. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002421 if (first_par_line == NULL)
2422 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002423 filebot->lineno - current->lineno : par_len, quote_len);
2424
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002425 /* Now we call justify_format() on the current line of the
2426 * paragraph, which will remove excess spaces from it and
2427 * change tabs to spaces. */
2428 justify_format(current, quote_len +
2429 indent_length(current->data + quote_len));
2430
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002431 line_len = strlen(current->data);
2432 display_len = strlenpt(current->data);
2433
2434 if (display_len > fill) {
2435 /* The line is too long. Try to wrap it to the next. */
2436 break_pos = break_line(current->data + indent_len,
2437 fill - strnlenpt(current->data, indent_len), TRUE);
2438 if (break_pos == -1 || break_pos + indent_len == line_len)
2439 /* We can't break the line, or don't need to, so
2440 * just go on to the next. */
2441 goto continue_loc;
2442 break_pos += indent_len;
2443 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002444 if (par_len == 1) {
2445 /* There is no next line in this paragraph. We make
2446 * a new line and copy text after break_pos into
2447 * it. */
2448 splice_node(current, make_new_node(current), current->next);
2449 /* In a non-quoted paragraph, we copy the indent
2450 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002451 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002452#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002453 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002454#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002455 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002456 indent_len = 0;
2457 current->next->data = charalloc(indent_len + line_len -
2458 break_pos);
2459 strncpy(current->next->data, current->data, indent_len);
2460 strcpy(current->next->data + indent_len,
2461 current->data + break_pos + 1);
2462 assert(strlen(current->next->data) ==
2463 indent_len + line_len - break_pos - 1);
2464 totlines++;
2465 totsize += indent_len;
2466 par_len++;
2467 } else {
2468 size_t next_line_len = strlen(current->next->data);
2469
2470 indent_len = quote_len +
2471 indent_length(current->next->data + quote_len);
2472 current->next->data = charealloc(current->next->data,
2473 next_line_len + line_len - break_pos + 1);
2474
2475 charmove(current->next->data + indent_len + line_len -
2476 break_pos, current->next->data + indent_len,
2477 next_line_len - indent_len + 1);
2478 strcpy(current->next->data + indent_len,
2479 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002480 current->next->data[indent_len + line_len -
2481 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002482#ifndef NANO_SMALL
2483 if (mark_beginbuf == current->next) {
2484 if (mark_beginx < indent_len)
2485 mark_beginx = indent_len;
2486 mark_beginx += line_len - break_pos;
2487 }
2488#endif
2489 }
2490#ifndef NANO_SMALL
2491 if (mark_beginbuf == current && mark_beginx > break_pos) {
2492 mark_beginbuf = current->next;
2493 mark_beginx -= break_pos + 1 - indent_len;
2494 }
2495#endif
2496 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002497
2498 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002499 current = current->next;
2500 } else if (display_len < fill && par_len > 1) {
2501 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002502
2503 indent_len = quote_len +
2504 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002505 /* If we can't pull a word from the next line up to this
2506 * one, just go on. */
2507 if (!breakable(current->next->data + indent_len,
2508 fill - display_len - 1))
2509 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002510
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002511 break_pos = break_line(current->next->data + indent_len,
2512 fill - display_len - 1, FALSE);
2513 assert(break_pos != -1);
2514
2515 current->data = charealloc(current->data,
2516 line_len + break_pos + 2);
2517 current->data[line_len] = ' ';
2518 strncpy(current->data + line_len + 1,
2519 current->next->data + indent_len, break_pos);
2520 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002521#ifndef NANO_SMALL
2522 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002523 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002524 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002525 if (mark_beginx <= indent_len)
2526 mark_beginx = line_len + 1;
2527 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002528 mark_beginx = line_len + 1 + mark_beginx -
2529 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002530 } else
2531 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002532 }
2533#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002534 next_line_len = strlen(current->next->data);
2535 if (indent_len + break_pos == next_line_len) {
2536 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002537
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002538 /* Don't destroy edittop! */
2539 if (line == edittop)
2540 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002541
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002542 unlink_node(line);
2543 delete_node(line);
2544 totlines--;
2545 totsize -= indent_len;
2546 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002547
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002548 /* Don't go to the next line. Accordingly, don't
2549 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002550 * previous justified line, so that we don't end up
2551 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002552 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002553 } else {
2554 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002555 current->next->data + indent_len + break_pos + 1,
2556 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002557 null_at(&current->next->data, next_line_len - break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002558
2559 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002560 current = current->next;
2561 }
2562 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002563 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002564 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002565 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002566
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002567 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002568 * current line. If the justified line was not the last
2569 * line of the paragraph, add a space to the end of it to
2570 * replace the one removed or left out by justify_format().
2571 * If it was the last line of the paragraph, and
2572 * justify_format() left a space on the end of it, remove
2573 * the space. */
2574 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002575 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002576
2577 if (par_len > 1) {
2578 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002579 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002580 current->prev->data[prev_line_len] = ' ';
2581 current->prev->data[prev_line_len + 1] = '\0';
2582 totsize++;
2583 } else if (par_len == 1 &&
2584 current->prev->data[prev_line_len - 1] == ' ') {
2585 current->prev->data = charealloc(current->prev->data,
2586 prev_line_len);
2587 current->prev->data[prev_line_len - 1] = '\0';
2588 totsize--;
2589 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002590 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002591 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002592
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002593 /* We've just justified a paragraph. If we're not justifying the
2594 * entire file, break out of the loop. Otherwise, continue the
2595 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002596 if (!full_justify)
2597 break;
2598
2599 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002600
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002601 /* We are now done justifying the paragraph or the file, so clean
2602 * up. totlines, totsize, and current_y have been maintained above.
2603 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002604 * fileage, and renumber() since edit_refresh() needs the line
2605 * numbers to be right (but only do the last two if we actually
2606 * justified something). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002607 last_par_line = current->prev;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002608 if (first_par_line != NULL) {
2609 if (first_par_line->prev == NULL)
2610 fileage = first_par_line;
2611 renumber(first_par_line);
2612 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002613
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002614 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002615
Chris Allegretta9149e612000-11-27 00:23:41 +00002616 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002617 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002618 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002619 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002620
Chris Allegretta6df90f52002-07-19 01:08:59 +00002621 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002622 * keystroke and return. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002623 kbinput = get_kbinput(edit, &meta_key);
Chris Allegretta5f071802001-05-06 02:34:31 +00002624
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002625#ifndef DISABLE_MOUSE
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002626 /* If it was a mouse click, parse it with do_mouse() and it might
2627 * become the unjustify key. Else give it back to the input
2628 * stream. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002629 if (kbinput == KEY_MOUSE) {
2630 do_mouse();
2631 kbinput = get_kbinput(edit, &meta_key);
2632 }
2633#endif
2634
2635 if (meta_key || (kbinput != NANO_UNJUSTIFY_KEY &&
2636 kbinput != NANO_UNJUSTIFY_FKEY)) {
2637 ungetch(kbinput);
2638 if (meta_key)
2639 ungetch(NANO_CONTROL_3);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002640 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002641 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002642 /* Else restore the justify we just did (ungrateful user!). */
2643 filestruct *cutbottom = get_cutbottom();
2644
Chris Allegretta6df90f52002-07-19 01:08:59 +00002645 current = current_save;
2646 current_x = current_x_save;
2647 current_y = current_y_save;
2648 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002649
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002650 /* Splice the cutbuffer back into the file, but only if we
2651 * actually justified something. */
2652 if (first_par_line != NULL) {
2653 cutbottom->next = last_par_line->next;
2654 cutbottom->next->prev = cutbottom;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002655 /* The line numbers after the end of the paragraph have been
2656 * changed, so we change them back. */
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002657 renumber(cutbottom->next);
2658 if (first_par_line->prev != NULL) {
2659 cutbuffer->prev = first_par_line->prev;
2660 cutbuffer->prev->next = cutbuffer;
2661 } else
2662 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002663
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002664 last_par_line->next = NULL;
2665 free_filestruct(first_par_line);
2666 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002667
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002668 /* Restore global variables from before the justify. */
2669 totsize = totsize_save;
2670 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002672 mark_beginbuf = mark_beginbuf_save;
2673 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002674#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002675 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002676 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002677 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002678 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002679 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002680
Chris Allegretta6df90f52002-07-19 01:08:59 +00002681 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002682 /* Note that now cutbottom is invalid, but that's okay. */
2683 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002684 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002685 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002686 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002687}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002688
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002689void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002690{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002691 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002692}
2693
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002694void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002695{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002696 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002697}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002698#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002699
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002700void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002701{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002702 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002703
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002704 if (!ISSET(MODIFIED))
2705 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002706 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002707 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002708 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002709 i = do_yesno(FALSE,
2710 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2711
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002712#ifdef DEBUG
2713 dump_buffer(fileage);
2714#endif
2715
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002716 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002717#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002718 /* Exit only if there are no more open buffers. */
2719 if (close_open_file() != 0)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002720#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002721 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002722 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002723 statusbar(_("Cancelled"));
2724
2725 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002726}
2727
2728void signal_init(void)
2729{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002730 /* Trap SIGINT and SIGQUIT because we want them to do useful
2731 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002732 memset(&act, 0, sizeof(struct sigaction));
2733 act.sa_handler = SIG_IGN;
2734 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002735 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002736
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002737 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002738 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002739 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002740 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002741
2742#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002743 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002744 act.sa_handler = handle_sigwinch;
2745 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002746 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002747#endif
2748
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002749 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002750 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002751 act.sa_handler = SIG_IGN;
2752 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002753 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002754 /* Block all other signals in the suspend and continue handlers.
2755 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002756 sigfillset(&act.sa_mask);
2757
2758 act.sa_handler = do_suspend;
2759 sigaction(SIGTSTP, &act, NULL);
2760
2761 act.sa_handler = do_cont;
2762 sigaction(SIGCONT, &act, NULL);
2763 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002764}
2765
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002766/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002767RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002768{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002769 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002770}
2771
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002772/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002773RETSIGTYPE do_suspend(int signal)
2774{
2775 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002776 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002777 fflush(stdout);
2778
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002779 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002780 tcsetattr(0, TCSANOW, &oldterm);
2781
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002782 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002783 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002784 act.sa_handler = handle_hupterm;
2785 sigaction(SIGHUP, &act, NULL);
2786 sigaction(SIGTERM, &act, NULL);
2787
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002788 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002789 kill(0, SIGSTOP);
2790}
2791
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002792/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002793RETSIGTYPE do_cont(int signal)
2794{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002796 /* Perhaps the user resized the window while we slept. Handle it
2797 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002798 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002799#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002800 /* Just update the screen. */
2801 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002802#endif
2803}
2804
2805#ifndef NANO_SMALL
2806void handle_sigwinch(int s)
2807{
2808 const char *tty = ttyname(0);
2809 int fd;
2810 int result = 0;
2811 struct winsize win;
2812
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002813 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002814 return;
2815 fd = open(tty, O_RDWR);
2816 if (fd == -1)
2817 return;
2818 result = ioctl(fd, TIOCGWINSZ, &win);
2819 close(fd);
2820 if (result == -1)
2821 return;
2822
2823 /* Could check whether the COLS or LINES changed, and return
2824 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2825 * variables, and in some cases ncurses has already updated them.
2826 * But not in all cases, argh. */
2827 COLS = win.ws_col;
2828 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002829 editwinrows = LINES - 5 + no_help();
2830 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002831 die_too_small();
2832
2833#ifndef DISABLE_WRAPJUSTIFY
2834 fill = wrap_at;
2835 if (fill <= 0)
2836 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002837 if (fill < 0)
2838 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002839#endif
2840
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002841 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002842 memset(hblank, ' ', COLS);
2843 hblank[COLS] = '\0';
2844
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002845#ifdef USE_SLANG
2846 /* Slang curses emulation brain damage, part 1: If we just do what
2847 * curses does here, it'll only work properly if the resize made the
2848 * window smaller. Do what mutt does: Leave and immediately reenter
2849 * Slang screen management mode. */
2850 SLsmg_reset_smg();
2851 SLsmg_init_smg();
2852#else
2853 /* Do the equivalent of what Minimum Profit does: Leave and
2854 * immediately reenter curses mode. */
2855 endwin();
2856 refresh();
2857#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002858
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002859 /* Restore the terminal to its previous state. */
2860 terminal_init();
2861
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002862 /* Do the equivalent of what both mutt and Minimum Profit do:
2863 * Reinitialize all the windows based on the new screen
2864 * dimensions. */
2865 window_init();
2866
2867 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002868 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002869 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002870 total_refresh();
2871
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002872 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002873 curs_set(1);
2874
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002875 /* Reset all the input routines that rely on character sequences. */
2876 reset_kbinput();
2877
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002878 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002879 siglongjmp(jmpbuf, 1);
2880}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002881
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002882void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002883{
2884 sigset_t winch;
2885 sigemptyset(&winch);
2886 sigaddset(&winch, SIGWINCH);
2887 if (allow)
2888 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2889 else
2890 sigprocmask(SIG_BLOCK, &winch, NULL);
2891}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002892#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002893
Chris Allegrettadab017e2002-04-23 10:56:06 +00002894#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002895void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002896{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002897 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002898
Chris Allegretta658399a2001-06-14 02:54:22 +00002899 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002900 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002901
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002902 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002903 case TOGGLE_SUSPEND_KEY:
2904 signal_init();
2905 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002906#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002907 case TOGGLE_MOUSE_KEY:
2908 mouse_init();
2909 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002910#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002911 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002912 blank_statusbar();
2913 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002914 wrefresh(bottomwin);
2915 window_init();
2916 edit_refresh();
2917 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002918 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002919 case TOGGLE_DOS_KEY:
2920 UNSET(MAC_FILE);
2921 break;
2922 case TOGGLE_MAC_KEY:
2923 UNSET(DOS_FILE);
2924 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002925#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002926 case TOGGLE_SYNTAX_KEY:
2927 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002928 break;
2929#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002930#ifdef ENABLE_NANORC
2931 case TOGGLE_WHITESPACE_KEY:
2932 edit_refresh();
2933 break;
2934#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002935 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002936
Chris Allegretta6df90f52002-07-19 01:08:59 +00002937 /* We are assuming here that shortcut_init() above didn't free and
2938 * reallocate the toggles. */
2939 enabled = ISSET(which->flag);
2940 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2941 enabled = !enabled;
2942 statusbar("%s %s", which->desc,
2943 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002944}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002945#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002946
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002947void disable_signals(void)
2948{
2949 struct termios term;
2950
2951 tcgetattr(0, &term);
2952 term.c_lflag &= ~ISIG;
2953 tcsetattr(0, TCSANOW, &term);
2954}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002955
2956#ifndef NANO_SMALL
2957void enable_signals(void)
2958{
2959 struct termios term;
2960
2961 tcgetattr(0, &term);
2962 term.c_lflag |= ISIG;
2963 tcsetattr(0, TCSANOW, &term);
2964}
2965#endif
2966
2967void disable_flow_control(void)
2968{
2969 struct termios term;
2970
2971 tcgetattr(0, &term);
2972 term.c_iflag &= ~(IXON|IXOFF);
2973 tcsetattr(0, TCSANOW, &term);
2974}
2975
2976void enable_flow_control(void)
2977{
2978 struct termios term;
2979
2980 tcgetattr(0, &term);
2981 term.c_iflag |= (IXON|IXOFF);
2982 tcsetattr(0, TCSANOW, &term);
2983}
2984
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002985/* Set up the terminal state. Put the terminal in cbreak mode (read one
2986 * character at a time and interpret the special control keys), disable
2987 * translation of carriage return (^M) into newline (^J) so that we can
2988 * tell the difference between the Enter key and Ctrl-J, and disable
2989 * echoing of characters as they're typed. Finally, disable
2990 * interpretation of the special control keys, and if we're not in
2991 * preserve mode, disable interpretation of the flow control characters
2992 * too. */
2993void terminal_init(void)
2994{
2995 cbreak();
2996 nonl();
2997 noecho();
2998 disable_signals();
2999 if (!ISSET(PRESERVE))
3000 disable_flow_control();
3001}
3002
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003003int main(int argc, char *argv[])
3004{
3005 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003006 int startline = 0; /* Line to try and start at */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003007#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003008 bool fill_flag_used = FALSE; /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003009#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003010 const shortcut *s;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003011 bool keyhandled = FALSE; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003012 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003013 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003014
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003015#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003016 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003017#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003018#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003019 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003020 {"help", 0, 0, 'h'},
3021#ifdef ENABLE_MULTIBUFFER
3022 {"multibuffer", 0, 0, 'F'},
3023#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003024#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003025#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003026 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003027#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003028 {"ignorercfiles", 0, 0, 'I'},
3029#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003030#ifndef DISABLE_JUSTIFY
3031 {"quotestr", 1, 0, 'Q'},
3032#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003033#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003034 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003035#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003036 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003037 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003038#ifdef ENABLE_COLOR
3039 {"syntax", 1, 0, 'Y'},
3040#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003041 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003042 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003043 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003044#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003045 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003046#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003047#ifndef DISABLE_OPERATINGDIR
3048 {"operatingdir", 1, 0, 'o'},
3049#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003050 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003051#ifndef DISABLE_WRAPJUSTIFY
3052 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003053#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054#ifndef DISABLE_SPELLER
3055 {"speller", 1, 0, 's'},
3056#endif
3057 {"tempfile", 0, 0, 't'},
3058 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003059#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003060 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003061#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062 {"nohelp", 0, 0, 'x'},
3063 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003064#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003065 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003066 {"backup", 0, 0, 'B'},
3067 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003068 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003069 {"mac", 0, 0, 'M'},
3070 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003071 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003072 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003073 {"autoindent", 0, 0, 'i'},
3074 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003075#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003076 {0, 0, 0, 0}
3077 };
3078#endif
3079
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003080 setlocale(LC_ALL, "");
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003081#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003082 bindtextdomain(PACKAGE, LOCALEDIR);
3083 textdomain(PACKAGE);
3084#endif
3085
Chris Allegretta7662c862003-01-13 01:35:15 +00003086#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003087 /* if we don't have rcfile support, we're root, and
3088 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003089 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003090 SET(NO_WRAP);
3091#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003092
Chris Allegretta6df90f52002-07-19 01:08:59 +00003093 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003094#ifdef HAVE_GETOPT_LONG
3095 getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
3096#else
3097 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003098#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003099 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003100
3101 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003102 case 'a':
3103 case 'b':
3104 case 'e':
3105 case 'f':
3106 case 'g':
3107 case 'j':
3108 /* Pico compatibility flags. */
3109 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003110#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003111 case 'A':
3112 SET(SMART_HOME);
3113 break;
3114 case 'B':
3115 SET(BACKUP_FILE);
3116 break;
3117 case 'D':
3118 SET(DOS_FILE);
3119 break;
3120 case 'E':
3121 backup_dir = mallocstrcpy(backup_dir, optarg);
3122 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003123#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003124#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003125 case 'F':
3126 SET(MULTIBUFFER);
3127 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003128#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003129#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003130#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003131 case 'H':
3132 SET(HISTORYLOG);
3133 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003134#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003135 case 'I':
3136 SET(NO_RCFILE);
3137 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003138#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003139#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003140 case 'M':
3141 SET(MAC_FILE);
3142 break;
3143 case 'N':
3144 SET(NO_CONVERT);
3145 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003146#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003147#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003148 case 'Q':
3149 quotestr = mallocstrcpy(quotestr, optarg);
3150 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003151#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003152#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003153 case 'R':
3154 SET(USE_REGEXP);
3155 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003156#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003157#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003158 case 'S':
3159 SET(SMOOTHSCROLL);
3160 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003161#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003162 case 'T':
3163 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003164 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
3165 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003166 exit(1);
3167 }
3168 break;
3169 case 'V':
3170 version();
3171 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003172#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003173 case 'Y':
3174 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3175 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00003176#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003177 case 'Z':
3178 SET(RESTRICTED);
3179 break;
3180 case 'c':
3181 SET(CONSTUPDATE);
3182 break;
3183 case 'd':
3184 SET(REBIND_DELETE);
3185 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003186#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003187 case 'i':
3188 SET(AUTOINDENT);
3189 break;
3190 case 'k':
3191 SET(CUT_TO_END);
3192 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003193#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003194 case 'l':
3195 SET(NOFOLLOW_SYMLINKS);
3196 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003197#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003198 case 'm':
3199 SET(USE_MOUSE);
3200 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003201#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003202#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003203 case 'o':
3204 operating_dir = mallocstrcpy(operating_dir, optarg);
3205 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003206#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003207 case 'p':
3208 SET(PRESERVE);
3209 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003210#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003211 case 'r':
3212 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003213 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
3214 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003215 exit(1);
3216 }
3217 fill_flag_used = TRUE;
3218 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003219#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003220#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003221 case 's':
3222 alt_speller = mallocstrcpy(alt_speller, optarg);
3223 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003224#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003225 case 't':
3226 SET(TEMP_FILE);
3227 break;
3228 case 'v':
3229 SET(VIEW_MODE);
3230 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003231#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003232 case 'w':
3233 SET(NO_WRAP);
3234 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003235#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003236 case 'x':
3237 SET(NO_HELP);
3238 break;
3239 case 'z':
3240 SET(SUSPEND);
3241 break;
3242 default:
3243 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003244 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003245 }
3246
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003247 /* If the executable filename starts with 'r', we use restricted
3248 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003249 if (*(tail(argv[0])) == 'r')
3250 SET(RESTRICTED);
3251
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003252 /* If we're using restricted mode, disable suspending, backups, and
3253 * reading rcfiles, since they all would allow reading from or
3254 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003255 if (ISSET(RESTRICTED)) {
3256 UNSET(SUSPEND);
3257 UNSET(BACKUP_FILE);
3258 SET(NO_RCFILE);
3259 }
3260
Chris Allegretta7662c862003-01-13 01:35:15 +00003261/* We've read through the command line options. Now back up the flags
3262 and values that are set, and read the rcfile(s). If the values
3263 haven't changed afterward, restore the backed-up values. */
3264#ifdef ENABLE_NANORC
3265 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003266#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003267 char *operating_dir_cpy = operating_dir;
3268#endif
David Lawrence Ramsey7e8dd192004-08-12 20:06:20 +00003269#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003270 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003271#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003272#ifndef NANO_SMALL
3273 char *backup_dir_cpy = backup_dir;
3274#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003275#ifndef DISABLE_JUSTIFY
3276 char *quotestr_cpy = quotestr;
3277#endif
3278#ifndef DISABLE_SPELLER
3279 char *alt_speller_cpy = alt_speller;
3280#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003281 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003282 long flags_cpy = flags;
3283
Chris Allegretta5ec68622003-02-05 02:39:34 +00003284#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003285 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003286#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003287#ifndef NANO_SMALL
3288 backup_dir = NULL;
3289#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003290#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003291 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003292#endif
3293#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003294 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003295#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003296
3297 do_rcfile();
3298
3299#ifndef DISABLE_OPERATINGDIR
3300 if (operating_dir_cpy != NULL) {
3301 free(operating_dir);
3302 operating_dir = operating_dir_cpy;
3303 }
3304#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003305#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003306 if (fill_flag_used)
3307 wrap_at = wrap_at_cpy;
3308#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003309#ifndef NANO_SMALL
3310 if (backup_dir_cpy != NULL) {
3311 free(backup_dir);
3312 backup_dir = backup_dir_cpy;
3313 }
3314#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003315#ifndef DISABLE_JUSTIFY
3316 if (quotestr_cpy != NULL) {
3317 free(quotestr);
3318 quotestr = quotestr_cpy;
3319 }
3320#endif
3321#ifndef DISABLE_SPELLER
3322 if (alt_speller_cpy != NULL) {
3323 free(alt_speller);
3324 alt_speller = alt_speller_cpy;
3325 }
3326#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00003327 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00003328 tabsize = tabsize_cpy;
3329 flags |= flags_cpy;
3330 }
3331#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003332 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003333 SET(NO_WRAP);
3334#endif
3335#endif /* ENABLE_NANORC */
3336
Chris Allegrettad8451932003-03-11 03:50:40 +00003337#ifndef NANO_SMALL
3338 history_init();
3339#ifdef ENABLE_NANORC
3340 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3341 load_history();
3342#endif
3343#endif
3344
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003345#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003346 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003347 * in which case backups are disabled, since they would allow
3348 * reading from or writing to files not specified on the command
3349 * line). This entails making sure it exists and is a directory, so
3350 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003351 if (!ISSET(RESTRICTED))
3352 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003353#endif
3354
Chris Allegretta7662c862003-01-13 01:35:15 +00003355#ifndef DISABLE_OPERATINGDIR
3356 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003357 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003358 init_operating_dir();
3359#endif
3360
Chris Allegretta7662c862003-01-13 01:35:15 +00003361#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003362 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003363 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003364
3365 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003366 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003367
Chris Allegretta7662c862003-01-13 01:35:15 +00003368 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003369 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003370#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003371 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003372#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003373 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003374#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003375 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003376#ifdef HAVE_REGEX_H
3377 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
3378
3379 if (quoterc == 0) {
3380 /* We no longer need quotestr, just quotereg. */
3381 free(quotestr);
3382 quotestr = NULL;
3383 } else {
3384 size_t size = regerror(quoterc, &quotereg, NULL, 0);
3385
3386 quoteerr = charalloc(size);
3387 regerror(quoterc, &quotereg, quoteerr, size);
3388 }
3389#else
3390 quotelen = strlen(quotestr);
3391#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00003392#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003393
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003394#ifndef DISABLE_SPELLER
3395 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003396 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003397 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003398 * checking is disabled, since it would allow reading from or
3399 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003400 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003401 char *spellenv = getenv("SPELL");
3402 if (spellenv != NULL)
3403 alt_speller = mallocstrcpy(NULL, spellenv);
3404 }
3405#endif
3406
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003407#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
3408 if (whitespace == NULL)
3409 whitespace = mallocstrcpy(NULL, " ");
3410#endif
3411
Chris Allegretta7662c862003-01-13 01:35:15 +00003412 if (tabsize == -1)
3413 tabsize = 8;
3414
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003415 /* Clear the filename we'll be using */
3416 filename = charalloc(1);
3417 filename[0] = '\0';
3418
Chris Allegretta7662c862003-01-13 01:35:15 +00003419 /* If there's a +LINE flag, it is the first non-option argument. */
3420 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3421 startline = atoi(&argv[optind][1]);
3422 optind++;
3423 }
3424 if (0 < optind && optind < argc)
3425 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003426
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003427 /* See if there's a non-option in argv (first non-option is the
3428 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003429 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003430 /* Look for the +line flag... */
3431 if (argv[optind][0] == '+') {
3432 startline = atoi(&argv[optind][1]);
3433 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003434 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003435 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003436 } else
3437 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003438 }
3439
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003440 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003441 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003442
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003443 /* Curses initialization stuff: Start curses and set up the
3444 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003445 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003446 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003447
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003448 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003449 global_init(FALSE);
3450 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003451
3452 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003453 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003454
3455#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003456 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003457#endif
3458
Chris Allegretta2a42af12000-09-12 23:02:49 +00003459 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003460#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003461 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003462#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003463
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003464#ifdef DEBUG
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003465 fprintf(stderr, "Main: top and bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003466#endif
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003467 titlebar(NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003468 display_main_list();
3469
3470#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003471 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003472#endif
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003473 open_file(filename, FALSE, FALSE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003474#ifdef ENABLE_MULTIBUFFER
3475 /* If we're using multibuffers and more than one file is specified
3476 on the command line, load them all and switch to the first one
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003477 afterward. */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003478 if (optind + 1 < argc) {
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003479 bool old_multibuffer = ISSET(MULTIBUFFER), list = FALSE;
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003480 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003481 for (optind++; optind < argc; optind++) {
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003482 add_open_file(TRUE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003483 new_file();
3484 filename = mallocstrcpy(filename, argv[optind]);
David Lawrence Ramsey6b248562004-08-07 22:33:14 +00003485 titlebar(NULL);
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003486 open_file(filename, FALSE, FALSE);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003487 load_file(FALSE);
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003488 /* Display the main list with "Close" if we haven't
3489 * already. */
3490 if (!list) {
3491 shortcut_init(FALSE);
3492 list = TRUE;
3493 display_main_list();
3494 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003495 }
3496 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003497 if (!old_multibuffer)
3498 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003499 }
3500#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003501
3502 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003503 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003504
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003505#ifndef NANO_SMALL
3506 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003507 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003508#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003509
Robert Siemborski6967eec2000-07-08 14:23:32 +00003510 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00003511
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003512 while (TRUE) {
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003513 keyhandled = FALSE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003514
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00003515 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003516 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003517 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003518
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003519#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003520 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003521#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003522
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003523 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003524#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003525 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003526#endif
David Lawrence Ramsey4d44d2d2004-08-01 22:35:31 +00003527 if (meta_key) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003528 /* Check for the metaval and miscval defs... */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003529 for (s =
3530#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3531 currshortcut
3532#else
3533 main_list
3534#endif
3535 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003536 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003537 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003538 if (ISSET(VIEW_MODE) && !s->viewok)
3539 print_view_warning();
3540 else {
3541 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003542 cutbuffer_reset();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003543 s->func();
3544 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003545 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003546 }
3547#ifndef NANO_SMALL
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003548 if (!keyhandled) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003549 /* And for toggle switches */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003550 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003551 if (kbinput == t->val) {
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003552 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003553 do_toggle(t);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003554 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003555 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003556 }
3557 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003558#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003559 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003560#ifdef DEBUG
David Lawrence Ramsey331e6592004-07-27 19:40:39 +00003561 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput, kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003562#endif
3563 }
3564
3565 /* Look through the main shortcut list to see if we've hit a
3566 shortcut key or function key */
3567
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003568 if (!keyhandled) {
3569 for (s =
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003570#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003571 currshortcut
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003572#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003573 main_list
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003574#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003575 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003576 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3577 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003578 if (ISSET(VIEW_MODE) && !s->viewok)
3579 print_view_warning();
3580 else {
3581 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003582 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003583 s->func();
3584 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003585 keyhandled = TRUE;
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003586 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003587 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003588 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003589
3590 if (!keyhandled)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003591 cutbuffer_reset();
Chris Allegrettae42df732002-10-15 00:27:55 +00003592
Chris Allegrettae42df732002-10-15 00:27:55 +00003593 /* Don't even think about changing this string */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003594 if (kbinput == NANO_XON_KEY)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003595 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003596 if (kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003597 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003598 if (kbinput == NANO_XON_KEY || kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003599 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003600
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003601 /* Catch ^Z by hand when triggered also */
3602 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003603 if (ISSET(SUSPEND))
3604 do_suspend(0);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003605 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003606 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003607
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003608 /* Last gasp, stuff that's not in the main lists */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003609 if (!keyhandled) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003610 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003611#ifndef DISABLE_MOUSE
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003612 case KEY_MOUSE:
3613 do_mouse();
3614 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003615#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003616 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3617 * have been handled before we
3618 * got here */
3619 case NANO_CONTROL_5: /* Ctrl-] */
3620 break;
3621 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003622#ifdef DEBUG
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003623 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003624#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003625 /* We no longer stop unhandled sequences so that
3626 people with odd character sets can type... */
3627 if (ISSET(VIEW_MODE))
3628 print_view_warning();
3629 else
3630 do_char((char)kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003631 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003632 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003633 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003634 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003635}