blob: 3408b79bb8f00f6c7dec67cfccf2e59a983941bf [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
Jordi Mallach55381aa2004-11-17 23:17:05 +000022#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
Chris Allegretta6efda542001-04-28 18:03:52 +000025
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000026#include <stdio.h>
27#include <stdlib.h>
28#include <stdarg.h>
29#include <signal.h>
30#include <unistd.h>
31#include <string.h>
32#include <fcntl.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000033#include <sys/ioctl.h>
34#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000035#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000036#include <errno.h>
37#include <ctype.h>
38#include <locale.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 Ramsey93c84052004-11-23 04:08:28 +000081#ifndef DISABLE_JUSTIFY
82static filestruct *jusbottom = NULL;
83 /* Pointer to end of justify buffer. */
84#endif
85
David Lawrence Ramseyda141062004-05-25 19:41:11 +000086/* What we do when we're all set to exit. */
87void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000089 if (!ISSET(NO_HELP))
90 blank_bottombars();
91 else
92 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000093
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094 wrefresh(bottomwin);
95 endwin();
96
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000097 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000098 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099
Chris Allegrettad8451932003-03-11 03:50:40 +0000100#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
101 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
102 save_history();
103#endif
104
Chris Allegretta6232d662002-05-12 19:52:15 +0000105#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000106 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000107#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000108
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000109 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000110}
111
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000112/* Die (gracefully?). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000113void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000114{
115 va_list ap;
116
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000117 endwin();
118 curses_ended = TRUE;
119
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000120 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000121 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000122
Chris Allegretta6df90f52002-07-19 01:08:59 +0000123 va_start(ap, msg);
124 vfprintf(stderr, msg, ap);
125 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000126
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000127 /* Save the current file buffer if it's been modified. */
Chris Allegretta32da4562002-01-02 15:12:21 +0000128 if (ISSET(MODIFIED))
129 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000130
Chris Allegretta355fbe52001-07-14 19:32:47 +0000131#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000132 /* Save all of the other modified file buffers, if any. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000133 if (open_files != NULL) {
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000134 openfilestruct *tmp = open_files;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000135
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000136 while (tmp != open_files->next) {
137 open_files = open_files->next;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000138
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000139 /* Save the current file buffer if it's been modified. */
140 if (open_files->flags & MODIFIED) {
141 /* Set fileage and filebot to match the current file
142 * buffer, and then write it to disk. */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000143 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000144 filebot = open_files->filebot;
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000145 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000146 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000148 }
149#endif
150
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000151 /* Get out. */
152 exit(1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153}
154
Chris Allegretta6df90f52002-07-19 01:08:59 +0000155void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000156{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000157 char *ret;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000158 bool failed = TRUE;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000160 /* If we're using restricted mode, don't write any emergency backup
161 * files, since that would allow reading from or writing to files
162 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000163 if (ISSET(RESTRICTED))
164 return;
165
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 /* If we can't save, we have REAL bad problems, but we might as well
167 TRY. */
168 if (die_filename[0] == '\0')
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000169 die_filename = "nano";
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000171 ret = get_next_filename(die_filename);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 if (ret[0] != '\0')
David Lawrence Ramsey951d7142004-10-04 15:23:47 +0000173 failed = (write_file(ret, TRUE, FALSE, TRUE) == -1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000174
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000175 if (!failed)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000176 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000177 else
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000178 fprintf(stderr, _("\nBuffer not written to %s (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000179
180 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000181}
182
Chris Allegrettae61e8302001-01-14 05:18:27 +0000183/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000184 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000185void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000186{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000187 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000188}
189
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000190void print_view_warning(void)
191{
192 statusbar(_("Key illegal in VIEW mode"));
193}
194
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000195/* Initialize global variables -- no better way for now. If
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000196 * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
197void global_init(bool save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000198{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000199 current_x = 0;
200 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000201
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000202 editwinrows = LINES - 5 + no_help();
203 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000204 die_too_small();
205
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000206 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000207 if (!save_cutbuffer)
208 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000209 current = NULL;
210 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000211 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000212 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000214
Chris Allegretta6fe61492001-05-21 12:56:25 +0000215#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000216 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000217 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000218 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000219 if (fill < 0)
220 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000221#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000222
Chris Allegretta88b09152001-05-17 11:35:43 +0000223 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000224 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000225 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000226}
227
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000228void window_init(void)
229{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000230 editwinrows = LINES - 5 + no_help();
231 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000232 die_too_small();
233
Chris Allegretta1a128af2003-01-26 04:15:56 +0000234 if (topwin != NULL)
235 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000236 if (edit != NULL)
237 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000238 if (bottomwin != NULL)
239 delwin(bottomwin);
240
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000241 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000242 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000243 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000244 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
245
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000246 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000247 keypad(edit, TRUE);
248 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249}
250
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000251#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252void mouse_init(void)
253{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000254 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255 mousemask(BUTTON1_RELEASED, NULL);
256 mouseinterval(50);
257 } else
258 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000259}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000260#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000261
262#ifndef DISABLE_HELP
263/* This function allocates help_text, and stores the help string in it.
264 * help_text should be NULL initially. */
265void help_init(void)
266{
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000267 size_t allocsize = 1; /* Space needed for help_text. */
268 const char *htx; /* Untranslated help message. */
269 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000270 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000271#ifndef NANO_SMALL
272 const toggle *t;
273#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000274
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000275 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000276 if (currshortcut == whereis_list || currshortcut == replace_list
277 || currshortcut == replace_list_2)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000278 htx = N_("Search Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000279 "Enter the words or characters you would like to search "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000280 "for, then hit Enter. If there is a match for the text you "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000281 "entered, the screen will be updated to the location of the "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000282 "nearest match for the search string.\n\n The previous "
283 "search string will be shown in brackets after the search "
284 "prompt. Hitting Enter without entering any text will "
285 "perform the previous search. If you have selected text "
286 "with the mark and then search to replace, only matches in "
287 "the selected text will be replaced.\n\n The following "
288 "function keys are available in Search mode:\n\n");
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000289 else if (currshortcut == gotoline_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000290 htx = N_("Go To Line Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000291 "Enter the line number that you wish to go to and hit "
292 "Enter. If there are fewer lines of text than the "
293 "number you entered, you will be brought to the last line "
294 "of the file.\n\n The following function keys are "
295 "available in Go To Line mode:\n\n");
296 else if (currshortcut == insertfile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000297 htx = N_("Insert File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000298 "Type in the name of a file to be inserted into the current "
299 "file buffer at the current cursor location.\n\n "
300 "If you have compiled nano with multiple file buffer "
301 "support, and enable multiple buffers with the -F "
302 "or --multibuffer command line flags, the Meta-F toggle, or "
303 "a nanorc file, inserting a file will cause it to be "
304 "loaded into a separate buffer (use Meta-< and > to switch "
David Lawrence Ramseyfdd3bec2004-11-07 21:30:55 +0000305 "between file buffers). If you need another blank buffer, "
306 "do not enter any filename, or type in a nonexistent "
307 "filename at the prompt and press Enter.\n\n The following "
308 "function keys are available in Insert File mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000309 else if (currshortcut == writefile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000310 htx = N_("Write File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000311 "Type the name that you wish to save the current file "
312 "as and hit Enter to save the file.\n\n If you have "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000313 "selected text with the mark, you will be prompted to "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000314 "save only the selected portion to a separate file. To "
315 "reduce the chance of overwriting the current file with "
316 "just a portion of it, the current filename is not the "
317 "default in this mode.\n\n The following function keys "
318 "are available in Write File mode:\n\n");
319#ifndef DISABLE_BROWSER
320 else if (currshortcut == browser_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000321 htx = N_("File Browser Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000322 "The file browser is used to visually browse the "
323 "directory structure to select a file for reading "
324 "or writing. You may use the arrow keys or Page Up/"
325 "Down to browse through the files, and S or Enter to "
326 "choose the selected file or enter the selected "
327 "directory. To move up one level, select the directory "
328 "called \"..\" at the top of the file list.\n\n The "
329 "following function keys are available in the file "
330 "browser:\n\n");
331 else if (currshortcut == gotodir_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000332 htx = N_("Browser Go To Directory Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000333 "Enter the name of the directory you would like to "
334 "browse to.\n\n If tab completion has not been disabled, "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000335 "you can use the Tab key to (attempt to) automatically "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000336 "complete the directory name.\n\n The following function "
337 "keys are available in Browser Go To Directory mode:\n\n");
338#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000339#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000340 else if (currshortcut == spell_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000341 htx = N_("Spell Check Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000342 "The spell checker checks the spelling of all text "
343 "in the current file. When an unknown word is "
344 "encountered, it is highlighted and a replacement can "
345 "be edited. It will then prompt to replace every "
346 "instance of the given misspelled word in the "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000347 "current file, or, if you have selected text with the "
348 "mark, in the selected text.\n\n The following other "
349 "functions are available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000350#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000351#ifndef NANO_SMALL
352 else if (currshortcut == extcmd_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000353 htx = N_("External Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000354 "This menu allows you to insert the output of a command "
355 "run by the shell into the current buffer (or a new "
David Lawrence Ramseyfdd3bec2004-11-07 21:30:55 +0000356 "buffer in multibuffer mode). If you need another blank "
357 "buffer, do not enter any command.\n\n The following keys "
358 "are available in this mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000359#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000360 else
361 /* Default to the main help list. */
362 htx = N_(" nano help text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000363 "The nano editor is designed to emulate the functionality and "
364 "ease-of-use of the UW Pico text editor. There are four main "
365 "sections of the editor: The top line shows the program "
366 "version, the current filename being edited, and whether "
367 "or not the file has been modified. Next is the main editor "
368 "window showing the file being edited. The status line is "
369 "the third line from the bottom and shows important messages. "
370 "The bottom two lines show the most commonly used shortcuts "
371 "in the editor.\n\n "
372 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000373 "sequences are notated with a caret (^) symbol and can be "
374 "entered either by using the Control (Ctrl) key or pressing the "
375 "Esc key twice. Escape-key sequences are notated with the Meta "
376 "(M) symbol and can be entered using either the Esc, Alt or "
377 "Meta key depending on your keyboard setup. Also, pressing Esc "
378 "twice and then typing a three-digit number from 000 to 255 "
379 "will enter the character with the corresponding ASCII code. "
380 "The following keystrokes are available in the main editor "
381 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000382
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000383 htx = _(htx);
384
385 allocsize += strlen(htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000386
387 /* The space needed for the shortcut lists, at most COLS characters,
388 * plus '\n'. */
David Lawrence Ramsey1f1ebb82004-11-11 21:50:01 +0000389 allocsize += (COLS < 21 ? 21 : COLS + 1) *
390 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 Ramsey1f1ebb82004-11-11 21:50:01 +0000402#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000403
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 Ramseydb6015c2004-09-11 21:41:13 +0000415 /* Now add our shortcut info. Assume that each shortcut has, at the
416 * very least, an equivalent control key, an equivalent primary meta
417 * key sequence, or both. Also assume that the meta key values are
418 * not control characters. We can display a maximum of 3 shortcut
419 * entries. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000420 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000421 int entries = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000422
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000423 /* Control key. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000424 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000425 entries++;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000426#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000427 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000428 ptr += sprintf(ptr, "%.7s", _("Up"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000429 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000430#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000431 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000432 ptr += sprintf(ptr, "^%.6s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000433 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000434 ptr += sprintf(ptr, "^?");
435 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000436 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000437 *(ptr++) = '\t';
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000438 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000439
440 /* Function key. */
441 if (s->funcval != NANO_NO_KEY) {
442 entries++;
David Lawrence Ramsey2e83a502004-11-01 22:35:26 +0000443 /* If this is the first entry, put it in the middle. */
444 if (entries == 1) {
445 entries++;
446 *(ptr++) = '\t';
447 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000448 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
449 *(ptr++) = '\t';
450 }
451
452 /* Primary meta key sequence. */
453 if (s->metaval != NANO_NO_KEY) {
454 entries++;
455 /* If this is the last entry, put it at the end. */
456 if (entries == 2 && s->miscval == NANO_NO_KEY) {
457 entries++;
458 *(ptr++) = '\t';
459 }
460 /* If the primary meta key sequence is the first entry,
461 * don't put parentheses around it. */
462 if (entries == 1 && s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000463 ptr += sprintf(ptr, "M-%.5s", _("Space"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000464 else
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000465 ptr += sprintf(ptr, entries == 1 ? "M-%c" : "(M-%c)",
466 toupper(s->metaval));
467 *(ptr++) = '\t';
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000468 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000469
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000470 /* Miscellaneous meta key sequence. */
471 if (entries < 3 && s->miscval != NANO_NO_KEY) {
472 entries++;
473 /* If this is the last entry, put it at the end. */
474 if (entries == 2) {
475 entries++;
476 *(ptr++) = '\t';
477 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000478 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000479 *(ptr++) = '\t';
480 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000481
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000482 /* Make sure all the help text starts at the same place. */
483 while (entries < 3) {
484 entries++;
485 *(ptr++) = '\t';
486 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000487
488 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000489 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000490 }
491
492#ifndef NANO_SMALL
493 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000494 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000495 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000496 assert(t->desc != NULL);
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +0000497 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
498 t->desc, _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000499 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000500 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000501#endif /* !NANO_SMALL */
502
503 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000504 * help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000505 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000506}
507#endif
508
509/* Create a new filestruct node. Note that we specifically do not set
510 * prevnode->next equal to the new line. */
511filestruct *make_new_node(filestruct *prevnode)
512{
513 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000514 newnode->data = NULL;
515 newnode->prev = prevnode;
516 newnode->next = NULL;
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000517 newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000518 return newnode;
519}
520
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000521/* Make a copy of a filestruct node. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000524 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000525 assert(src != NULL);
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000526 dst->data = mallocstrcpy(NULL, src->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000527 dst->next = src->next;
528 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529 dst->lineno = src->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000530 return dst;
531}
532
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000533/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000534void splice_node(filestruct *begin, filestruct *newnode, filestruct
535 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000536{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000537 assert(newnode != NULL && begin != NULL);
538 newnode->next = end;
539 newnode->prev = begin;
540 begin->next = newnode;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000541 if (end != NULL)
542 end->prev = newnode;
543}
544
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000545/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 assert(fileptr != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000549 if (fileptr->prev != NULL)
550 fileptr->prev->next = fileptr->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000551 if (fileptr->next != NULL)
552 fileptr->next->prev = fileptr->prev;
553}
554
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000555/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000556void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000557{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000558 assert(fileptr != NULL && fileptr->data != NULL);
559 if (fileptr->data != NULL)
560 free(fileptr->data);
561 free(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562}
563
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000564/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000565filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000566{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000567 filestruct *head; /* copy of src, top of the copied list */
568 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000569
Chris Allegretta6df90f52002-07-19 01:08:59 +0000570 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571
Chris Allegretta6df90f52002-07-19 01:08:59 +0000572 prev = copy_node(src);
573 prev->prev = NULL;
574 head = prev;
575 src = src->next;
576 while (src != NULL) {
577 prev->next = copy_node(src);
578 prev->next->prev = prev;
579 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580
Chris Allegretta6df90f52002-07-19 01:08:59 +0000581 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000582 }
583
Chris Allegretta6df90f52002-07-19 01:08:59 +0000584 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000585 return head;
586}
587
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000588/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000589void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000591 assert(src != NULL);
592
593 while (src->next != NULL) {
594 src = src->next;
595 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000596 }
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000597 delete_node(src);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000598}
599
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000600/* Partition a filestruct so it begins at (top, top_x) and ends at (bot,
601 * bot_x). */
602partition *partition_filestruct(filestruct *top, size_t top_x,
603 filestruct *bot, size_t bot_x)
604{
605 partition *p;
David Lawrence Ramsey6299b0d2004-11-08 03:22:23 +0000606 assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000607
608 /* Initialize the partition. */
609 p = (partition *)nmalloc(sizeof(partition));
610
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000611 /* If the top and bottom of the partition are different from the top
612 * and bottom of the filestruct, save the latter and then set them
613 * to top and bot. */
614 if (top != fileage) {
615 p->fileage = fileage;
616 fileage = top;
617 } else
618 p->fileage = NULL;
619 if (bot != filebot) {
620 p->filebot = filebot;
621 filebot = bot;
622 } else
623 p->filebot = NULL;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000624
625 /* Save the line above the top of the partition, detach the top of
626 * the partition from it, and save the text before top_x in
627 * top_data. */
628 p->top_prev = top->prev;
629 top->prev = NULL;
630 p->top_data = mallocstrncpy(NULL, top->data, top_x + 1);
631 p->top_data[top_x] = '\0';
632
633 /* Save the line below the bottom of the partition, detach the
634 * bottom of the partition from it, and save the text after bot_x in
635 * bot_data. */
636 p->bot_next = bot->next;
637 bot->next = NULL;
638 p->bot_data = mallocstrcpy(NULL, bot->data + bot_x);
639
640 /* Remove all text after bot_x at the bottom of the partition. */
641 null_at(&bot->data, bot_x);
642
643 /* Remove all text before top_x at the top of the partition. */
644 charmove(top->data, top->data + top_x, strlen(top->data) -
645 top_x + 1);
646 align(&top->data);
647
648 /* Return the partition. */
649 return p;
650}
651
652/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
653 * (filebot, strlen(filebot)) again. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000654void unpartition_filestruct(partition **p)
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000655{
656 char *tmp;
David Lawrence Ramsey2c315402004-11-08 03:19:10 +0000657 assert(p != NULL && fileage != NULL && filebot != NULL);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000658
659 /* Reattach the line above the top of the partition, and restore the
660 * text before top_x from top_data. Free top_data when we're done
661 * with it. */
662 tmp = mallocstrcpy(NULL, fileage->data);
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000663 fileage->prev = (*p)->top_prev;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000664 if (fileage->prev != NULL)
665 fileage->prev->next = fileage;
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000666 fileage->data = charealloc(fileage->data, strlen((*p)->top_data) +
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000667 strlen(fileage->data) + 1);
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000668 strcpy(fileage->data, (*p)->top_data);
669 free((*p)->top_data);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000670 strcat(fileage->data, tmp);
671 free(tmp);
672
673 /* Reattach the line below the bottom of the partition, and restore
674 * the text after bot_x from bot_data. Free bot_data when we're
675 * done with it. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000676 filebot->next = (*p)->bot_next;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000677 if (filebot->next != NULL)
678 filebot->next->prev = filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000679 filebot->data = charealloc(filebot->data, strlen(filebot->data) +
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000680 strlen((*p)->bot_data) + 1);
681 strcat(filebot->data, (*p)->bot_data);
682 free((*p)->bot_data);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000683
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000684 /* Restore the top and bottom of the filestruct, if they were
685 * different from the top and bottom of the partition. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000686 if ((*p)->fileage != NULL)
687 fileage = (*p)->fileage;
688 if ((*p)->filebot != NULL)
689 filebot = (*p)->filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000690
691 /* Uninitialize the partition. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000692 free(*p);
693 *p = NULL;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000694}
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000695
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000696/* Move all the text between (top, top_x) and (bot, bot_x) in the
697 * current filestruct to a filestruct beginning with file_top and ending
698 * with file_bot. If no text is between (top, top_x) and (bot, bot_x),
699 * don't do anything. */
700void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
701 filestruct *top, size_t top_x, filestruct *bot, size_t bot_x)
702{
703 filestruct *top_save;
704 long part_totsize;
705 bool at_edittop;
706#ifndef NANO_SMALL
707 bool mark_inside = FALSE;
708#endif
709
710 assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
711
712 /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
713 if (top == bot && top_x == bot_x)
714 return;
715
716 /* Partition the filestruct so that it contains only the text from
717 * (top, top_x) to (bot, bot_x), keep track of whether the top of
718 * the partition is the top of the edit window, and keep track of
719 * whether the mark begins inside the partition. */
720 filepart = partition_filestruct(top, top_x, bot, bot_x);
721 at_edittop = (fileage == edittop);
722#ifndef NANO_SMALL
723 if (ISSET(MARK_ISSET))
724 mark_inside = (mark_beginbuf->lineno >= fileage->lineno &&
725 mark_beginbuf->lineno <= filebot->lineno &&
726 (mark_beginbuf != fileage || mark_beginx >= top_x) &&
727 (mark_beginbuf != filebot || mark_beginx <= bot_x));
728#endif
729
730 /* Get the number of characters in the text, and subtract it from
731 * totsize. */
732 get_totals(top, bot, NULL, &part_totsize);
733 totsize -= part_totsize;
734
735 if (*file_top == NULL) {
736 /* If file_top is empty, just move all the text directly into
737 * it. This is equivalent to tacking the text in top onto the
738 * (lack of) text at the end of file_top. */
739 *file_top = fileage;
740 *file_bot = filebot;
741 } else {
742 /* Otherwise, tack the text in top onto the text at the end of
743 * file_bot. */
744 (*file_bot)->data = charealloc((*file_bot)->data,
745 strlen((*file_bot)->data) + strlen(fileage->data) + 1);
746 strcat((*file_bot)->data, fileage->data);
747
748 /* Attach the line after top to the line after file_bot. Then,
749 * if there's more than one line after top, move file_bot down
750 * to bot. */
751 (*file_bot)->next = fileage->next;
752 if ((*file_bot)->next != NULL) {
753 (*file_bot)->next->prev = *file_bot;
754 *file_bot = filebot;
755 }
756 }
757
758 /* Since the text has now been saved, remove it from the filestruct.
759 * If the top of the partition was the top of the edit window, set
760 * edittop to where the text used to start. If the mark began
761 * inside the partition, set the beginning of the mark to where the
762 * text used to start. */
763 fileage = (filestruct *)nmalloc(sizeof(filestruct));
764 fileage->data = mallocstrcpy(NULL, "");
765 filebot = fileage;
766 if (at_edittop)
767 edittop = fileage;
768#ifndef NANO_SMALL
769 if (mark_inside) {
770 mark_beginbuf = fileage;
771 mark_beginx = top_x;
772 }
773#endif
774
775 /* Restore the current line and cursor position. */
776 current = fileage;
777 current_x = top_x;
778
779 top_save = fileage;
780
781 /* Unpartition the filestruct so that it contains all the text
782 * again, minus the saved text. */
783 unpartition_filestruct(&filepart);
784
785 /* Renumber starting with the beginning line of the old
786 * partition. */
787 renumber(top_save);
788
789 if (filebot->data[0] != '\0')
790 new_magicline();
791
792 /* Set totlines to the new number of lines in the file. */
793 totlines = filebot->lineno;
794}
795
796/* Copy all the text from the filestruct beginning with file_top and
797 * ending with file_bot to the current filestruct at the current cursor
798 * position. */
799void copy_from_filestruct(filestruct *file_top, filestruct *file_bot)
800{
801 filestruct *top_save;
802 int part_totlines;
803 long part_totsize;
804 bool at_edittop;
805
806 assert(file_top != NULL && file_bot != NULL);
807
808 /* Partition the filestruct so that it contains no text, and keep
809 * track of whether the top of the partition is the top of the edit
810 * window. */
811 filepart = partition_filestruct(current, current_x, current,
812 current_x);
813 at_edittop = (fileage == edittop);
814
815 /* Put the top and bottom of the filestruct at copies of file_top
816 * and file_bot. */
817 fileage = copy_filestruct(file_top);
818 filebot = fileage;
819 while (filebot->next != NULL)
820 filebot = filebot->next;
821
822 /* Restore the current line and cursor position. */
823 current = filebot;
824 current_x = strlen(filebot->data);
825 if (fileage == filebot)
826 current_x += strlen(filepart->top_data);
827
828 /* Get the number of lines and the number of characters in the saved
829 * text, and add the latter to totsize. */
830 get_totals(fileage, filebot, &part_totlines, &part_totsize);
831 totsize += part_totsize;
832
833 /* If the top of the partition was the top of the edit window, set
834 * edittop to where the saved text now starts, and update the
835 * current y-coordinate to account for the number of lines it
836 * has, less one since the first line will be tacked onto the
837 * current line. */
838 if (at_edittop)
839 edittop = fileage;
840 current_y += part_totlines - 1;
841
842 top_save = fileage;
843
844 /* Unpartition the filestruct so that it contains all the text
845 * again, minus the saved text. */
846 unpartition_filestruct(&filepart);
847
848 /* Renumber starting with the beginning line of the old
849 * partition. */
850 renumber(top_save);
851
852 if (filebot->data[0] != '\0')
853 new_magicline();
854
855 /* Set totlines to the new number of lines in the file. */
856 totlines = filebot->lineno;
857}
858
Chris Allegretta6df90f52002-07-19 01:08:59 +0000859void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000860{
861 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000862 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000863
Chris Allegretta6df90f52002-07-19 01:08:59 +0000864 assert(fileage == NULL || fileage != fileage->next);
865 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000866 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000867}
868
Chris Allegretta6df90f52002-07-19 01:08:59 +0000869void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000870{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000871 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000872 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000873 else {
874 int lineno = fileptr->prev->lineno;
875
876 assert(fileptr != fileptr->next);
877 for (; fileptr != NULL; fileptr = fileptr->next)
878 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000879 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000880}
881
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000882/* Print one usage string to the screen. This cuts down on duplicate
883 * strings to translate and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000884 * translatable (the flag names). */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000885void print1opt(const char *shortflag, const char *longflag, const char
886 *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000887{
888 printf(" %s\t", shortflag);
889 if (strlen(shortflag) < 8)
890 printf("\t");
891
892#ifdef HAVE_GETOPT_LONG
893 printf("%s\t", longflag);
894 if (strlen(longflag) < 8)
895 printf("\t\t");
896 else if (strlen(longflag) < 16)
897 printf("\t");
898#endif
899
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000900 printf("%s\n", _(desc));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000901}
902
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000903void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000904{
905#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000906 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
907 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000908#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000909 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
910 printf(_("Option\t\tMeaning\n"));
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +0000911#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000912
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000913 print1opt("-h, -?", "--help", N_("Show this message"));
914 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000915#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000916 print1opt("-A", "--smarthome", N_("Enable smart home key"));
917 print1opt("-B", "--backup", N_("Backup existing files on save"));
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000918 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000919#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000920#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000921 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000922#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000923#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000924#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000925 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000926#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000927 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000928#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000929#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000930 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000931#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000932#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000933 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000934#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000935#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000936 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000937#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000938#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000939 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000940#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000941 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
942 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000943#ifdef ENABLE_COLOR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000944 print1opt(_("-Y [str]"), _("--syntax [str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000945#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000946 print1opt("-Z", "--restricted", N_("Restricted mode"));
947 print1opt("-c", "--const", N_("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000948#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000949 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
950 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
951 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000952#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000953 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000954#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000955 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000956#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000957#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000958 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000959#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000960 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000961#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000962 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000963#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000964#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000965 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000966#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000967 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
968 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000969#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000970 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000971#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000972 print1opt("-x", "--nohelp", N_("Don't show help window"));
973 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000974
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000975 /* This is a special case. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000977
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000978 exit(0);
979}
980
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000981void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000982{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000983 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000984 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000985 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000986 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000987 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000988
Chris Allegrettae6600372003-01-17 03:39:41 +0000989#ifndef ENABLE_NLS
990 printf(" --disable-nls");
991#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000992#ifdef DEBUG
993 printf(" --enable-debug");
994#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000995#ifdef NANO_EXTRA
996 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000997#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000998#ifdef NANO_SMALL
999 printf(" --enable-tiny");
1000#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001001#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +00001002 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001003#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001004#ifdef DISABLE_HELP
1005 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001006#endif
1007#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00001008 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001009#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001010#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +00001011 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +00001012#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00001013#ifdef DISABLE_OPERATINGDIR
1014 printf(" --disable-operatingdir");
1015#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001016#ifdef DISABLE_SPELLER
1017 printf(" --disable-speller");
1018#endif
1019#ifdef DISABLE_TABCOMP
1020 printf(" --disable-tabcomp");
1021#endif
Chris Allegretta84de5522001-04-12 14:51:48 +00001022#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001023#ifdef DISABLE_WRAPPING
1024 printf(" --disable-wrapping");
1025#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00001026#ifdef DISABLE_ROOTWRAP
1027 printf(" --disable-wrapping-as-root");
1028#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029#ifdef ENABLE_COLOR
1030 printf(" --enable-color");
1031#endif
1032#ifdef ENABLE_MULTIBUFFER
1033 printf(" --enable-multibuffer");
1034#endif
1035#ifdef ENABLE_NANORC
1036 printf(" --enable-nanorc");
1037#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001038#ifdef USE_SLANG
1039 printf(" --with-slang");
1040#endif
1041 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001042}
1043
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001044int no_help(void)
1045{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001046 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001047}
1048
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001049void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +00001050{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001051 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +00001052}
1053
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001054#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001055RETSIGTYPE cancel_fork(int signal)
1056{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001057 if (kill(pid, SIGKILL) == -1)
1058 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001059}
1060
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001061/* Return TRUE on success. */
1062bool open_pipe(const char *command)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001063{
1064 int fd[2];
1065 FILE *f;
1066 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +00001067 /* Original and temporary handlers for
1068 * SIGINT. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001069 bool sig_failed = FALSE;
1070 /* sig_failed means that sigaction() failed without changing the
1071 * signal handlers.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001072 *
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001073 * We use this variable since it is important to put things back
1074 * when we finish, even if we get errors. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001075
1076 /* Make our pipes. */
1077
1078 if (pipe(fd) == -1) {
1079 statusbar(_("Could not pipe"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001080 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001081 }
1082
1083 /* Fork a child. */
1084
1085 if ((pid = fork()) == 0) {
1086 close(fd[0]);
1087 dup2(fd[1], fileno(stdout));
1088 dup2(fd[1], fileno(stderr));
1089 /* If execl() returns at all, there was an error. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001090
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001091 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001092 exit(0);
1093 }
1094
1095 /* Else continue as parent. */
1096
1097 close(fd[1]);
1098
1099 if (pid == -1) {
1100 close(fd[0]);
1101 statusbar(_("Could not fork"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001102 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001103 }
1104
1105 /* Before we start reading the forked command's output, we set
1106 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001107
David Lawrence Ramseye608f942004-05-19 16:04:27 +00001108 /* Enable interpretation of the special control keys so that we get
1109 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001110 enable_signals();
1111
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001112 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001113 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001114 nperror("sigaction");
1115 } else {
1116 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001117 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001118 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001119 nperror("sigaction");
1120 }
1121 }
1122 /* Note that now oldaction is the previous SIGINT signal handler,
1123 * to be restored later. */
1124
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001125 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001126 if (f == NULL)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001127 nperror("fdopen");
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001128
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001129 read_file(f, "stdin");
David Lawrence Ramsey22fac782004-08-05 15:16:19 +00001130 /* If multibuffer mode is on, we could be here in view mode. If so,
1131 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001132 if (!ISSET(VIEW_MODE))
1133 set_modified();
1134
1135 if (wait(NULL) == -1)
1136 nperror("wait");
1137
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001138 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001139 nperror("sigaction");
1140
David Lawrence Ramseye608f942004-05-19 16:04:27 +00001141 /* Disable interpretation of the special control keys so that we can
1142 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001143 disable_signals();
1144
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001145 return TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001146}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +00001147#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001148
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001149/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001150void do_char(char ch)
1151{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001152 size_t current_len = strlen(current->data);
1153#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001154 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001155 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +00001156 * update_line()? */
1157#endif
1158
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001159 if (ch == '\0') /* Null to newline, if needed. */
1160 ch = '\n';
1161 else if (ch == '\n') { /* Newline to Enter, if needed. */
1162 do_enter();
1163 return;
1164 }
1165
1166 assert(current != NULL && current->data != NULL);
1167
1168 /* When a character is inserted on the current magicline, it means
1169 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001170 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +00001171 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +00001172
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001173 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001174 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001175 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001176 charmove(&current->data[current_x + 1], &current->data[current_x],
1177 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001179 totsize++;
1180 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181
Chris Allegretta6df90f52002-07-19 01:08:59 +00001182#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001183 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001184 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001185 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001186#endif
1187
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001188 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001189
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001190#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001191 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +00001192 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001193 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001194#endif
1195
Chris Allegretta6df90f52002-07-19 01:08:59 +00001196#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001197 /* If color syntaxes are turned on, we need to call
1198 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +00001199 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001200 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001201#endif
1202
1203#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001204 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001205 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001206 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00001207#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001208 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001209}
1210
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001211void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001212{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001213 int *v_kbinput = NULL; /* Used to hold verbatim input. */
1214 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +00001215 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001216
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001217 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001218
David Lawrence Ramsey1483ee32004-11-29 00:30:07 +00001219 v_kbinput = get_verbatim_kbinput(edit, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001220
1221 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1222 * off afterwards, so that if constant cursor position display is
1223 * on, it will be updated properly. */
1224 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001225 for (i = 0; i < v_len; i++)
1226 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001227 UNSET(DISABLE_CURPOS);
1228
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001229 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001230}
1231
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001232void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001233{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001234 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001235 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001236 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001237 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001238}
1239
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001240void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001241{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001242 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001243 /* Do we have to call edit_refresh(), or can we get away with
1244 * update_line()? */
1245
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +00001246 assert(current != NULL && current->data != NULL &&
1247 current_x <= strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001248
1249 placewewant = xplustabs();
1250
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001251 if (current->data[current_x] != '\0') {
1252 size_t linelen = strlen(current->data + current_x);
1253
1254 assert(current_x < strlen(current->data));
1255
1256 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001257 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001258 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001259
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001260 null_at(&current->data, linelen + current_x - 1);
1261#ifndef NANO_SMALL
1262 if (current_x < mark_beginx && mark_beginbuf == current)
1263 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001264#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001265 } else if (current != filebot && (current->next != filebot ||
1266 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001267 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001268 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001269 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001270
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001271 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001272
1273 /* If we're deleting at the end of a line, we need to call
1274 * edit_refresh(). */
1275 if (current->data[current_x] == '\0')
1276 do_refresh = TRUE;
1277
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001278 current->data = charealloc(current->data, current_x +
1279 strlen(foo->data) + 1);
1280 strcpy(current->data + current_x, foo->data);
1281#ifndef NANO_SMALL
1282 if (mark_beginbuf == current->next) {
1283 mark_beginx += current_x;
1284 mark_beginbuf = current;
1285 }
1286#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001287 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001288 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001289
1290 unlink_node(foo);
1291 delete_node(foo);
1292 renumber(current);
1293 totlines--;
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001294#ifndef DISABLE_WRAPPING
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001295 wrap_reset();
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001296#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001297 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001298 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001299
1300 totsize--;
1301 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001302
1303#ifdef ENABLE_COLOR
1304 /* If color syntaxes are turned on, we need to call
1305 * edit_refresh(). */
1306 if (ISSET(COLOR_SYNTAX))
1307 do_refresh = TRUE;
1308#endif
1309
1310 if (do_refresh)
1311 edit_refresh();
1312 else
1313 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001314}
1315
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001316void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001317{
1318 do_char('\t');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001319}
1320
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001321/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001322void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001323{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001324 filestruct *newnode = make_new_node(current);
1325 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001326
Chris Allegretta6df90f52002-07-19 01:08:59 +00001327 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001328
Chris Allegrettaff989832001-09-17 13:48:00 +00001329#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001330 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001331 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001332 /* If we are breaking the line in the indentation, the new
1333 * indentation should have only current_x characters, and
1334 * current_x should not change. */
1335 extra = indent_length(current->data);
1336 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001337 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001338 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001339 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001340#endif
1341 newnode->data = charalloc(strlen(current->data + current_x) +
1342 extra + 1);
1343 strcpy(&newnode->data[extra], current->data + current_x);
1344#ifndef NANO_SMALL
1345 if (ISSET(AUTOINDENT))
1346 strncpy(newnode->data, current->data, extra);
1347#endif
1348 null_at(&current->data, current_x);
1349#ifndef NANO_SMALL
1350 if (current == mark_beginbuf && current_x < mark_beginx) {
1351 mark_beginbuf = newnode;
1352 mark_beginx += extra - current_x;
1353 }
1354#endif
1355 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001356
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001357 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001358 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001359 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001360
1361 totsize++;
1362 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001363 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001364
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001365 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001366
1367 totlines++;
1368 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001369 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001370}
1371
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001372#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001373void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001374{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001375 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001376 const filestruct *old_current = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001377 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001378
Chris Allegretta6df90f52002-07-19 01:08:59 +00001379 /* Skip letters in this word first. */
1380 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001381 isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001382 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001383
Chris Allegretta6df90f52002-07-19 01:08:59 +00001384 for (; current != NULL; current = current->next) {
1385 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001386 !isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001387 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001388
Chris Allegretta6df90f52002-07-19 01:08:59 +00001389 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001390 break;
1391
Chris Allegretta6df90f52002-07-19 01:08:59 +00001392 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001393 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001394 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001395 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001396
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001397 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001398
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001399 /* Update the screen. */
1400 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001401}
1402
Chris Allegretta6df90f52002-07-19 01:08:59 +00001403/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001404void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001405{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001406 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001407 const filestruct *old_current = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001408 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001409
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001410 current_x++;
1411
Chris Allegretta6df90f52002-07-19 01:08:59 +00001412 /* Skip letters in this word first. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001413 while (current_x > 0 && isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001414 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001415
Chris Allegretta6df90f52002-07-19 01:08:59 +00001416 for (; current != NULL; current = current->prev) {
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001417 while (current_x > 0 && !isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001418 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001419
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001420 if (current_x > 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001421 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001422
Chris Allegretta6df90f52002-07-19 01:08:59 +00001423 if (current->prev != NULL)
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001424 current_x = strlen(current->prev->data) + 1;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001425 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001426
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001427 current_x--;
1428
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001429 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001430 current = fileage;
1431 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001432 } else {
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001433 while (current_x > 0 && isalnum(current->data[current_x - 1]))
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001434 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001435 }
1436
Chris Allegretta76e291b2001-10-14 19:05:10 +00001437 placewewant = xplustabs();
1438
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001439 /* Update the screen. */
1440 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001441}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001442
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001443void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001444{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001445 TOGGLE(MARK_ISSET);
1446 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001447 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001448 mark_beginbuf = current;
1449 mark_beginx = current_x;
1450 } else {
1451 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001452 edit_refresh();
1453 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001454}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001455#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001456
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001457#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001458void wrap_reset(void)
1459{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001460 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001461}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001462#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001463
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001464#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001465/* We wrap the given line. Precondition: we assume the cursor has been
1466 * moved forward since the last typed character. Return value: whether
1467 * we wrapped. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001468bool do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001469{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001470 size_t len = strlen(inptr->data);
1471 /* Length of the line we wrap. */
1472 size_t i = 0;
1473 /* Generic loop variable. */
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001474 ssize_t wrap_loc = -1;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001475 /* Index of inptr->data where we wrap. */
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001476 ssize_t word_back = -1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001477#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001478 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001479 /* Indentation to prepend to the new line. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001480 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001481#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001482 const char *after_break; /* Text after the wrap point. */
1483 size_t after_break_len; /* strlen(after_break) */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001484 bool wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001485 const char *wrap_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001486 /* The next line, minus indentation. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001487 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1488 char *newline = NULL; /* The line we create. */
1489 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001490
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001491/* There are three steps. First, we decide where to wrap. Then, we
1492 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001493
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001494/* Step 1, finding where to wrap. We are going to add a new line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001495 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001496 * location of this replacement.
1497 *
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001498 * Where should we break the line? We need the last legal wrap point
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001499 * such that the last word before it ended at or before fill. If there
1500 * is no such point, we settle for the first legal wrap point.
1501 *
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001502 * A legal wrap point is a whitespace character that is not followed by
1503 * whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001504 *
1505 * If there is no legal wrap point or we found the last character of the
1506 * line, we should return without wrapping.
1507 *
1508 * Note that the initial indentation does not count as a legal wrap
1509 * point if we are going to auto-indent!
1510 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001511 * Note that the code below could be optimized, by not calling
1512 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001513
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001514#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001515 if (ISSET(AUTOINDENT))
1516 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001517#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001518 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001519 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001520 /* Record where the last word ended. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001521 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001522 word_back = i;
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001523 /* If we have found a legal wrap point and the current word
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001524 * extends too far, then we stop. */
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +00001525 if (wrap_loc != -1 &&
1526 strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001527 break;
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001528 /* We record the latest legal wrap point. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001529 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001530 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001531 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001532 if (i == len)
1533 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001534
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001535 /* Step 2, making the new wrap line. It will consist of indentation
1536 * + after_break + " " + wrap_line (although indentation and
1537 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001538
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001539 /* after_break is the text that will be moved to the next line. */
1540 after_break = inptr->data + wrap_loc + 1;
1541 after_break_len = len - wrap_loc - 1;
1542 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001543
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001544 /* new_line_len will later be increased by the lengths of indentation
1545 * and wrap_line. */
1546 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001547
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001548 /* We prepend the wrapped text to the next line, if the flag is set,
1549 * and there is a next line, and prepending would not make the line
1550 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001551 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001552 wrap_line = inptr->next->data;
1553 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001554
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001555 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001556 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001557 wrapping = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001558 new_line_len += (1 + wrap_line_len);
1559 }
1560 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001561
Chris Allegrettaff989832001-09-17 13:48:00 +00001562#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001563 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001564 /* Indentation comes from the next line if wrapping, else from
1565 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001566 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001567 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001568 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001569 /* The wrap_line text should not duplicate indentation.
1570 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001571 wrap_line += indent_len;
1572 else
1573 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001574 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001575#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001576
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001577 /* Now we allocate the new line and copy into it. */
1578 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001579 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001580 *newline = '\0';
1581
1582#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001583 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001584 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001585 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001586 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001587 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001588#endif
1589 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001590 new_line_len += after_break_len;
1591 /* We end the old line after wrap_loc. Note that this does not eat
1592 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001593 null_at(&inptr->data, wrap_loc + 1);
1594 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001595 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001596 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001597 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001598 * in a tab or a space, we don't add a space and decrement
1599 * totsize to account for that. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001600 if (!isblank(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001601 strcat(newline, " ");
1602 else
1603 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001604 strcat(newline, wrap_line);
1605 free(inptr->next->data);
1606 inptr->next->data = newline;
1607 } else {
1608 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001609
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001610 /* In this case, the file size changes by +1 for the new line,
1611 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001612#ifndef NANO_SMALL
1613 totsize += indent_len;
1614#endif
1615 totlines++;
1616 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001617 temp->prev = inptr;
1618 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001619 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001620 /* If temp->next is NULL, then temp is the last line of the
1621 * file, so we must set filebot. */
1622 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001623 temp->next->prev = temp;
1624 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001625 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001626 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001627
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001628 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1629 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001630
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001631 /* Later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001632 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001633
1634 /* Each line knows its line number. We recalculate these if we
1635 * inserted a new line. */
1636 if (!wrapping)
1637 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001638
Chris Allegretta6df90f52002-07-19 01:08:59 +00001639 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001640 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001641 current = current->next;
1642 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001643#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001644 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001645#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001646 wrap_loc + 1;
1647 wrap_reset();
1648 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001649 }
1650
Chris Allegretta6df90f52002-07-19 01:08:59 +00001651#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001652 /* If the mark was on this line after the wrap point, we move it
1653 * down. If it was on the next line and we wrapped, we move it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001654 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001655 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1656 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001657 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001658 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001659 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001660#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001661
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001662 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001663}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001664#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001665
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001666#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001667/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001668 * return FALSE if the user cancels. */
1669bool do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001670{
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001671 char *save_search, *save_replace;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001672 size_t current_x_save = current_x, pww_save = placewewant;
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001673 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001674 /* Save where we are. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001675 bool canceled = FALSE;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001676 /* The return value. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001677 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001678#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001679 bool reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001680#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001681#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001682 bool regexp_set = ISSET(USE_REGEXP);
1683#endif
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001684#ifndef NANO_SMALL
1685 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001686 bool added_magicline = FALSE;
1687 /* Whether we added a magicline after filebot. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001688 bool right_side_up = FALSE;
1689 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
1690 * FALSE if (current, current_x) is. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001691 filestruct *top, *bot;
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001692 size_t top_x, bot_x;
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001693#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001694
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001695 /* Make sure spell-check is case sensitive. */
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001696 SET(CASE_SENSITIVE);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001697
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001698#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001699 /* Make sure spell-check goes forward only. */
1700 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001701#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001702#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001703 /* Make sure spell-check doesn't use regular expressions. */
1704 UNSET(USE_REGEXP);
1705#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001706
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001707 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001708 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001709 save_search = last_search;
1710 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001711
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001712 /* Set the search/replace strings to the misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001713 last_search = mallocstrcpy(NULL, word);
1714 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001715
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001716#ifndef NANO_SMALL
1717 if (old_mark_set) {
David Lawrence Ramseyf978f042004-11-04 16:45:48 +00001718 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001719 * contains only the marked text, keep track of whether the text
1720 * will have a magicline added when we're done correcting
1721 * misspelled words, and turn the mark off. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001722 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001723 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001724 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001725 added_magicline = (filebot->data[0] != '\0');
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001726 UNSET(MARK_ISSET);
1727 }
1728#endif
1729
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001730 /* Start from the top of the file. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001731 edittop = fileage;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001732 current = fileage;
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001733 current_x = (size_t)-1;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001734 placewewant = 0;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001735
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001736 /* Find the first whole-word occurrence of word. */
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +00001737 findnextstr_wrap_reset();
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +00001738 while (findnextstr(TRUE, TRUE, FALSE, fileage, 0, word, NULL)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001739 if (is_whole_word(current_x, current->data, word)) {
1740 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001741
Chris Allegretta6df90f52002-07-19 01:08:59 +00001742 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001743
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +00001744 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001745 canceled = (statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001746#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001747 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001748#endif
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001749 _("Edit a replacement")) == -1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001750
Chris Allegretta6df90f52002-07-19 01:08:59 +00001751 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001752
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001753 if (!canceled && strcmp(word, answer) != 0) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001754 current_x--;
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001755 do_replace_loop(word, current, &current_x, TRUE,
1756 &canceled);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001757 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001758
1759 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001760 }
David Lawrence Ramsey53752e82004-10-18 22:19:22 +00001761 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001762
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001763#ifndef NANO_SMALL
1764 if (old_mark_set) {
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00001765 /* If the mark was on and we added a magicline, remove it
1766 * now. */
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001767 if (added_magicline)
1768 remove_magicline();
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001769
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001770 /* Put the beginning and the end of the mark at the beginning
1771 * and the end of the spell-checked text. */
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001772 if (fileage == filebot)
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001773 bot_x += top_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001774 if (right_side_up) {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001775 mark_beginx = top_x;
1776 current_x_save = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001777 } else {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001778 current_x_save = top_x;
1779 mark_beginx = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001780 }
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001781
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00001782 /* Unpartition the filestruct so that it contains all the text
1783 * again, and turn the mark back on. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00001784 unpartition_filestruct(&filepart);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001785 SET(MARK_ISSET);
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001786 }
1787#endif
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001788
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001789 /* Restore the search/replace strings. */
1790 free(last_search);
1791 last_search = save_search;
1792 free(last_replace);
1793 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001794
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001795 /* Restore where we were. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001796 edittop = edittop_save;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001797 current = current_save;
1798 current_x = current_x_save;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001799 placewewant = pww_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001800
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001801 /* Restore case sensitivity setting. */
1802 if (!case_sens_set)
1803 UNSET(CASE_SENSITIVE);
1804
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001805#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001806 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001807 if (reverse_search_set)
1808 SET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001809#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001810#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001811 /* Restore regular expression usage setting. */
1812 if (regexp_set)
1813 SET(USE_REGEXP);
1814#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001815
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001816 return !canceled;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001817}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001818
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001819/* Integrated spell checking using 'spell' program. Return value: NULL
1820 * for normal termination, otherwise the error string. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001821const char *do_int_speller(const char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001822{
Chris Allegretta271e9722000-11-10 18:15:43 +00001823 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001824 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001825 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001826 pid_t pid_spell, pid_sort, pid_uniq;
1827 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001828
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001829 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001830 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1831 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001832
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001833 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001834
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001835 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001836 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001837
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001838 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001839
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001840 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001841
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001842 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001843 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1844 goto close_pipes_and_exit;
1845
1846 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1847 goto close_pipes_and_exit;
1848
Chris Allegretta271e9722000-11-10 18:15:43 +00001849 close(tempfile_fd);
1850
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001851 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001852 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1853 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001854
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001855 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001856
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001857 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001858 execlp("spell", "spell", NULL);
1859
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001860 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001861 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001862 }
1863
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001864 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001865 close(spell_fd[1]);
1866
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001867 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001868 if ((pid_sort = fork()) == 0) {
1869
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001870 /* Child continues (i.e, future spell process). Replace the
1871 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001872 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1873 goto close_pipes_and_exit;
1874
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001875 close(spell_fd[0]);
1876
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001877 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001878 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1879 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001880
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001881 close(sort_fd[1]);
1882
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001883 /* Start sort program. Use -f to remove mixed case without
1884 * having to have ANOTHER pipe for tr. If this isn't portable,
1885 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001886 execlp("sort", "sort", "-f", NULL);
1887
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001888 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001889 exit(1);
1890 }
1891
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001892 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001893 close(sort_fd[1]);
1894
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001895 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001896 if ((pid_uniq = fork()) == 0) {
1897
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001898 /* Child continues (i.e, future uniq process). Replace the
1899 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001900 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1901 goto close_pipes_and_exit;
1902
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001903 close(sort_fd[0]);
1904
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001905 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001906 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1907 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001908
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001909 close(uniq_fd[1]);
1910
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001911 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001912 execlp("uniq", "uniq", NULL);
1913
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001914 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001915 exit(1);
1916 }
1917
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001918 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001919 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001920
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001921 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001922 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1923 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001924 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001925 }
1926
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001927 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001928 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1929 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001930 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001931 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001932
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001933 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001934 read_buff_read = 0;
1935 read_buff_size = pipe_buff_size + 1;
1936 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001937
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001938 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001939 read_buff_read += bytesread;
1940 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001941 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001942 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001943
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001944 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001945
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001946 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001947 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001948
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001949 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001950 read_buff_word = read_buff_ptr = read_buff;
1951
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001952 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001953
1954 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001955 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001956 if (read_buff_word != read_buff_ptr) {
1957 if (!do_int_spell_fix(read_buff_word)) {
1958 read_buff_word = read_buff_ptr;
1959 break;
1960 }
1961 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001962 read_buff_word = read_buff_ptr + 1;
1963 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001964 read_buff_ptr++;
1965 }
1966
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001967 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001968 if (read_buff_word != read_buff_ptr)
1969 do_int_spell_fix(read_buff_word);
1970
Chris Allegretta271e9722000-11-10 18:15:43 +00001971 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001972 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001973 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001974
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001975 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001976 waitpid(pid_spell, &spell_status, 0);
1977 waitpid(pid_sort, &sort_status, 0);
1978 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001979
Chris Allegretta334a9402002-12-16 04:25:53 +00001980 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1981 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001982
Chris Allegretta334a9402002-12-16 04:25:53 +00001983 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1984 return _("Error invoking \"sort -f\"");
1985
1986 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1987 return _("Error invoking \"uniq\"");
1988
1989 /* Otherwise... */
1990 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001991
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001992 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001993
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001994 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001995 close(tempfile_fd);
1996 close(spell_fd[0]);
1997 close(spell_fd[1]);
1998 close(sort_fd[0]);
1999 close(sort_fd[1]);
2000 close(uniq_fd[0]);
2001 close(uniq_fd[1]);
2002 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002003}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002004
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002005/* External spell checking. Return value: NULL for normal termination,
2006 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002007const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002008{
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002009 int alt_spell_status, lineno_save = current->lineno;
2010 size_t current_x_save = current_x, pww_save = placewewant;
2011 int current_y_save = current_y;
Chris Allegretta271e9722000-11-10 18:15:43 +00002012 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00002013 char *ptr;
2014 static int arglen = 3;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002015 static char **spellargs = NULL;
2016 FILE *f;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002017#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002018 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002019 bool added_magicline = FALSE;
2020 /* Whether we added a magicline after filebot. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002021 bool right_side_up = FALSE;
2022 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
2023 * FALSE if (current, current_x) is. */
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002024 filestruct *top, *bot;
2025 size_t top_x, bot_x;
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002026 int mbb_lineno_save = 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002027 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002028 * the alternate spell command. The line that mark_beginbuf
2029 * points to will be freed, so we save the line number and
2030 * restore afterwards. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002031 long old_totsize = totsize;
2032 /* Our saved value of totsize, used when we spell-check a marked
2033 * selection. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002034
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002035 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002036 /* If the mark is on, save the number of the line it starts on,
2037 * and then turn the mark off. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002038 mbb_lineno_save = mark_beginbuf->lineno;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002039 UNSET(MARK_ISSET);
2040 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002041#endif
2042
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002043 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002044
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002045 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00002046 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002047 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00002048
Chris Allegrettae434b452001-01-27 19:25:00 +00002049 spellargs[0] = strtok(alt_speller, " ");
2050 while ((ptr = strtok(NULL, " ")) != NULL) {
2051 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002052 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00002053 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00002054 }
Chris Allegrettae434b452001-01-27 19:25:00 +00002055 spellargs[arglen - 1] = NULL;
2056 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002057 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00002058
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002059 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002060 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002061 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00002062 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00002063
2064 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00002065 exit(1);
2066 }
2067
2068 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00002069 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00002070 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00002071
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002072 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00002073 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002074
Chris Allegretta334a9402002-12-16 04:25:53 +00002075 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
2076 char *altspell_error = NULL;
2077 char *invoke_error = _("Could not invoke \"%s\"");
2078 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
2079
2080 altspell_error = charalloc(msglen);
2081 snprintf(altspell_error, msglen, invoke_error, alt_speller);
2082 return altspell_error;
2083 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002084
Chris Allegretta8f6c0692000-07-19 01:16:18 +00002085 refresh();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002086
David Lawrence Ramsey439fbe32004-10-16 04:56:34 +00002087 /* Restore the terminal to its previous state. */
2088 terminal_init();
2089
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002090#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002091 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002092 long part_totsize;
2093
2094 /* If the mark was on, partition the filestruct so that it
2095 * contains only the marked text, and keep track of whether the
2096 * temp file (which should contain the spell-checked marked
2097 * text) will have a magicline added when it's reloaded. */
2098 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002099 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002100 filepart = partition_filestruct(top, top_x, bot, bot_x);
2101 added_magicline = (filebot->data[0] != '\0');
2102
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002103 /* Get the number of characters in the marked text, and subtract
2104 * it from the saved value of totsize. Note that we don't need
2105 * to save totlines. */
2106 get_totals(top, bot, NULL, &part_totsize);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002107 old_totsize -= part_totsize;
2108 }
2109#endif
2110
2111 /* Reinitialize the filestruct. */
2112 free_filestruct(fileage);
2113 global_init(TRUE);
2114
2115 /* Reload the temp file. Do what load_buffer() would do, except for
2116 * making a new buffer for the temp file if multibuffer support is
2117 * available. */
2118 open_file(tempfile_name, FALSE, &f);
2119 read_file(f, tempfile_name);
2120 current = fileage;
2121
2122#ifndef NANO_SMALL
2123 if (old_mark_set) {
David Lawrence Ramsey15398372004-11-05 15:03:12 +00002124 filestruct *top_save = fileage;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002125
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00002126 /* If the mark was on and we added a magicline, remove it
2127 * now. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002128 if (added_magicline)
2129 remove_magicline();
2130
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002131 /* Put the beginning and the end of the mark at the beginning
2132 * and the end of the spell-checked text. */
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002133 if (fileage == filebot)
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002134 bot_x += top_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002135 if (right_side_up) {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002136 mark_beginx = top_x;
2137 current_x_save = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002138 } else {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002139 current_x_save = top_x;
2140 mark_beginx = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002141 }
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002142
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00002143 /* Unpartition the filestruct so that it contains all the text
2144 * again. Note that we've replaced the marked text originally
2145 * in the partition with the spell-checked marked text in the
2146 * temp file. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00002147 unpartition_filestruct(&filepart);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002148
2149 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002150 * partition. Also set totlines to the new number of lines in
2151 * the file, add the number of characters in the spell-checked
2152 * marked text to the saved value of totsize, and then make that
2153 * saved value the actual value. */
David Lawrence Ramsey15398372004-11-05 15:03:12 +00002154 renumber(top_save);
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002155 totlines = filebot->lineno;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002156 old_totsize += totsize;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002157 totsize = old_totsize;
2158
2159 /* Assign mark_beginbuf to the line where the mark began
2160 * before. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002161 do_gotopos(mbb_lineno_save, mark_beginx, current_y_save, 0);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002162 mark_beginbuf = current;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002163
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002164 /* Assign mark_beginx to the location in mark_beginbuf where the
2165 * mark began before, adjusted for any shortening of the
2166 * line. */
2167 mark_beginx = current_x;
2168
2169 /* Turn the mark back on. */
2170 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002171 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002172#endif
2173
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002174 /* Go back to the old position, mark the file as modified, and make
2175 * sure that the titlebar is refreshed. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002176 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002177 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00002178 clearok(topwin, FALSE);
2179 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002180
Chris Allegretta334a9402002-12-16 04:25:53 +00002181 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002182}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002183
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002184void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002185{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002186 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002187 char *temp = safe_tempnam(0, "nano.");
2188 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002189
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002190 if (temp == NULL) {
2191 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002192 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00002193 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002194
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002195#ifndef NANO_SMALL
2196 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002197 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002198 else
2199#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002200 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002201
2202 if (i == -1) {
David Lawrence Ramsey95e39e52004-08-12 02:52:14 +00002203 statusbar(_("Error writing temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00002204 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002205 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00002206 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002207
Chris Allegrettae1f14522001-09-19 03:19:43 +00002208#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002209 /* Update the current open_files entry before spell-checking, in
2210 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002211 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00002212#endif
2213
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002214 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
2215 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002216 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00002217 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002218
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002219 if (spell_msg != NULL)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002220 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2221 strerror(errno));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002222 else
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002223 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00002224}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002225#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002226
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002227#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00002228/* The "indentation" of a line is the whitespace between the quote part
2229 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002230size_t indent_length(const char *line)
2231{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002232 size_t len = 0;
2233
2234 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002235 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002236 line++;
2237 len++;
2238 }
2239 return len;
2240}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002241#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002242
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002243#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00002244/* justify_format() replaces Tab by Space and multiple spaces by 1
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002245 * (except it maintains 2 after a non-repeated character in punct
2246 * followed by a character in brackets). Note that the terminating \0
2247 * counts as a space.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002248 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002249 * justify_format() might make line->data shorter, and change the actual
2250 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00002251 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002252 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00002253 * skip should be at most strlen(line->data). The character at
2254 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002255void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002256{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002257 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002258
Chris Allegretta6df90f52002-07-19 01:08:59 +00002259 /* These four asserts are assumptions about the input data. */
2260 assert(line != NULL);
2261 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00002262 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002263 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002264
Chris Allegretta6df90f52002-07-19 01:08:59 +00002265 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002266 for (front = back; ; front++) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002267 bool remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002268 /* Do we want to remove this space? */
2269
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002270 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002271 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002272
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00002273 /* These tests are safe since line->data + skip is not a
2274 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002275 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002276 const char *bob = back - 2;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002277
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002278 remove_space = TRUE;
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002279 for (; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002280 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002281 /* If this character is in punct, don't remove the
2282 * space unless this character and the character
2283 * before it are the same. */
2284 remove_space = (bob > line->data + skip &&
2285 *bob == *(bob - 1));
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002286 break;
2287 }
2288 if (strchr(brackets, *bob) == NULL)
2289 break;
2290 }
2291 }
2292
2293 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002294 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002295 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002296#ifndef NANO_SMALL
2297 if (mark_beginbuf == line && back - line->data < mark_beginx)
2298 mark_beginx--;
2299#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002300 if (*front == '\0')
2301 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002302 } else {
2303 *back = *front;
2304 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002305 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002306 if (*front == '\0')
2307 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002308 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002309
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002310 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00002311 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00002312
Chris Allegretta6df90f52002-07-19 01:08:59 +00002313 /* Now back is the new end of line->data. */
2314 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00002315 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002316 null_at(&line->data, back - line->data);
2317#ifndef NANO_SMALL
2318 if (mark_beginbuf == line && back - line->data < mark_beginx)
2319 mark_beginx = back - line->data;
2320#endif
2321 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002322}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002323
2324/* The "quote part" of a line is the largest initial substring matching
2325 * the quote string. This function returns the length of the quote part
2326 * of the given line.
2327 *
2328 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2329 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002330size_t quote_length(const char *line)
2331{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002332#ifdef HAVE_REGEX_H
2333 regmatch_t matches;
2334 int rc = regexec(&quotereg, line, 1, &matches, 0);
2335
2336 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
2337 return 0;
2338 /* matches.rm_so should be 0, since the quote string should start
2339 * with the caret ^. */
2340 return matches.rm_eo;
2341#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002342 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002343
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00002344 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002345 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002346 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002347 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002348#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002349}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002350
Chris Allegretta6df90f52002-07-19 01:08:59 +00002351/* a_line and b_line are lines of text. The quotation part of a_line is
2352 * the first a_quote characters. Check that the quotation part of
2353 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002354bool quotes_match(const char *a_line, size_t a_quote, const char
2355 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002356{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002357 /* Here is the assumption about a_quote: */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002358 assert(a_quote == quote_length(a_line));
2359 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002360 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002361}
2362
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002363/* We assume a_line and b_line have no quote part. Then, we return
2364 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002365bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002366 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002367{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002368 assert(a_indent == indent_length(a_line));
2369 assert(b_indent == indent_length(b_line));
2370
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002371 return b_indent <= a_indent &&
2372 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002373}
2374
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002375/* Is foo the beginning of a paragraph?
2376 *
2377 * A line of text consists of a "quote part", followed by an
2378 * "indentation part", followed by text. The functions quote_length()
2379 * and indent_length() calculate these parts.
2380 *
2381 * A line is "part of a paragraph" if it has a part not in the quote
2382 * part or the indentation.
2383 *
2384 * A line is "the beginning of a paragraph" if it is part of a
2385 * paragraph and
2386 * 1) it is the top line of the file, or
2387 * 2) the line above it is not part of a paragraph, or
2388 * 3) the line above it does not have precisely the same quote
2389 * part, or
2390 * 4) the indentation of this line is not an initial substring of
2391 * the indentation of the previous line, or
2392 * 5) this line has no quote part and some indentation, and
2393 * AUTOINDENT is not set.
2394 * The reason for number 5) is that if AUTOINDENT is not set, then an
2395 * indented line is expected to start a paragraph, like in books.
2396 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2397 * turned on. */
2398bool begpar(const filestruct *const foo)
2399{
2400 size_t quote_len;
2401 size_t indent_len;
2402 size_t temp_id_len;
2403
2404 /* Case 1). */
2405 if (foo->prev == NULL)
2406 return TRUE;
2407
2408 quote_len = quote_length(foo->data);
2409 indent_len = indent_length(foo->data + quote_len);
2410
2411 /* Not part of a paragraph. */
2412 if (foo->data[quote_len + indent_len] == '\0')
2413 return FALSE;
2414
2415 /* Case 3). */
2416 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2417 return TRUE;
2418
2419 temp_id_len = indent_length(foo->prev->data + quote_len);
2420
2421 /* Case 2) or 5) or 4). */
2422 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2423 (quote_len == 0 && indent_len > 0
2424#ifndef NANO_SMALL
2425 && !ISSET(AUTOINDENT)
2426#endif
2427 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2428 foo->data + quote_len, indent_len))
2429 return TRUE;
2430
2431 return FALSE;
2432}
2433
2434/* We find the last beginning-of-paragraph line before the current
2435 * line. */
2436void do_para_begin(void)
2437{
2438 const filestruct *old_current = current;
2439 const size_t old_pww = placewewant;
2440
2441 current_x = 0;
2442 placewewant = 0;
2443
2444 if (current->prev != NULL) {
2445 do {
2446 current = current->prev;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002447 current_y--;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002448 } while (!begpar(current));
2449 }
2450
2451 edit_redraw(old_current, old_pww);
2452}
2453
2454bool inpar(const char *str)
2455{
2456 size_t quote_len = quote_length(str);
2457
2458 return str[quote_len + indent_length(str + quote_len)] != '\0';
2459}
2460
2461/* A line is the last line of a paragraph if it is in a paragraph, and
2462 * the next line isn't, or is the beginning of a paragraph. We move
2463 * down to the end of a paragraph, then one line farther. */
2464void do_para_end(void)
2465{
2466 const filestruct *const old_current = current;
2467 const size_t old_pww = placewewant;
2468
2469 current_x = 0;
2470 placewewant = 0;
2471
2472 while (current->next != NULL && !inpar(current->data))
2473 current = current->next;
2474
2475 while (current->next != NULL && inpar(current->next->data) &&
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002476 !begpar(current->next)) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002477 current = current->next;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002478 current_y++;
2479 }
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002480
2481 if (current->next != NULL)
2482 current = current->next;
2483
2484 edit_redraw(old_current, old_pww);
2485}
2486
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002487/* Put the next par_len lines, starting with first_line, into the
2488 * justify buffer, leaving copies of those lines in place. Assume there
2489 * are enough lines after first_line. Return the new copy of
2490 * first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002491filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2492 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002493{
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002494 filestruct *top = first_line;
2495 /* The top of the paragraph we're backing up. */
2496 filestruct *bot = first_line;
2497 /* The bottom of the paragraph we're backing up. */
2498 size_t i;
2499 /* Generic loop variable. */
2500 size_t current_x_save = current_x;
2501 int fl_lineno_save = first_line->lineno;
2502 int edittop_lineno_save = edittop->lineno;
2503 int current_lineno_save = current->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002504#ifndef NANO_SMALL
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002505 bool old_mark_set = ISSET(MARK_ISSET);
2506 int mbb_lineno_save = 0;
2507
2508 if (old_mark_set)
2509 mbb_lineno_save = mark_beginbuf->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002510#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002511
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002512 /* Move bot down par_len lines to the newline after the last line of
2513 * the paragraph. */
2514 for (i = par_len; i > 0; i--)
2515 bot = bot->next;
2516
2517 /* Move the paragraph from the main filestruct to the justify
2518 * buffer. */
2519 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot, 0);
2520
2521 /* Copy the paragraph from the justify buffer to the main
2522 * filestruct. */
2523 copy_from_filestruct(jusbuffer, jusbottom);
2524
2525 /* Move upward from the last line of the paragraph to the first
2526 * line, putting first_line, edittop, current, and mark_beginbuf at
2527 * the same lines in the copied paragraph that they had in the
2528 * original paragraph. */
2529 top = current->prev;
2530 for (i = par_len; i > 0; i--) {
2531 if (top->lineno == fl_lineno_save)
2532 first_line = top;
2533 if (top->lineno == edittop_lineno_save)
2534 edittop = top;
2535 if (top->lineno == current_lineno_save)
2536 current = top;
2537#ifndef NANO_SMALL
2538 if (old_mark_set && top->lineno == mbb_lineno_save)
2539 mark_beginbuf = top;
2540#endif
2541 top = top->prev;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002542 }
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002543
2544 /* Put current_x at the same place in the copied paragraph that it
2545 * had in the original paragraph. */
2546 current_x = current_x_save;
2547
2548 set_modified();
2549
Chris Allegretta6df90f52002-07-19 01:08:59 +00002550 return first_line;
2551}
2552
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002553/* Is it possible to break line at or before goal? */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002554bool breakable(const char *line, ssize_t goal)
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002555{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002556 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002557 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002558 return TRUE;
2559
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002560 if (is_cntrl_char(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002561 goal -= 2;
2562 else
2563 goal -= 1;
2564 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002565 /* If goal is not negative, the whole line (one word) was short
2566 * enough. */
2567 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002568}
2569
Chris Allegretta6df90f52002-07-19 01:08:59 +00002570/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002571 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002572 * such space, and force is TRUE, then we find the first space. Anyway,
2573 * we then take the last space in that group of spaces. The terminating
2574 * '\0' counts as a space. */
David Lawrence Ramseyfc54d6e2004-12-02 17:37:09 +00002575ssize_t break_line(const char *line, ssize_t goal, bool force)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002576{
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002577 ssize_t space_loc = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002578 /* Current tentative return value. Index of the last space we
2579 * found with short enough display width. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002580 ssize_t cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002581 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002582
2583 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002584 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002585 if (*line == ' ')
2586 space_loc = cur_loc;
2587 assert(*line != '\t');
2588
Chris Allegrettacf287c82002-07-20 13:57:41 +00002589 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002590 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002591 else
2592 goal--;
2593 }
2594 if (goal >= 0)
2595 /* In fact, the whole line displays shorter than goal. */
2596 return cur_loc;
2597 if (space_loc == -1) {
2598 /* No space found short enough. */
2599 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002600 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002601 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002602 return cur_loc;
2603 return -1;
2604 }
2605 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002606 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002607 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2608 *(line - cur_loc + space_loc + 1) == '\0')
2609 space_loc++;
2610 return space_loc;
2611}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002613/* Find the beginning of the current paragraph if we're in one, or the
2614 * beginning of the next paragraph if we're not. Afterwards, save the
2615 * quote length and paragraph length in *quote and *par. Return FALSE
2616 * if we found a paragraph, or TRUE if there was an error or we didn't
2617 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002618 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002619 * See the comment at begpar() for more about when a line is the
2620 * beginning of a paragraph. */
2621bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002622{
2623 size_t quote_len;
2624 /* Length of the initial quotation of the paragraph we
2625 * search. */
2626 size_t par_len;
2627 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002628 size_t indent_len;
2629 /* Generic indentation length. */
2630 filestruct *line;
2631 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002632
2633#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002634 if (quoterc != 0) {
2635 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2636 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002637 }
2638#endif
2639
2640 /* Here is an assumption that is always true anyway. */
2641 assert(current != NULL);
2642
2643 current_x = 0;
2644
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002645 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002646 indent_len = indent_length(current->data + quote_len);
2647
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002648 /* Here we find the first line of the paragraph to search. If the
2649 * current line is in a paragraph, then we move back to the first
2650 * line of the paragraph. Otherwise, we move to the first line that
2651 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002652 if (current->data[quote_len + indent_len] != '\0') {
2653 /* This line is part of a paragraph. So we must search back to
2654 * the first line of this paragraph. First we check items 1)
2655 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002656 while (current->prev != NULL && quotes_match(current->data,
2657 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002658 size_t temp_id_len =
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00002659 indent_length(current->prev->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002660 /* The indentation length of the previous line. */
2661
2662 /* Is this line the beginning of a paragraph, according to
2663 * items 2), 5), or 4) above? If so, stop. */
2664 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002665 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002666#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002667 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002668#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002669 ) || !indents_match(current->prev->data + quote_len,
2670 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002671 break;
2672 indent_len = temp_id_len;
2673 current = current->prev;
2674 current_y--;
2675 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002676 } else {
2677 /* This line is not part of a paragraph. Move down until we get
2678 * to a non "blank" line. */
2679 do {
2680 /* There is no next paragraph, so nothing to move to. */
2681 if (current->next == NULL) {
2682 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002683 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002684 }
2685 current = current->next;
2686 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002687 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002688 indent_len = indent_length(current->data + quote_len);
2689 } while (current->data[quote_len + indent_len] == '\0');
2690 }
2691
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002692 /* Now current is the first line of the paragraph, and quote_len is
2693 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002694
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002695 /* Next step, compute par_len, the number of lines in this
2696 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002697 line = current;
2698 par_len = 1;
2699 indent_len = indent_length(line->data + quote_len);
2700
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002701 while (line->next != NULL &&
2702 quotes_match(current->data, quote_len, line->next->data)) {
2703 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002704
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002705 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002706 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002707 line->next->data[quote_len + temp_id_len] == '\0' ||
2708 (quote_len == 0 && temp_id_len > 0
2709#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002710 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002711#endif
2712 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002713 break;
2714 indent_len = temp_id_len;
2715 line = line->next;
2716 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002717 }
2718
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002719 /* Now par_len is the number of lines in this paragraph. We should
2720 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002721
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002722 /* Save the values of quote_len and par_len. */
2723 assert(quote != NULL && par != NULL);
2724 *quote = quote_len;
2725 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002726
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002727 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002728}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002729
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002730/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2731 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002732void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002733{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002734 filestruct *first_par_line = NULL;
2735 /* Will be the first line of the resulting justified paragraph.
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002736 * For restoring after unjustify. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002737 filestruct *last_par_line;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002738 /* Will be the line containing the newline after the last line
2739 * of the result. Also for restoring after unjustify. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002740 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002741 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002742 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002743 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002744
2745 /* We save these global variables to be restored if the user
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002746 * unjustifies. Note that we don't need to save totlines. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00002747 size_t current_x_save = current_x;
2748 int current_y_save = current_y;
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002749 long flags_save = flags, totsize_save = totsize;
2750 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002751#ifndef NANO_SMALL
2752 filestruct *mark_beginbuf_save = mark_beginbuf;
David Lawrence Ramsey687776b2004-10-30 01:16:08 +00002753 size_t mark_beginx_save = mark_beginx;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002754#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002755 int kbinput;
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00002756 bool meta_key, func_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002757
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002758 /* If we're justifying the entire file, start at the beginning. */
2759 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002760 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002761
2762 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002763
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002764 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002765 size_t quote_len;
2766 /* Length of the initial quotation of the paragraph we
2767 * justify. */
2768 size_t par_len;
2769 /* Number of lines in that paragraph. */
2770
2771 /* Find the first line of the paragraph to be justified. That
2772 * is the start of this paragraph if we're in one, or the start
2773 * of the next otherwise. Save the quote length and paragraph
2774 * length (number of lines). Don't refresh the screen yet
2775 * (since we'll do that after we justify). If the search failed
2776 * and we're justifying the whole file, move the last line of
2777 * the text we're justifying to just before the magicline, which
2778 * is where it'll be anyway if we've searched the entire file,
2779 * and break out of the loop; otherwise, refresh the screen and
2780 * get out. */
2781 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002782 if (full_justify) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002783 last_par_line = filebot;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002784 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002785 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002786 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002787 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002788 }
2789 }
2790
2791 /* Next step, we loop through the lines of this paragraph,
2792 * justifying each one individually. */
2793 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002794 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002795 size_t line_len;
2796 size_t display_len;
2797 /* The width of current in screen columns. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002798 ssize_t break_pos;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002799 /* Where we will break the line. */
2800
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002801 /* We'll be moving to the next line after justifying the
2802 * current line in almost all cases, so allow changing the
2803 * spacing at the ends of justified lines by default. */
2804 allow_respacing = TRUE;
2805
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002806 indent_len = quote_len + indent_length(current->data +
2807 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002808
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002809 /* If we haven't already done it, copy the original
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002810 * paragraph to the justify buffer. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002811 if (first_par_line == NULL)
2812 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey6b769e52004-11-17 16:59:34 +00002813 filebot->lineno - current->lineno : par_len,
2814 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002815
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002816 /* Now we call justify_format() on the current line of the
2817 * paragraph, which will remove excess spaces from it and
2818 * change tabs to spaces. */
2819 justify_format(current, quote_len +
2820 indent_length(current->data + quote_len));
2821
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002822 line_len = strlen(current->data);
2823 display_len = strlenpt(current->data);
2824
2825 if (display_len > fill) {
2826 /* The line is too long. Try to wrap it to the next. */
2827 break_pos = break_line(current->data + indent_len,
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002828 fill - strnlenpt(current->data, indent_len),
2829 TRUE);
2830 if (break_pos == -1 || break_pos + indent_len ==
2831 line_len)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002832 /* We can't break the line, or don't need to, so
2833 * just go on to the next. */
2834 goto continue_loc;
2835 break_pos += indent_len;
2836 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002837 if (par_len == 1) {
2838 /* There is no next line in this paragraph. We make
2839 * a new line and copy text after break_pos into
2840 * it. */
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002841 splice_node(current, make_new_node(current),
2842 current->next);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002843 /* In a non-quoted paragraph, we copy the indent
2844 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002845 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002846#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002847 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002848#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002849 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002850 indent_len = 0;
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002851 current->next->data = charalloc(indent_len +
2852 line_len - break_pos);
2853 strncpy(current->next->data, current->data,
2854 indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002855 strcpy(current->next->data + indent_len,
2856 current->data + break_pos + 1);
2857 assert(strlen(current->next->data) ==
2858 indent_len + line_len - break_pos - 1);
2859 totlines++;
2860 totsize += indent_len;
2861 par_len++;
2862 } else {
2863 size_t next_line_len = strlen(current->next->data);
2864
2865 indent_len = quote_len +
2866 indent_length(current->next->data + quote_len);
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002867 current->next->data =
2868 charealloc(current->next->data, next_line_len +
2869 line_len - break_pos + 1);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002870
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002871 charmove(current->next->data + indent_len +
2872 line_len - break_pos, current->next->data +
2873 indent_len, next_line_len - indent_len + 1);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002874 strcpy(current->next->data + indent_len,
2875 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002876 current->next->data[indent_len + line_len -
2877 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002878#ifndef NANO_SMALL
2879 if (mark_beginbuf == current->next) {
2880 if (mark_beginx < indent_len)
2881 mark_beginx = indent_len;
2882 mark_beginx += line_len - break_pos;
2883 }
2884#endif
2885 }
2886#ifndef NANO_SMALL
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +00002887 if (mark_beginbuf == current &&
2888 mark_beginx > break_pos) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002889 mark_beginbuf = current->next;
2890 mark_beginx -= break_pos + 1 - indent_len;
2891 }
2892#endif
2893 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002894
2895 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002896 current = current->next;
2897 } else if (display_len < fill && par_len > 1) {
2898 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002899
2900 indent_len = quote_len +
2901 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002902 /* If we can't pull a word from the next line up to this
2903 * one, just go on. */
2904 if (!breakable(current->next->data + indent_len,
2905 fill - display_len - 1))
2906 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002907
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002908 break_pos = break_line(current->next->data + indent_len,
2909 fill - display_len - 1, FALSE);
2910 assert(break_pos != -1);
2911
2912 current->data = charealloc(current->data,
2913 line_len + break_pos + 2);
2914 current->data[line_len] = ' ';
2915 strncpy(current->data + line_len + 1,
2916 current->next->data + indent_len, break_pos);
2917 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002918#ifndef NANO_SMALL
2919 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002920 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002921 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002922 if (mark_beginx <= indent_len)
2923 mark_beginx = line_len + 1;
2924 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002925 mark_beginx = line_len + 1 + mark_beginx -
2926 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002927 } else
2928 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002929 }
2930#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002931 next_line_len = strlen(current->next->data);
2932 if (indent_len + break_pos == next_line_len) {
2933 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002934
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002935 /* Don't destroy edittop! */
2936 if (line == edittop)
2937 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002938
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002939 unlink_node(line);
2940 delete_node(line);
2941 totlines--;
2942 totsize -= indent_len;
2943 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002944
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002945 /* Don't go to the next line. Accordingly, don't
2946 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002947 * previous justified line, so that we don't end up
2948 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002949 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002950 } else {
2951 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002952 current->next->data + indent_len + break_pos + 1,
2953 next_line_len - break_pos - indent_len);
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002954 null_at(&current->next->data, next_line_len -
2955 break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002956
2957 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002958 current = current->next;
2959 }
2960 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002961 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002962 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002963 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002964
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002965 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002966 * current line. If the justified line was not the last
2967 * line of the paragraph, add a space to the end of it to
2968 * replace the one removed or left out by justify_format().
2969 * If it was the last line of the paragraph, and
2970 * justify_format() left a space on the end of it, remove
2971 * the space. */
2972 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002973 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002974
2975 if (par_len > 1) {
2976 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002977 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002978 current->prev->data[prev_line_len] = ' ';
2979 current->prev->data[prev_line_len + 1] = '\0';
2980 totsize++;
2981 } else if (par_len == 1 &&
2982 current->prev->data[prev_line_len - 1] == ' ') {
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002983 current->prev->data =
2984 charealloc(current->prev->data, prev_line_len);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002985 current->prev->data[prev_line_len - 1] = '\0';
2986 totsize--;
2987 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002988 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002989 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002990
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002991 /* We've just justified a paragraph. If we're not justifying the
2992 * entire file, break out of the loop. Otherwise, continue the
2993 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002994 if (!full_justify)
2995 break;
2996
2997 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002998
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002999 /* We are now done justifying the paragraph or the file, so clean
3000 * up. totlines, totsize, and current_y have been maintained above.
3001 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00003002 * fileage, and renumber() since edit_refresh() needs the line
3003 * numbers to be right (but only do the last two if we actually
3004 * justified something). */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003005 last_par_line = current;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00003006 if (first_par_line != NULL) {
3007 if (first_par_line->prev == NULL)
3008 fileage = first_par_line;
3009 renumber(first_par_line);
3010 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00003011
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00003012 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00003013
Chris Allegretta9149e612000-11-27 00:23:41 +00003014 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003015
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003016 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003017 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00003018 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00003019
David Lawrence Ramsey63e73cb2004-11-28 04:52:57 +00003020 /* Now get a keystroke and see if it's unjustify. If not, put back
3021 * the keystroke and return. */
David Lawrence Ramseyd994ad52004-11-23 21:40:26 +00003022 kbinput = get_edit_input(&meta_key, &func_key, FALSE);
Chris Allegretta5f071802001-05-06 02:34:31 +00003023
David Lawrence Ramsey45f971d2004-09-27 01:10:48 +00003024 if (!meta_key && !func_key && kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003025 /* Restore the justify we just did (ungrateful user!). */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003026 current = current_save;
3027 current_x = current_x_save;
3028 current_y = current_y_save;
3029 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00003030
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003031 /* Splice the justify buffer back into the file, but only if we
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00003032 * actually justified something. */
3033 if (first_par_line != NULL) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003034 filestruct *bot_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003035
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003036 /* Partition the filestruct so that it contains only the
3037 * text of the justified paragraph. */
3038 filepart = partition_filestruct(first_par_line, 0,
3039 last_par_line, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00003040
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003041 /* Remove the text of the justified paragraph, and
3042 * put the text in the justify buffer in its place. */
3043 free_filestruct(fileage);
3044 fileage = jusbuffer;
3045 filebot = jusbottom;
3046
3047 bot_save = filebot;
3048
3049 /* Unpartition the filestruct so that it contains all the
3050 * text again. Note that the justified paragraph has been
3051 * replaced with the unjustified paragraph. */
3052 unpartition_filestruct(&filepart);
3053
3054 /* Renumber starting with the ending line of the old
3055 * partition. */
3056 if (bot_save->next != NULL)
3057 renumber(bot_save->next);
3058
3059 /* Restore global variables from before the justify. */
3060 totsize = totsize_save;
3061 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003062#ifndef NANO_SMALL
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003063 mark_beginbuf = mark_beginbuf_save;
3064 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003065#endif
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003066 flags = flags_save;
3067
3068 /* Clear the justify buffer. */
3069 jusbuffer = NULL;
3070
3071 if (!ISSET(MODIFIED))
3072 titlebar(NULL);
3073 edit_refresh();
3074 }
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003075 } else {
David Lawrence Ramsey1483ee32004-11-29 00:30:07 +00003076 unget_kbinput(kbinput, meta_key);
David Lawrence Ramseyd994ad52004-11-23 21:40:26 +00003077
David Lawrence Ramsey53d3db42004-11-28 03:53:01 +00003078 /* Blow away the text in the justify buffer. */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003079 free_filestruct(jusbuffer);
3080 jusbuffer = NULL;
Chris Allegretta9149e612000-11-27 00:23:41 +00003081 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003082
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00003083 blank_statusbar();
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003084
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003085 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003086 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00003087 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003088}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003089
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003090void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003091{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003092 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003093}
3094
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003095void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003096{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003097 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003098}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003099#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003100
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003101void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003102{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003103 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00003104
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003105 if (!ISSET(MODIFIED))
3106 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00003107 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003108 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003109 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003110 i = do_yesno(FALSE,
3111 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
3112
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003113#ifdef DEBUG
3114 dump_buffer(fileage);
3115#endif
3116
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003117 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003118#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +00003119 /* Exit only if there are no more open file buffers. */
David Lawrence Ramsey3e189a82004-10-03 19:18:48 +00003120 if (!close_open_file())
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003121#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00003122 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003123 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003124 statusbar(_("Cancelled"));
3125
3126 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003127}
3128
3129void signal_init(void)
3130{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003131 /* Trap SIGINT and SIGQUIT because we want them to do useful
3132 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003133 memset(&act, 0, sizeof(struct sigaction));
3134 act.sa_handler = SIG_IGN;
3135 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00003136 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003137
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003138 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003139 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003140 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003141 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003142
3143#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003144 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003145 act.sa_handler = handle_sigwinch;
3146 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003147 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003148#endif
3149
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003150 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003151 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003152 act.sa_handler = SIG_IGN;
3153 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003154 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003155 /* Block all other signals in the suspend and continue handlers.
3156 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003157 sigfillset(&act.sa_mask);
3158
3159 act.sa_handler = do_suspend;
3160 sigaction(SIGTSTP, &act, NULL);
3161
3162 act.sa_handler = do_cont;
3163 sigaction(SIGCONT, &act, NULL);
3164 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003165}
3166
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003167/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003168RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003169{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00003170 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003171}
3172
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003173/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003174RETSIGTYPE do_suspend(int signal)
3175{
3176 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00003177 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003178 fflush(stdout);
3179
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003180 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003181 tcsetattr(0, TCSANOW, &oldterm);
3182
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00003183 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003184 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00003185 act.sa_handler = handle_hupterm;
3186 sigaction(SIGHUP, &act, NULL);
3187 sigaction(SIGTERM, &act, NULL);
3188
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003189 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003190 kill(0, SIGSTOP);
3191}
3192
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003193/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003194RETSIGTYPE do_cont(int signal)
3195{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003196#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003197 /* Perhaps the user resized the window while we slept. Handle it
3198 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003199 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003200#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003201 /* Just update the screen. */
3202 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003203#endif
3204}
3205
3206#ifndef NANO_SMALL
3207void handle_sigwinch(int s)
3208{
3209 const char *tty = ttyname(0);
3210 int fd;
3211 int result = 0;
3212 struct winsize win;
3213
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003214 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003215 return;
3216 fd = open(tty, O_RDWR);
3217 if (fd == -1)
3218 return;
3219 result = ioctl(fd, TIOCGWINSZ, &win);
3220 close(fd);
3221 if (result == -1)
3222 return;
3223
3224 /* Could check whether the COLS or LINES changed, and return
3225 * otherwise. EXCEPT, that COLS and LINES are ncurses global
3226 * variables, and in some cases ncurses has already updated them.
3227 * But not in all cases, argh. */
3228 COLS = win.ws_col;
3229 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00003230 editwinrows = LINES - 5 + no_help();
3231 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003232 die_too_small();
3233
3234#ifndef DISABLE_WRAPJUSTIFY
3235 fill = wrap_at;
3236 if (fill <= 0)
3237 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00003238 if (fill < 0)
3239 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003240#endif
3241
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00003242 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003243 memset(hblank, ' ', COLS);
3244 hblank[COLS] = '\0';
3245
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00003246 /* If we've partitioned the filestruct, unpartition it now. */
3247 if (filepart != NULL)
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00003248 unpartition_filestruct(&filepart);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00003249
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003250#ifndef DISABLE_JUSTIFY
David Lawrence Ramseybc3b9262004-11-23 04:17:19 +00003251 /* If the justify buffer isn't empty, blow away the text in it and
3252 * display the shortcut list with UnCut. */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003253 if (jusbuffer != NULL) {
3254 free_filestruct(jusbuffer);
3255 jusbuffer = NULL;
3256 shortcut_init(FALSE);
3257 }
3258#endif
3259
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003260#ifdef USE_SLANG
3261 /* Slang curses emulation brain damage, part 1: If we just do what
3262 * curses does here, it'll only work properly if the resize made the
3263 * window smaller. Do what mutt does: Leave and immediately reenter
3264 * Slang screen management mode. */
3265 SLsmg_reset_smg();
3266 SLsmg_init_smg();
3267#else
3268 /* Do the equivalent of what Minimum Profit does: Leave and
3269 * immediately reenter curses mode. */
3270 endwin();
3271 refresh();
3272#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003273
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003274 /* Restore the terminal to its previous state. */
3275 terminal_init();
3276
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003277 /* Do the equivalent of what both mutt and Minimum Profit do:
3278 * Reinitialize all the windows based on the new screen
3279 * dimensions. */
3280 window_init();
3281
David Lawrence Ramsey907725f2004-11-12 00:09:20 +00003282 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003283 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003284 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003285 total_refresh();
3286
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003287 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003288 curs_set(1);
3289
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00003290 /* Reset all the input routines that rely on character sequences. */
3291 reset_kbinput();
3292
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003293 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003294 siglongjmp(jmpbuf, 1);
3295}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003296
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003297void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003298{
3299 sigset_t winch;
3300 sigemptyset(&winch);
3301 sigaddset(&winch, SIGWINCH);
3302 if (allow)
3303 sigprocmask(SIG_UNBLOCK, &winch, NULL);
3304 else
3305 sigprocmask(SIG_BLOCK, &winch, NULL);
3306}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003307#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003308
Chris Allegrettadab017e2002-04-23 10:56:06 +00003309#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00003310void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00003311{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003312 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00003313
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003314 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00003315
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003316 switch (which->val) {
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003317 case TOGGLE_SUSPEND_KEY:
3318 signal_init();
3319 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003320#ifndef DISABLE_MOUSE
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003321 case TOGGLE_MOUSE_KEY:
3322 mouse_init();
3323 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003324#endif
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003325 case TOGGLE_NOHELP_KEY:
3326 blank_statusbar();
3327 blank_bottombars();
3328 wrefresh(bottomwin);
3329 window_init();
3330 edit_refresh();
3331 display_main_list();
3332 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003333#ifdef ENABLE_COLOR
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003334 case TOGGLE_SYNTAX_KEY:
3335 edit_refresh();
3336 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003337#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003338#ifdef ENABLE_NANORC
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003339 case TOGGLE_WHITESPACE_KEY:
3340 edit_refresh();
3341 break;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003342#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003343 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003344
Chris Allegretta6df90f52002-07-19 01:08:59 +00003345 /* We are assuming here that shortcut_init() above didn't free and
3346 * reallocate the toggles. */
3347 enabled = ISSET(which->flag);
3348 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3349 enabled = !enabled;
3350 statusbar("%s %s", which->desc,
3351 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003352}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003353#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003354
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003355void disable_extended_input(void)
3356{
3357 struct termios term;
3358
3359 tcgetattr(0, &term);
3360 term.c_lflag &= ~IEXTEN;
3361 tcsetattr(0, TCSANOW, &term);
3362}
3363
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003364void disable_signals(void)
3365{
3366 struct termios term;
3367
3368 tcgetattr(0, &term);
3369 term.c_lflag &= ~ISIG;
3370 tcsetattr(0, TCSANOW, &term);
3371}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003372
3373#ifndef NANO_SMALL
3374void enable_signals(void)
3375{
3376 struct termios term;
3377
3378 tcgetattr(0, &term);
3379 term.c_lflag |= ISIG;
3380 tcsetattr(0, TCSANOW, &term);
3381}
3382#endif
3383
3384void disable_flow_control(void)
3385{
3386 struct termios term;
3387
3388 tcgetattr(0, &term);
3389 term.c_iflag &= ~(IXON|IXOFF);
3390 tcsetattr(0, TCSANOW, &term);
3391}
3392
3393void enable_flow_control(void)
3394{
3395 struct termios term;
3396
3397 tcgetattr(0, &term);
3398 term.c_iflag |= (IXON|IXOFF);
3399 tcsetattr(0, TCSANOW, &term);
3400}
3401
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003402/* Set up the terminal state. Put the terminal in cbreak mode (read one
3403 * character at a time and interpret the special control keys), disable
3404 * translation of carriage return (^M) into newline (^J) so that we can
3405 * tell the difference between the Enter key and Ctrl-J, and disable
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003406 * echoing of characters as they're typed. Finally, disable extended
3407 * input processing, disable interpretation of the special control keys,
3408 * and if we're not in preserve mode, disable interpretation of the flow
3409 * control characters too. */
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003410void terminal_init(void)
3411{
3412 cbreak();
3413 nonl();
3414 noecho();
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003415 disable_extended_input();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003416 disable_signals();
3417 if (!ISSET(PRESERVE))
3418 disable_flow_control();
3419}
3420
David Lawrence Ramseya27bd652004-08-17 05:23:38 +00003421int main(int argc, char **argv)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003422{
3423 int optchr;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003424 int startline = 0;
3425 /* Line to try and start at. */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003426#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003427 bool fill_flag_used = FALSE;
3428 /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003429#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003430#ifdef ENABLE_MULTIBUFFER
3431 bool old_multibuffer;
3432 /* The old value of the multibuffer option, restored after we
3433 * load all files on the command line. */
3434#endif
3435 int kbinput;
3436 /* Input from keyboard. */
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00003437 bool meta_key, func_key;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003438#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003439 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003440 {"help", 0, 0, 'h'},
3441#ifdef ENABLE_MULTIBUFFER
3442 {"multibuffer", 0, 0, 'F'},
3443#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003444#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003445#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003446 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003447#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003448 {"ignorercfiles", 0, 0, 'I'},
3449#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003450#ifndef DISABLE_JUSTIFY
3451 {"quotestr", 1, 0, 'Q'},
3452#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003453#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003454 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003455#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003456 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003457 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003458#ifdef ENABLE_COLOR
3459 {"syntax", 1, 0, 'Y'},
3460#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003461 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003462 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003463 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003464#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003465 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003466#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003467#ifndef DISABLE_OPERATINGDIR
3468 {"operatingdir", 1, 0, 'o'},
3469#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003470 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003471#ifndef DISABLE_WRAPJUSTIFY
3472 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003473#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003474#ifndef DISABLE_SPELLER
3475 {"speller", 1, 0, 's'},
3476#endif
3477 {"tempfile", 0, 0, 't'},
3478 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003479#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003480 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003481#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003482 {"nohelp", 0, 0, 'x'},
3483 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003484#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003485 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003486 {"backup", 0, 0, 'B'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003487 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003488 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003489 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003490 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003491 {"autoindent", 0, 0, 'i'},
3492 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003493#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003494 {0, 0, 0, 0}
3495 };
3496#endif
3497
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003498 setlocale(LC_ALL, "");
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003499#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003500 bindtextdomain(PACKAGE, LOCALEDIR);
3501 textdomain(PACKAGE);
3502#endif
3503
Chris Allegretta7662c862003-01-13 01:35:15 +00003504#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003505 /* If we don't have rcfile support, we're root, and
3506 * --disable-wrapping-as-root is used, turn wrapping off. */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003507 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003508 SET(NO_WRAP);
3509#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003510
Chris Allegretta6df90f52002-07-19 01:08:59 +00003511 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003512#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey28caf142004-10-07 20:54:52 +00003513 getopt_long(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003514#else
David Lawrence Ramsey28caf142004-10-07 20:54:52 +00003515 getopt(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003516#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003517 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003518
3519 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003520 case 'a':
3521 case 'b':
3522 case 'e':
3523 case 'f':
3524 case 'g':
3525 case 'j':
3526 /* Pico compatibility flags. */
3527 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003528#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003529 case 'A':
3530 SET(SMART_HOME);
3531 break;
3532 case 'B':
3533 SET(BACKUP_FILE);
3534 break;
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003535 case 'E':
3536 backup_dir = mallocstrcpy(backup_dir, optarg);
3537 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003538#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003539#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003540 case 'F':
3541 SET(MULTIBUFFER);
3542 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003543#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003544#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003545#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003546 case 'H':
3547 SET(HISTORYLOG);
3548 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003549#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003550 case 'I':
3551 SET(NO_RCFILE);
3552 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003553#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003554#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003555 case 'N':
3556 SET(NO_CONVERT);
3557 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003558#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003559#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003560 case 'Q':
3561 quotestr = mallocstrcpy(quotestr, optarg);
3562 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003563#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003564#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003565 case 'R':
3566 SET(USE_REGEXP);
3567 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003568#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003569#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003570 case 'S':
3571 SET(SMOOTHSCROLL);
3572 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003573#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003574 case 'T':
3575 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003576 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
3577 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003578 exit(1);
3579 }
3580 break;
3581 case 'V':
3582 version();
3583 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003584#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003585 case 'Y':
3586 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3587 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00003588#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003589 case 'Z':
3590 SET(RESTRICTED);
3591 break;
3592 case 'c':
3593 SET(CONSTUPDATE);
3594 break;
3595 case 'd':
3596 SET(REBIND_DELETE);
3597 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003598#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003599 case 'i':
3600 SET(AUTOINDENT);
3601 break;
3602 case 'k':
3603 SET(CUT_TO_END);
3604 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003605#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003606 case 'l':
3607 SET(NOFOLLOW_SYMLINKS);
3608 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003609#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003610 case 'm':
3611 SET(USE_MOUSE);
3612 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003613#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003614#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003615 case 'o':
3616 operating_dir = mallocstrcpy(operating_dir, optarg);
3617 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003618#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003619 case 'p':
3620 SET(PRESERVE);
3621 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003622#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003623 case 'r':
3624 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003625 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
3626 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003627 exit(1);
3628 }
3629 fill_flag_used = TRUE;
3630 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003631#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003632#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003633 case 's':
3634 alt_speller = mallocstrcpy(alt_speller, optarg);
3635 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003636#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003637 case 't':
3638 SET(TEMP_FILE);
3639 break;
3640 case 'v':
3641 SET(VIEW_MODE);
3642 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003643#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003644 case 'w':
3645 SET(NO_WRAP);
3646 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003647#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003648 case 'x':
3649 SET(NO_HELP);
3650 break;
3651 case 'z':
3652 SET(SUSPEND);
3653 break;
3654 default:
3655 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003656 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003657 }
3658
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003659 /* If the executable filename starts with 'r', we use restricted
3660 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003661 if (*(tail(argv[0])) == 'r')
3662 SET(RESTRICTED);
3663
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003664 /* If we're using restricted mode, disable suspending, backups, and
3665 * reading rcfiles, since they all would allow reading from or
3666 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003667 if (ISSET(RESTRICTED)) {
3668 UNSET(SUSPEND);
3669 UNSET(BACKUP_FILE);
3670 SET(NO_RCFILE);
3671 }
3672
Chris Allegretta7662c862003-01-13 01:35:15 +00003673/* We've read through the command line options. Now back up the flags
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003674 * and values that are set, and read the rcfile(s). If the values
3675 * haven't changed afterward, restore the backed-up values. */
Chris Allegretta7662c862003-01-13 01:35:15 +00003676#ifdef ENABLE_NANORC
3677 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003678#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003679 char *operating_dir_cpy = operating_dir;
3680#endif
David Lawrence Ramsey7e8dd192004-08-12 20:06:20 +00003681#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003682 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003683#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003684#ifndef NANO_SMALL
3685 char *backup_dir_cpy = backup_dir;
3686#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003687#ifndef DISABLE_JUSTIFY
3688 char *quotestr_cpy = quotestr;
3689#endif
3690#ifndef DISABLE_SPELLER
3691 char *alt_speller_cpy = alt_speller;
3692#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003693 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003694 long flags_cpy = flags;
3695
Chris Allegretta5ec68622003-02-05 02:39:34 +00003696#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003697 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003698#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003699#ifndef NANO_SMALL
3700 backup_dir = NULL;
3701#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003702#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003703 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003704#endif
3705#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003706 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003707#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003708
3709 do_rcfile();
3710
3711#ifndef DISABLE_OPERATINGDIR
3712 if (operating_dir_cpy != NULL) {
3713 free(operating_dir);
3714 operating_dir = operating_dir_cpy;
3715 }
3716#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003717#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003718 if (fill_flag_used)
3719 wrap_at = wrap_at_cpy;
3720#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003721#ifndef NANO_SMALL
3722 if (backup_dir_cpy != NULL) {
3723 free(backup_dir);
3724 backup_dir = backup_dir_cpy;
3725 }
3726#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003727#ifndef DISABLE_JUSTIFY
3728 if (quotestr_cpy != NULL) {
3729 free(quotestr);
3730 quotestr = quotestr_cpy;
3731 }
3732#endif
3733#ifndef DISABLE_SPELLER
3734 if (alt_speller_cpy != NULL) {
3735 free(alt_speller);
3736 alt_speller = alt_speller_cpy;
3737 }
3738#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00003739 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00003740 tabsize = tabsize_cpy;
3741 flags |= flags_cpy;
3742 }
3743#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003744 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003745 SET(NO_WRAP);
3746#endif
3747#endif /* ENABLE_NANORC */
3748
Chris Allegrettad8451932003-03-11 03:50:40 +00003749#ifndef NANO_SMALL
3750 history_init();
3751#ifdef ENABLE_NANORC
3752 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3753 load_history();
3754#endif
3755#endif
3756
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003757#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003758 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003759 * in which case backups are disabled, since they would allow
3760 * reading from or writing to files not specified on the command
3761 * line). This entails making sure it exists and is a directory, so
3762 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003763 if (!ISSET(RESTRICTED))
3764 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003765#endif
3766
Chris Allegretta7662c862003-01-13 01:35:15 +00003767#ifndef DISABLE_OPERATINGDIR
3768 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003769 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003770 init_operating_dir();
3771#endif
3772
Chris Allegretta7662c862003-01-13 01:35:15 +00003773#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003774 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003775 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003776
3777 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003778 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003779
Chris Allegretta7662c862003-01-13 01:35:15 +00003780 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003781 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003782#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003783 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003784#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003785 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003786#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003787 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003788#ifdef HAVE_REGEX_H
3789 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
3790
3791 if (quoterc == 0) {
3792 /* We no longer need quotestr, just quotereg. */
3793 free(quotestr);
3794 quotestr = NULL;
3795 } else {
3796 size_t size = regerror(quoterc, &quotereg, NULL, 0);
3797
3798 quoteerr = charalloc(size);
3799 regerror(quoterc, &quotereg, quoteerr, size);
3800 }
3801#else
3802 quotelen = strlen(quotestr);
3803#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00003804#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003805
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003806#ifndef DISABLE_SPELLER
3807 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003808 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003809 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003810 * checking is disabled, since it would allow reading from or
3811 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003812 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003813 char *spellenv = getenv("SPELL");
3814 if (spellenv != NULL)
3815 alt_speller = mallocstrcpy(NULL, spellenv);
3816 }
3817#endif
3818
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003819#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003820 /* If whitespace wasn't specified, set its default value. */
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003821 if (whitespace == NULL)
3822 whitespace = mallocstrcpy(NULL, " ");
3823#endif
3824
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003825 /* If tabsize wasn't specified, set its default value. */
Chris Allegretta7662c862003-01-13 01:35:15 +00003826 if (tabsize == -1)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003827 tabsize = WIDTH_OF_TAB;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003828
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003829 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003830 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003831
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003832 /* Curses initialization stuff: Start curses and set up the
3833 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003834 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003835 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003836
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003837 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003838 global_init(FALSE);
3839 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003840
3841 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003842 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003843
3844#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003845 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003846#endif
3847
Chris Allegretta2a42af12000-09-12 23:02:49 +00003848 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003849#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003850 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003851#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003852
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003853#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003854 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003855#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003856
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00003857 /* If there's a +LINE flag here, it is the first non-option
3858 * argument, and it is followed by at least one other argument, the
3859 * filename it applies to. */
3860 if (0 < optind && optind < argc - 1 && argv[optind][0] == '+') {
3861 startline = atoi(&argv[optind][1]);
3862 optind++;
3863 }
3864
Chris Allegretta7662c862003-01-13 01:35:15 +00003865#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003866 old_multibuffer = ISSET(MULTIBUFFER);
3867 SET(MULTIBUFFER);
3868
3869 /* Read all the files after the first one on the command line into
3870 * new buffers. */
3871 {
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00003872 int i = optind + 1, iline = 0;
3873 for (; i < argc; i++) {
3874 /* If there's a +LINE flag here, it is followed by at least
3875 * one other argument, the filename it applies to. */
3876 if (i < argc - 1 && argv[i][0] == '+' && iline == 0) {
3877 iline = atoi(&argv[i][1]);
3878 } else {
3879 load_buffer(argv[i]);
3880 if (iline > 0) {
3881 do_gotoline(iline, FALSE);
3882 iline = 0;
3883 }
3884 }
3885 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003886 }
3887#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003888
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003889 /* Read the first file on the command line into either the current
3890 * buffer or a new buffer, depending on whether multibuffer mode is
3891 * enabled. */
3892 if (optind < argc)
3893 load_buffer(argv[optind]);
3894
3895 /* We didn't open any files if all the command line arguments were
3896 * invalid files like directories or if there were no command line
3897 * arguments given. In this case, we have to load a blank buffer.
3898 * Also, we unset view mode to allow editing. */
3899 if (filename == NULL) {
3900 filename = mallocstrcpy(NULL, "");
3901 new_file();
3902 UNSET(VIEW_MODE);
3903
3904 /* Add this new entry to the open_files structure if we have
3905 * multibuffer support, or to the main filestruct if we don't. */
3906 load_file();
3907 }
3908
3909#ifdef ENABLE_MULTIBUFFER
3910 if (!old_multibuffer)
3911 UNSET(MULTIBUFFER);
3912#endif
3913
3914#ifdef DEBUG
3915 fprintf(stderr, "Main: top and bottom win\n");
3916#endif
3917
3918 titlebar(NULL);
3919 display_main_list();
3920
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003921 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003922 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003923
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003924#ifndef NANO_SMALL
3925 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003926 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003927#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003928
Robert Siemborski6967eec2000-07-08 14:23:32 +00003929 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00003930
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003931 while (TRUE) {
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00003932 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003933 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003934 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003935
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003936#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003937 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003938#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003939
David Lawrence Ramseyd994ad52004-11-23 21:40:26 +00003940 kbinput = get_edit_input(&meta_key, &func_key, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003941
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003942 /* Last gasp, stuff that's not in the main lists. */
David Lawrence Ramseye6ef8b92004-09-12 22:01:38 +00003943 if (kbinput != ERR && !is_cntrl_char(kbinput)) {
David Lawrence Ramsey807657b2004-09-12 21:40:04 +00003944 /* Don't stop unhandled printable sequences, so that people
3945 * with odd character sets can type. */
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003946 if (ISSET(VIEW_MODE))
3947 print_view_warning();
3948 else
3949 do_char(kbinput);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003950 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003951 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003952 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003953}