blob: 00c0fd5feebc859c6858a22e153b126a1b72803e [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 Ramseyc13b7f02005-01-01 07:28:15 +00005 * Copyright (C) 1999-2005 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
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000047#ifdef HAVE_GETOPT_H
48#include <getopt.h>
49#endif
50
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000051#ifndef NANO_SMALL
52#include <setjmp.h>
53#endif
54
Chris Allegretta6fe61492001-05-21 12:56:25 +000055#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000056static ssize_t fill = 0; /* Fill - where to wrap lines,
57 basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000058#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000059#ifndef DISABLE_WRAPPING
David Lawrence Ramseyce62e822004-08-05 22:10:22 +000060static bool same_line_wrap = FALSE; /* Whether wrapped text should
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000061 be prepended to the next
62 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000063#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000064
Chris Allegretta6df90f52002-07-19 01:08:59 +000065static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000066static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000067
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000068#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000069static sigjmp_buf jmpbuf; /* Used to return to mainloop after
70 SIGWINCH */
David Lawrence Ramsey22fac782004-08-05 15:16:19 +000071static int pid; /* The PID of the newly forked process
72 * in open_pipe(). It must be global
73 * because the signal handler needs
74 * it. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000075#endif
Chris Allegretta08020882001-01-29 23:37:54 +000076
David Lawrence Ramsey93c84052004-11-23 04:08:28 +000077#ifndef DISABLE_JUSTIFY
78static filestruct *jusbottom = NULL;
79 /* Pointer to end of justify buffer. */
80#endif
81
David Lawrence Ramseyda141062004-05-25 19:41:11 +000082/* What we do when we're all set to exit. */
83void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000084{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000085 if (!ISSET(NO_HELP))
86 blank_bottombars();
87 else
88 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000089
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000090 wrefresh(bottomwin);
91 endwin();
92
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000093 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000094 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000095
Chris Allegrettad8451932003-03-11 03:50:40 +000096#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
97 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
98 save_history();
99#endif
100
Chris Allegretta6232d662002-05-12 19:52:15 +0000101#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000102 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000103#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000104
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000105 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000106}
107
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000108/* Die (gracefully?). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000109void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000110{
111 va_list ap;
112
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000113 endwin();
114 curses_ended = TRUE;
115
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000116 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000117 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000118
Chris Allegretta6df90f52002-07-19 01:08:59 +0000119 va_start(ap, msg);
120 vfprintf(stderr, msg, ap);
121 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000122
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000123 /* Save the current file buffer if it's been modified. */
Chris Allegretta32da4562002-01-02 15:12:21 +0000124 if (ISSET(MODIFIED))
125 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000126
Chris Allegretta355fbe52001-07-14 19:32:47 +0000127#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000128 /* Save all of the other modified file buffers, if any. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000129 if (open_files != NULL) {
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000130 openfilestruct *tmp = open_files;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000131
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000132 while (tmp != open_files->next) {
133 open_files = open_files->next;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000134
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000135 /* Save the current file buffer if it's been modified. */
136 if (open_files->flags & MODIFIED) {
137 /* Set fileage and filebot to match the current file
138 * buffer, and then write it to disk. */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000139 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000140 filebot = open_files->filebot;
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000141 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000142 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000144 }
145#endif
146
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000147 /* Get out. */
148 exit(1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149}
150
Chris Allegretta6df90f52002-07-19 01:08:59 +0000151void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000152{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000153 char *ret;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000154 bool failed = TRUE;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000155
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000156 /* If we're using restricted mode, don't write any emergency backup
157 * files, since that would allow reading from or writing to files
158 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000159 if (ISSET(RESTRICTED))
160 return;
161
Chris Allegretta6df90f52002-07-19 01:08:59 +0000162 /* If we can't save, we have REAL bad problems, but we might as well
163 TRY. */
164 if (die_filename[0] == '\0')
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000165 die_filename = "nano";
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000167 ret = get_next_filename(die_filename);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168 if (ret[0] != '\0')
David Lawrence Ramsey951d7142004-10-04 15:23:47 +0000169 failed = (write_file(ret, TRUE, FALSE, TRUE) == -1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000170
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000171 if (!failed)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000173 else
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000174 fprintf(stderr, _("\nBuffer not written to %s (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000175
176 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000177}
178
Chris Allegrettae61e8302001-01-14 05:18:27 +0000179/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000180 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000181void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000182{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000183 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000184}
185
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000186void print_view_warning(void)
187{
188 statusbar(_("Key illegal in VIEW mode"));
189}
190
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000191/* Initialize global variables -- no better way for now. If
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000192 * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
193void global_init(bool save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000194{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000195 current_x = 0;
196 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000197
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000198 editwinrows = LINES - 5 + no_help();
199 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000200 die_too_small();
201
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000202 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000203 if (!save_cutbuffer)
204 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000205 current = NULL;
206 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000207 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000208 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000209 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000210
Chris Allegretta6fe61492001-05-21 12:56:25 +0000211#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000212 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000213 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000214 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000215 if (fill < 0)
216 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000217#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000218
Chris Allegretta88b09152001-05-17 11:35:43 +0000219 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000220 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000221 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000222}
223
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000224void window_init(void)
225{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000226 editwinrows = LINES - 5 + no_help();
227 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000228 die_too_small();
229
Chris Allegretta1a128af2003-01-26 04:15:56 +0000230 if (topwin != NULL)
231 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000232 if (edit != NULL)
233 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000234 if (bottomwin != NULL)
235 delwin(bottomwin);
236
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000237 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000238 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000239 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000240 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
241
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000242 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000243 keypad(edit, TRUE);
244 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000245}
246
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000247#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248void mouse_init(void)
249{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000250 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251 mousemask(BUTTON1_RELEASED, NULL);
252 mouseinterval(50);
253 } else
254 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000256#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257
258#ifndef DISABLE_HELP
259/* This function allocates help_text, and stores the help string in it.
260 * help_text should be NULL initially. */
261void help_init(void)
262{
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000263 size_t allocsize = 1; /* Space needed for help_text. */
264 const char *htx; /* Untranslated help message. */
265 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000266 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000267#ifndef NANO_SMALL
268 const toggle *t;
269#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000270
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000271 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000272 if (currshortcut == whereis_list || currshortcut == replace_list
273 || currshortcut == replace_list_2)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000274 htx = N_("Search Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000275 "Enter the words or characters you would like to search "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000276 "for, then hit Enter. If there is a match for the text you "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000277 "entered, the screen will be updated to the location of the "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000278 "nearest match for the search string.\n\n The previous "
279 "search string will be shown in brackets after the search "
280 "prompt. Hitting Enter without entering any text will "
281 "perform the previous search. If you have selected text "
282 "with the mark and then search to replace, only matches in "
283 "the selected text will be replaced.\n\n The following "
284 "function keys are available in Search mode:\n\n");
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000285 else if (currshortcut == gotoline_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000286 htx = N_("Go To Line Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000287 "Enter the line number that you wish to go to and hit "
288 "Enter. If there are fewer lines of text than the "
289 "number you entered, you will be brought to the last line "
290 "of the file.\n\n The following function keys are "
291 "available in Go To Line mode:\n\n");
292 else if (currshortcut == insertfile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000293 htx = N_("Insert File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000294 "Type in the name of a file to be inserted into the current "
295 "file buffer at the current cursor location.\n\n "
296 "If you have compiled nano with multiple file buffer "
297 "support, and enable multiple buffers with the -F "
298 "or --multibuffer command line flags, the Meta-F toggle, or "
299 "a nanorc file, inserting a file will cause it to be "
300 "loaded into a separate buffer (use Meta-< and > to switch "
David Lawrence Ramseyfdd3bec2004-11-07 21:30:55 +0000301 "between file buffers). If you need another blank buffer, "
302 "do not enter any filename, or type in a nonexistent "
303 "filename at the prompt and press Enter.\n\n The following "
304 "function keys are available in Insert File mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000305 else if (currshortcut == writefile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000306 htx = N_("Write File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000307 "Type the name that you wish to save the current file "
308 "as and hit Enter to save the file.\n\n If you have "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000309 "selected text with the mark, you will be prompted to "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000310 "save only the selected portion to a separate file. To "
311 "reduce the chance of overwriting the current file with "
312 "just a portion of it, the current filename is not the "
313 "default in this mode.\n\n The following function keys "
314 "are available in Write File mode:\n\n");
315#ifndef DISABLE_BROWSER
316 else if (currshortcut == browser_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000317 htx = N_("File Browser Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000318 "The file browser is used to visually browse the "
319 "directory structure to select a file for reading "
320 "or writing. You may use the arrow keys or Page Up/"
321 "Down to browse through the files, and S or Enter to "
322 "choose the selected file or enter the selected "
323 "directory. To move up one level, select the directory "
324 "called \"..\" at the top of the file list.\n\n The "
325 "following function keys are available in the file "
326 "browser:\n\n");
327 else if (currshortcut == gotodir_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000328 htx = N_("Browser Go To Directory Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000329 "Enter the name of the directory you would like to "
330 "browse to.\n\n If tab completion has not been disabled, "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000331 "you can use the Tab key to (attempt to) automatically "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000332 "complete the directory name.\n\n The following function "
333 "keys are available in Browser Go To Directory mode:\n\n");
334#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000335#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000336 else if (currshortcut == spell_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000337 htx = N_("Spell Check Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000338 "The spell checker checks the spelling of all text "
339 "in the current file. When an unknown word is "
340 "encountered, it is highlighted and a replacement can "
341 "be edited. It will then prompt to replace every "
342 "instance of the given misspelled word in the "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000343 "current file, or, if you have selected text with the "
344 "mark, in the selected text.\n\n The following other "
345 "functions are available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000346#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000347#ifndef NANO_SMALL
348 else if (currshortcut == extcmd_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000349 htx = N_("External Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000350 "This menu allows you to insert the output of a command "
351 "run by the shell into the current buffer (or a new "
David Lawrence Ramseyfdd3bec2004-11-07 21:30:55 +0000352 "buffer in multibuffer mode). If you need another blank "
353 "buffer, do not enter any command.\n\n The following keys "
354 "are available in this mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000355#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000356 else
357 /* Default to the main help list. */
358 htx = N_(" nano help text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000359 "The nano editor is designed to emulate the functionality and "
360 "ease-of-use of the UW Pico text editor. There are four main "
361 "sections of the editor: The top line shows the program "
362 "version, the current filename being edited, and whether "
363 "or not the file has been modified. Next is the main editor "
364 "window showing the file being edited. The status line is "
365 "the third line from the bottom and shows important messages. "
366 "The bottom two lines show the most commonly used shortcuts "
367 "in the editor.\n\n "
368 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000369 "sequences are notated with a caret (^) symbol and can be "
370 "entered either by using the Control (Ctrl) key or pressing the "
371 "Esc key twice. Escape-key sequences are notated with the Meta "
372 "(M) symbol and can be entered using either the Esc, Alt or "
373 "Meta key depending on your keyboard setup. Also, pressing Esc "
374 "twice and then typing a three-digit number from 000 to 255 "
David Lawrence Ramseyf0a53f02005-01-03 19:56:56 +0000375 "will enter the character with the corresponding value. The "
376 "following keystrokes are available in the main editor window. "
377 "Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000378
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000379 htx = _(htx);
380
381 allocsize += strlen(htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000382
383 /* The space needed for the shortcut lists, at most COLS characters,
384 * plus '\n'. */
David Lawrence Ramsey1f1ebb82004-11-11 21:50:01 +0000385 allocsize += (COLS < 21 ? 21 : COLS + 1) *
386 length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000387
388#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000389 /* If we're on the main list, we also count the toggle help text.
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000390 * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
391 * plus translated text, plus '\n'. */
Chris Allegretta3a784062003-02-10 02:32:58 +0000392 if (currshortcut == main_list) {
393 size_t endislen = strlen(_("enable/disable"));
394
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000395 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000396 allocsize += 8 + strlen(t->desc) + endislen;
397 }
David Lawrence Ramsey1f1ebb82004-11-11 21:50:01 +0000398#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000399
400 /* help_text has been freed and set to NULL unless the user resized
401 * while in the help screen. */
402 free(help_text);
403
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000404 /* Allocate space for the help text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000405 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000406
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000407 /* Now add the text we want. */
408 strcpy(help_text, htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000409 ptr = help_text + strlen(help_text);
410
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000411 /* Now add our shortcut info. Assume that each shortcut has, at the
412 * very least, an equivalent control key, an equivalent primary meta
413 * key sequence, or both. Also assume that the meta key values are
414 * not control characters. We can display a maximum of 3 shortcut
415 * entries. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000416 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000417 int entries = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000418
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000419 /* Control key. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000420 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000421 entries++;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000422#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000423 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000424 ptr += sprintf(ptr, "%.7s", _("Up"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000425 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000426#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000427 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000428 ptr += sprintf(ptr, "^%.6s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000429 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000430 ptr += sprintf(ptr, "^?");
431 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000432 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000433 *(ptr++) = '\t';
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000434 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000435
436 /* Function key. */
437 if (s->funcval != NANO_NO_KEY) {
438 entries++;
David Lawrence Ramsey2e83a502004-11-01 22:35:26 +0000439 /* If this is the first entry, put it in the middle. */
440 if (entries == 1) {
441 entries++;
442 *(ptr++) = '\t';
443 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000444 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
445 *(ptr++) = '\t';
446 }
447
448 /* Primary meta key sequence. */
449 if (s->metaval != NANO_NO_KEY) {
450 entries++;
451 /* If this is the last entry, put it at the end. */
452 if (entries == 2 && s->miscval == NANO_NO_KEY) {
453 entries++;
454 *(ptr++) = '\t';
455 }
456 /* If the primary meta key sequence is the first entry,
457 * don't put parentheses around it. */
458 if (entries == 1 && s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000459 ptr += sprintf(ptr, "M-%.5s", _("Space"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000460 else
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000461 ptr += sprintf(ptr, entries == 1 ? "M-%c" : "(M-%c)",
462 toupper(s->metaval));
463 *(ptr++) = '\t';
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000464 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000465
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000466 /* Miscellaneous meta key sequence. */
467 if (entries < 3 && s->miscval != NANO_NO_KEY) {
468 entries++;
469 /* If this is the last entry, put it at the end. */
470 if (entries == 2) {
471 entries++;
472 *(ptr++) = '\t';
473 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000474 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000475 *(ptr++) = '\t';
476 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000477
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000478 /* Make sure all the help text starts at the same place. */
479 while (entries < 3) {
480 entries++;
481 *(ptr++) = '\t';
482 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000483
484 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000485 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000486 }
487
488#ifndef NANO_SMALL
489 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000490 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000491 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000492 assert(t->desc != NULL);
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +0000493 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
494 t->desc, _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000495 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000496 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000497#endif /* !NANO_SMALL */
498
499 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000500 * help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000501 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000502}
503#endif
504
505/* Create a new filestruct node. Note that we specifically do not set
506 * prevnode->next equal to the new line. */
507filestruct *make_new_node(filestruct *prevnode)
508{
509 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000510 newnode->data = NULL;
511 newnode->prev = prevnode;
512 newnode->next = NULL;
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000513 newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000514 return newnode;
515}
516
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000517/* Make a copy of a filestruct node. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000518filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000519{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000520 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000521 assert(src != NULL);
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000522 dst->data = mallocstrcpy(NULL, src->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523 dst->next = src->next;
524 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000525 dst->lineno = src->lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000526 return dst;
527}
528
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000529/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000530void splice_node(filestruct *begin, filestruct *newnode, filestruct
531 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000532{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000533 assert(newnode != NULL && begin != NULL);
534 newnode->next = end;
535 newnode->prev = begin;
536 begin->next = newnode;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000537 if (end != NULL)
538 end->prev = newnode;
539}
540
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000541/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000542void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000544 assert(fileptr != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000545 if (fileptr->prev != NULL)
546 fileptr->prev->next = fileptr->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547 if (fileptr->next != NULL)
548 fileptr->next->prev = fileptr->prev;
549}
550
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000551/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000552void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000553{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000554 assert(fileptr != NULL && fileptr->data != NULL);
555 if (fileptr->data != NULL)
556 free(fileptr->data);
557 free(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000558}
559
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000560/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000561filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000563 filestruct *head; /* copy of src, top of the copied list */
564 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000565
Chris Allegretta6df90f52002-07-19 01:08:59 +0000566 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000567
Chris Allegretta6df90f52002-07-19 01:08:59 +0000568 prev = copy_node(src);
569 prev->prev = NULL;
570 head = prev;
571 src = src->next;
572 while (src != NULL) {
573 prev->next = copy_node(src);
574 prev->next->prev = prev;
575 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000576
Chris Allegretta6df90f52002-07-19 01:08:59 +0000577 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000578 }
579
Chris Allegretta6df90f52002-07-19 01:08:59 +0000580 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581 return head;
582}
583
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000584/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000585void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000587 assert(src != NULL);
588
589 while (src->next != NULL) {
590 src = src->next;
591 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000592 }
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000593 delete_node(src);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594}
595
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000596/* Partition a filestruct so it begins at (top, top_x) and ends at (bot,
597 * bot_x). */
598partition *partition_filestruct(filestruct *top, size_t top_x,
599 filestruct *bot, size_t bot_x)
600{
601 partition *p;
David Lawrence Ramsey6299b0d2004-11-08 03:22:23 +0000602 assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000603
604 /* Initialize the partition. */
605 p = (partition *)nmalloc(sizeof(partition));
606
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000607 /* If the top and bottom of the partition are different from the top
608 * and bottom of the filestruct, save the latter and then set them
609 * to top and bot. */
610 if (top != fileage) {
611 p->fileage = fileage;
612 fileage = top;
613 } else
614 p->fileage = NULL;
615 if (bot != filebot) {
616 p->filebot = filebot;
617 filebot = bot;
618 } else
619 p->filebot = NULL;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000620
621 /* Save the line above the top of the partition, detach the top of
622 * the partition from it, and save the text before top_x in
623 * top_data. */
624 p->top_prev = top->prev;
625 top->prev = NULL;
626 p->top_data = mallocstrncpy(NULL, top->data, top_x + 1);
627 p->top_data[top_x] = '\0';
628
629 /* Save the line below the bottom of the partition, detach the
630 * bottom of the partition from it, and save the text after bot_x in
631 * bot_data. */
632 p->bot_next = bot->next;
633 bot->next = NULL;
634 p->bot_data = mallocstrcpy(NULL, bot->data + bot_x);
635
636 /* Remove all text after bot_x at the bottom of the partition. */
637 null_at(&bot->data, bot_x);
638
639 /* Remove all text before top_x at the top of the partition. */
640 charmove(top->data, top->data + top_x, strlen(top->data) -
641 top_x + 1);
642 align(&top->data);
643
644 /* Return the partition. */
645 return p;
646}
647
648/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
649 * (filebot, strlen(filebot)) again. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000650void unpartition_filestruct(partition **p)
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000651{
652 char *tmp;
David Lawrence Ramsey2c315402004-11-08 03:19:10 +0000653 assert(p != NULL && fileage != NULL && filebot != NULL);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000654
655 /* Reattach the line above the top of the partition, and restore the
656 * text before top_x from top_data. Free top_data when we're done
657 * with it. */
658 tmp = mallocstrcpy(NULL, fileage->data);
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000659 fileage->prev = (*p)->top_prev;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000660 if (fileage->prev != NULL)
661 fileage->prev->next = fileage;
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000662 fileage->data = charealloc(fileage->data, strlen((*p)->top_data) +
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000663 strlen(fileage->data) + 1);
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000664 strcpy(fileage->data, (*p)->top_data);
665 free((*p)->top_data);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000666 strcat(fileage->data, tmp);
667 free(tmp);
668
669 /* Reattach the line below the bottom of the partition, and restore
670 * the text after bot_x from bot_data. Free bot_data when we're
671 * done with it. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000672 filebot->next = (*p)->bot_next;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000673 if (filebot->next != NULL)
674 filebot->next->prev = filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000675 filebot->data = charealloc(filebot->data, strlen(filebot->data) +
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000676 strlen((*p)->bot_data) + 1);
677 strcat(filebot->data, (*p)->bot_data);
678 free((*p)->bot_data);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000679
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000680 /* Restore the top and bottom of the filestruct, if they were
681 * different from the top and bottom of the partition. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000682 if ((*p)->fileage != NULL)
683 fileage = (*p)->fileage;
684 if ((*p)->filebot != NULL)
685 filebot = (*p)->filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000686
687 /* Uninitialize the partition. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000688 free(*p);
689 *p = NULL;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000690}
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000691
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000692/* Move all the text between (top, top_x) and (bot, bot_x) in the
693 * current filestruct to a filestruct beginning with file_top and ending
694 * with file_bot. If no text is between (top, top_x) and (bot, bot_x),
695 * don't do anything. */
696void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
697 filestruct *top, size_t top_x, filestruct *bot, size_t bot_x)
698{
699 filestruct *top_save;
700 long part_totsize;
701 bool at_edittop;
702#ifndef NANO_SMALL
703 bool mark_inside = FALSE;
704#endif
705
706 assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
707
708 /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
709 if (top == bot && top_x == bot_x)
710 return;
711
712 /* Partition the filestruct so that it contains only the text from
713 * (top, top_x) to (bot, bot_x), keep track of whether the top of
714 * the partition is the top of the edit window, and keep track of
715 * whether the mark begins inside the partition. */
716 filepart = partition_filestruct(top, top_x, bot, bot_x);
717 at_edittop = (fileage == edittop);
718#ifndef NANO_SMALL
719 if (ISSET(MARK_ISSET))
720 mark_inside = (mark_beginbuf->lineno >= fileage->lineno &&
721 mark_beginbuf->lineno <= filebot->lineno &&
722 (mark_beginbuf != fileage || mark_beginx >= top_x) &&
723 (mark_beginbuf != filebot || mark_beginx <= bot_x));
724#endif
725
726 /* Get the number of characters in the text, and subtract it from
727 * totsize. */
728 get_totals(top, bot, NULL, &part_totsize);
729 totsize -= part_totsize;
730
731 if (*file_top == NULL) {
732 /* If file_top is empty, just move all the text directly into
733 * it. This is equivalent to tacking the text in top onto the
734 * (lack of) text at the end of file_top. */
735 *file_top = fileage;
736 *file_bot = filebot;
737 } else {
738 /* Otherwise, tack the text in top onto the text at the end of
739 * file_bot. */
740 (*file_bot)->data = charealloc((*file_bot)->data,
741 strlen((*file_bot)->data) + strlen(fileage->data) + 1);
742 strcat((*file_bot)->data, fileage->data);
743
744 /* Attach the line after top to the line after file_bot. Then,
745 * if there's more than one line after top, move file_bot down
746 * to bot. */
747 (*file_bot)->next = fileage->next;
748 if ((*file_bot)->next != NULL) {
749 (*file_bot)->next->prev = *file_bot;
750 *file_bot = filebot;
751 }
752 }
753
754 /* Since the text has now been saved, remove it from the filestruct.
755 * If the top of the partition was the top of the edit window, set
756 * edittop to where the text used to start. If the mark began
757 * inside the partition, set the beginning of the mark to where the
758 * text used to start. */
759 fileage = (filestruct *)nmalloc(sizeof(filestruct));
760 fileage->data = mallocstrcpy(NULL, "");
761 filebot = fileage;
762 if (at_edittop)
763 edittop = fileage;
764#ifndef NANO_SMALL
765 if (mark_inside) {
766 mark_beginbuf = fileage;
767 mark_beginx = top_x;
768 }
769#endif
770
771 /* Restore the current line and cursor position. */
772 current = fileage;
773 current_x = top_x;
774
775 top_save = fileage;
776
777 /* Unpartition the filestruct so that it contains all the text
778 * again, minus the saved text. */
779 unpartition_filestruct(&filepart);
780
781 /* Renumber starting with the beginning line of the old
782 * partition. */
783 renumber(top_save);
784
785 if (filebot->data[0] != '\0')
786 new_magicline();
787
788 /* Set totlines to the new number of lines in the file. */
789 totlines = filebot->lineno;
790}
791
792/* Copy all the text from the filestruct beginning with file_top and
793 * ending with file_bot to the current filestruct at the current cursor
794 * position. */
795void copy_from_filestruct(filestruct *file_top, filestruct *file_bot)
796{
797 filestruct *top_save;
798 int part_totlines;
799 long part_totsize;
800 bool at_edittop;
801
802 assert(file_top != NULL && file_bot != NULL);
803
804 /* Partition the filestruct so that it contains no text, and keep
805 * track of whether the top of the partition is the top of the edit
806 * window. */
807 filepart = partition_filestruct(current, current_x, current,
808 current_x);
809 at_edittop = (fileage == edittop);
810
811 /* Put the top and bottom of the filestruct at copies of file_top
812 * and file_bot. */
813 fileage = copy_filestruct(file_top);
814 filebot = fileage;
815 while (filebot->next != NULL)
816 filebot = filebot->next;
817
818 /* Restore the current line and cursor position. */
819 current = filebot;
820 current_x = strlen(filebot->data);
821 if (fileage == filebot)
822 current_x += strlen(filepart->top_data);
823
824 /* Get the number of lines and the number of characters in the saved
825 * text, and add the latter to totsize. */
826 get_totals(fileage, filebot, &part_totlines, &part_totsize);
827 totsize += part_totsize;
828
829 /* If the top of the partition was the top of the edit window, set
830 * edittop to where the saved text now starts, and update the
831 * current y-coordinate to account for the number of lines it
832 * has, less one since the first line will be tacked onto the
833 * current line. */
834 if (at_edittop)
835 edittop = fileage;
836 current_y += part_totlines - 1;
837
838 top_save = fileage;
839
840 /* Unpartition the filestruct so that it contains all the text
841 * again, minus the saved text. */
842 unpartition_filestruct(&filepart);
843
844 /* Renumber starting with the beginning line of the old
845 * partition. */
846 renumber(top_save);
847
848 if (filebot->data[0] != '\0')
849 new_magicline();
850
851 /* Set totlines to the new number of lines in the file. */
852 totlines = filebot->lineno;
853}
854
Chris Allegretta6df90f52002-07-19 01:08:59 +0000855void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000856{
857 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000858 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000859
Chris Allegretta6df90f52002-07-19 01:08:59 +0000860 assert(fileage == NULL || fileage != fileage->next);
861 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000862 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000863}
864
Chris Allegretta6df90f52002-07-19 01:08:59 +0000865void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000866{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000867 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000868 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000869 else {
870 int lineno = fileptr->prev->lineno;
871
872 assert(fileptr != fileptr->next);
873 for (; fileptr != NULL; fileptr = fileptr->next)
874 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000875 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000876}
877
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000878/* Print one usage string to the screen. This cuts down on duplicate
879 * strings to translate and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000880 * translatable (the flag names). */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000881void print1opt(const char *shortflag, const char *longflag, const char
882 *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000883{
884 printf(" %s\t", shortflag);
885 if (strlen(shortflag) < 8)
886 printf("\t");
887
888#ifdef HAVE_GETOPT_LONG
889 printf("%s\t", longflag);
890 if (strlen(longflag) < 8)
891 printf("\t\t");
892 else if (strlen(longflag) < 16)
893 printf("\t");
894#endif
895
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000896 printf("%s\n", _(desc));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000897}
898
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000899void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000900{
901#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000902 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
903 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000904#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000905 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
906 printf(_("Option\t\tMeaning\n"));
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +0000907#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000908
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000909 print1opt("-h, -?", "--help", N_("Show this message"));
910 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000911#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000912 print1opt("-A", "--smarthome", N_("Enable smart home key"));
913 print1opt("-B", "--backup", N_("Backup existing files on save"));
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000914 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000915#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000916#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000917 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000918#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000919#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000920#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000921 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000922#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000923 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000924#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000925#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000926 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000927#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000928#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000929 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000930#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000931#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000932 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000933#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000934#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000935 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000936#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000937 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
938 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000939#ifdef ENABLE_COLOR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000940 print1opt(_("-Y [str]"), _("--syntax [str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000941#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000942 print1opt("-Z", "--restricted", N_("Restricted mode"));
943 print1opt("-c", "--const", N_("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000944#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000945 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
946 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
947 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000948#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000949 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000950#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000951 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000952#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000953#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000954 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000955#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000956 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000957#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000958 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000959#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000960#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000961 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000962#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000963 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
964 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000965#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000966 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000967#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000968 print1opt("-x", "--nohelp", N_("Don't show help window"));
969 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000970
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000971 /* This is a special case. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000972 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000973
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000974 exit(0);
975}
976
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000977void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000978{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000979 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000980 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000981 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000982 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000983 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000984
Chris Allegrettae6600372003-01-17 03:39:41 +0000985#ifndef ENABLE_NLS
986 printf(" --disable-nls");
987#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000988#ifdef DEBUG
989 printf(" --enable-debug");
990#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000991#ifdef NANO_EXTRA
992 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000993#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000994#ifdef NANO_SMALL
995 printf(" --enable-tiny");
996#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000997#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000998 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000999#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001000#ifdef DISABLE_HELP
1001 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001002#endif
1003#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00001004 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001005#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001006#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +00001007 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +00001008#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00001009#ifdef DISABLE_OPERATINGDIR
1010 printf(" --disable-operatingdir");
1011#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001012#ifdef DISABLE_SPELLER
1013 printf(" --disable-speller");
1014#endif
1015#ifdef DISABLE_TABCOMP
1016 printf(" --disable-tabcomp");
1017#endif
Chris Allegretta84de5522001-04-12 14:51:48 +00001018#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001019#ifdef DISABLE_WRAPPING
1020 printf(" --disable-wrapping");
1021#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00001022#ifdef DISABLE_ROOTWRAP
1023 printf(" --disable-wrapping-as-root");
1024#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001025#ifdef ENABLE_COLOR
1026 printf(" --enable-color");
1027#endif
1028#ifdef ENABLE_MULTIBUFFER
1029 printf(" --enable-multibuffer");
1030#endif
1031#ifdef ENABLE_NANORC
1032 printf(" --enable-nanorc");
1033#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001034#ifdef USE_SLANG
1035 printf(" --with-slang");
1036#endif
1037 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001038}
1039
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001040int no_help(void)
1041{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001042 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001043}
1044
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001045void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +00001046{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001047 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +00001048}
1049
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001050#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001051RETSIGTYPE cancel_fork(int signal)
1052{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001053 if (kill(pid, SIGKILL) == -1)
1054 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001055}
1056
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001057/* Return TRUE on success. */
1058bool open_pipe(const char *command)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001059{
1060 int fd[2];
1061 FILE *f;
1062 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +00001063 /* Original and temporary handlers for
1064 * SIGINT. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001065 bool sig_failed = FALSE;
1066 /* sig_failed means that sigaction() failed without changing the
1067 * signal handlers.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001068 *
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001069 * We use this variable since it is important to put things back
1070 * when we finish, even if we get errors. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001071
1072 /* Make our pipes. */
1073
1074 if (pipe(fd) == -1) {
1075 statusbar(_("Could not pipe"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001076 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001077 }
1078
1079 /* Fork a child. */
1080
1081 if ((pid = fork()) == 0) {
1082 close(fd[0]);
1083 dup2(fd[1], fileno(stdout));
1084 dup2(fd[1], fileno(stderr));
1085 /* If execl() returns at all, there was an error. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001086
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001087 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001088 exit(0);
1089 }
1090
1091 /* Else continue as parent. */
1092
1093 close(fd[1]);
1094
1095 if (pid == -1) {
1096 close(fd[0]);
1097 statusbar(_("Could not fork"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001098 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001099 }
1100
1101 /* Before we start reading the forked command's output, we set
1102 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001103
David Lawrence Ramseye608f942004-05-19 16:04:27 +00001104 /* Enable interpretation of the special control keys so that we get
1105 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001106 enable_signals();
1107
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001108 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001109 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001110 nperror("sigaction");
1111 } else {
1112 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001113 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001114 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001115 nperror("sigaction");
1116 }
1117 }
1118 /* Note that now oldaction is the previous SIGINT signal handler,
1119 * to be restored later. */
1120
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001121 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001122 if (f == NULL)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001123 nperror("fdopen");
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001124
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001125 read_file(f, "stdin");
David Lawrence Ramsey22fac782004-08-05 15:16:19 +00001126 /* If multibuffer mode is on, we could be here in view mode. If so,
1127 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001128 if (!ISSET(VIEW_MODE))
1129 set_modified();
1130
1131 if (wait(NULL) == -1)
1132 nperror("wait");
1133
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001134 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001135 nperror("sigaction");
1136
David Lawrence Ramseye608f942004-05-19 16:04:27 +00001137 /* Disable interpretation of the special control keys so that we can
1138 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001139 disable_signals();
1140
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001141 return TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001142}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +00001143#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001144
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001145void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001146{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001147 int *kbinput;
1148 size_t kbinput_len, i;
1149 char *output;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001150
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001151 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001152
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001153 /* Read in all the verbatim characters. */
1154 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001155
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001156 /* Display all the verbatim characters at once. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001157 output = charalloc(kbinput_len + 1);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001158
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001159 for (i = 0; i < kbinput_len; i++)
1160 output[i] = (char)kbinput[i];
1161 output[i] = '\0';
1162
1163 do_output(output, kbinput_len);
1164
1165 free(output);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001166}
1167
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001168void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001169{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001170 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001171 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001172 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001173 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001174}
1175
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001176void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001177{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001178 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001179 /* Do we have to call edit_refresh(), or can we get away with
1180 * update_line()? */
1181
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +00001182 assert(current != NULL && current->data != NULL &&
1183 current_x <= strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001184
1185 placewewant = xplustabs();
1186
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001187 if (current->data[current_x] != '\0') {
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001188 int char_buf_len = parse_mbchar(current->data + current_x, NULL
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001189#ifdef NANO_WIDE
1190 , NULL
1191#endif
David Lawrence Ramseyd96851f2005-01-07 22:39:43 +00001192 , NULL);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001193 size_t line_len = strlen(current->data + current_x);
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001194
1195 assert(current_x < strlen(current->data));
1196
1197 /* Let's get dangerous. */
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001198 charmove(&current->data[current_x],
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001199 &current->data[current_x + char_buf_len],
1200 line_len - char_buf_len + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001201
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001202 null_at(&current->data, current_x + line_len - char_buf_len);
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001203#ifndef NANO_SMALL
1204 if (current_x < mark_beginx && mark_beginbuf == current)
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001205 mark_beginx -= char_buf_len;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001206#endif
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001207 totsize -= char_buf_len;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001208 } else if (current != filebot && (current->next != filebot ||
1209 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001210 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001211 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001212 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001213
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001214 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001215
1216 /* If we're deleting at the end of a line, we need to call
1217 * edit_refresh(). */
1218 if (current->data[current_x] == '\0')
1219 do_refresh = TRUE;
1220
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001221 current->data = charealloc(current->data,
1222 current_x + strlen(foo->data) + 1);
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001223 strcpy(current->data + current_x, foo->data);
1224#ifndef NANO_SMALL
1225 if (mark_beginbuf == current->next) {
1226 mark_beginx += current_x;
1227 mark_beginbuf = current;
1228 }
1229#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001230 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001231 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001232
1233 unlink_node(foo);
1234 delete_node(foo);
1235 renumber(current);
1236 totlines--;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001237 totsize--;
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001238#ifndef DISABLE_WRAPPING
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001239 wrap_reset();
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001240#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001241 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001242 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001243
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001244 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001245
1246#ifdef ENABLE_COLOR
1247 /* If color syntaxes are turned on, we need to call
1248 * edit_refresh(). */
1249 if (ISSET(COLOR_SYNTAX))
1250 do_refresh = TRUE;
1251#endif
1252
1253 if (do_refresh)
1254 edit_refresh();
1255 else
1256 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001257}
1258
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001259void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001260{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001261 char *kbinput = "\t";
1262
1263 do_output(kbinput, 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001264}
1265
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001266/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001267void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001268{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001269 filestruct *newnode = make_new_node(current);
1270 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001271
Chris Allegretta6df90f52002-07-19 01:08:59 +00001272 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001273
Chris Allegrettaff989832001-09-17 13:48:00 +00001274#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001275 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001276 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001277 /* If we are breaking the line in the indentation, the new
1278 * indentation should have only current_x characters, and
1279 * current_x should not change. */
1280 extra = indent_length(current->data);
1281 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001282 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001283 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001284 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001285#endif
1286 newnode->data = charalloc(strlen(current->data + current_x) +
1287 extra + 1);
1288 strcpy(&newnode->data[extra], current->data + current_x);
1289#ifndef NANO_SMALL
1290 if (ISSET(AUTOINDENT))
1291 strncpy(newnode->data, current->data, extra);
1292#endif
1293 null_at(&current->data, current_x);
1294#ifndef NANO_SMALL
1295 if (current == mark_beginbuf && current_x < mark_beginx) {
1296 mark_beginbuf = newnode;
1297 mark_beginx += extra - current_x;
1298 }
1299#endif
1300 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001301
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001302 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001303 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001304 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001305
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001306 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001307 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001308
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001309 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001310
1311 totlines++;
David Lawrence Ramsey4d97a582004-12-29 16:42:48 +00001312 totsize++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001313 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001314 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001315}
1316
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001317#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001318void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001319{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001320 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001321 const filestruct *old_current = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001322 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001323
Chris Allegretta6df90f52002-07-19 01:08:59 +00001324 /* Skip letters in this word first. */
1325 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001326 isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001327 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001328
Chris Allegretta6df90f52002-07-19 01:08:59 +00001329 for (; current != NULL; current = current->next) {
1330 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001331 !isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001332 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001333
Chris Allegretta6df90f52002-07-19 01:08:59 +00001334 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001335 break;
1336
Chris Allegretta6df90f52002-07-19 01:08:59 +00001337 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001338 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001339 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001340 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001341
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001342 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001343
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001344 /* Update the screen. */
1345 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001346}
1347
Chris Allegretta6df90f52002-07-19 01:08:59 +00001348/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001349void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001350{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001351 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001352 const filestruct *old_current = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001353 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001354
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001355 current_x++;
1356
Chris Allegretta6df90f52002-07-19 01:08:59 +00001357 /* Skip letters in this word first. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001358 while (current_x > 0 && isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001359 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001360
Chris Allegretta6df90f52002-07-19 01:08:59 +00001361 for (; current != NULL; current = current->prev) {
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001362 while (current_x > 0 && !isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001363 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001364
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001365 if (current_x > 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001366 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001367
Chris Allegretta6df90f52002-07-19 01:08:59 +00001368 if (current->prev != NULL)
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001369 current_x = strlen(current->prev->data) + 1;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001370 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001371
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001372 current_x--;
1373
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001374 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001375 current = fileage;
1376 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001377 } else {
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001378 while (current_x > 0 && isalnum(current->data[current_x - 1]))
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001379 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001380 }
1381
Chris Allegretta76e291b2001-10-14 19:05:10 +00001382 placewewant = xplustabs();
1383
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001384 /* Update the screen. */
1385 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001386}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001387
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001388void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001389{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001390 TOGGLE(MARK_ISSET);
1391 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001392 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001393 mark_beginbuf = current;
1394 mark_beginx = current_x;
1395 } else {
1396 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001397 edit_refresh();
1398 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001399}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001400#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001401
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001402#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001403void wrap_reset(void)
1404{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001405 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001406}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001407#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001408
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001409#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001410/* We wrap the given line. Precondition: we assume the cursor has been
1411 * moved forward since the last typed character. Return value: whether
1412 * we wrapped. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001413bool do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001414{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001415 size_t len = strlen(inptr->data);
1416 /* Length of the line we wrap. */
1417 size_t i = 0;
1418 /* Generic loop variable. */
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001419 ssize_t wrap_loc = -1;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001420 /* Index of inptr->data where we wrap. */
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001421 ssize_t word_back = -1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001422#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001423 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001424 /* Indentation to prepend to the new line. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001425 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001426#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001427 const char *after_break; /* Text after the wrap point. */
1428 size_t after_break_len; /* strlen(after_break) */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001429 bool wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001430 const char *wrap_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001431 /* The next line, minus indentation. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001432 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1433 char *newline = NULL; /* The line we create. */
1434 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001435
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001436/* There are three steps. First, we decide where to wrap. Then, we
1437 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001438
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001439/* Step 1, finding where to wrap. We are going to add a new line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001440 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001441 * location of this replacement.
1442 *
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001443 * Where should we break the line? We need the last legal wrap point
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001444 * such that the last word before it ended at or before fill. If there
1445 * is no such point, we settle for the first legal wrap point.
1446 *
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001447 * A legal wrap point is a whitespace character that is not followed by
1448 * whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001449 *
1450 * If there is no legal wrap point or we found the last character of the
1451 * line, we should return without wrapping.
1452 *
1453 * Note that the initial indentation does not count as a legal wrap
1454 * point if we are going to auto-indent!
1455 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001456 * Note that the code below could be optimized, by not calling
1457 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001458
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001459#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001460 if (ISSET(AUTOINDENT))
1461 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001462#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001463 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001464 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001465 /* Record where the last word ended. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001466 if (!is_blank_char(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001467 word_back = i;
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001468 /* If we have found a legal wrap point and the current word
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001469 * extends too far, then we stop. */
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +00001470 if (wrap_loc != -1 &&
1471 strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001472 break;
David Lawrence Ramseyb5a7a5a2004-11-23 03:42:43 +00001473 /* We record the latest legal wrap point. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001474 if (word_back != i && !is_blank_char(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001475 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001476 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001477 if (i == len)
1478 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001479
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001480 /* Step 2, making the new wrap line. It will consist of indentation
1481 * + after_break + " " + wrap_line (although indentation and
1482 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001483
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001484 /* after_break is the text that will be moved to the next line. */
1485 after_break = inptr->data + wrap_loc + 1;
1486 after_break_len = len - wrap_loc - 1;
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00001487
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001488 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001489
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001490 /* new_line_len will later be increased by the lengths of indentation
1491 * and wrap_line. */
1492 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001493
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001494 /* We prepend the wrapped text to the next line, if the flag is set,
1495 * and there is a next line, and prepending would not make the line
1496 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001497 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001498 wrap_line = inptr->next->data;
1499 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001500
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001501 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001502 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001503 wrapping = TRUE;
David Lawrence Ramsey45641702004-12-18 20:29:42 +00001504 new_line_len += 1 + wrap_line_len;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001505 }
1506 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001507
Chris Allegrettaff989832001-09-17 13:48:00 +00001508#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001509 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001510 /* Indentation comes from the next line if wrapping, else from
1511 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001512 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001513 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001514 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001515 /* The wrap_line text should not duplicate indentation.
1516 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001517 wrap_line += indent_len;
1518 else
1519 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001520 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001521#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001522
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001523 /* Now we allocate the new line and copy into it. */
1524 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001525 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001526 *newline = '\0';
1527
1528#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001529 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001530 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001531 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001532 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001533 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001534#endif
1535 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001536 new_line_len += after_break_len;
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00001537
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001538 /* We end the old line after wrap_loc. Note that this does not eat
1539 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001540 null_at(&inptr->data, wrap_loc + 1);
1541 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001542 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001543 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001544 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001545 * in a tab or a space, we don't add a space and decrement
1546 * totsize to account for that. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001547 if (!is_blank_char(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001548 strcat(newline, " ");
1549 else
1550 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001551 strcat(newline, wrap_line);
1552 free(inptr->next->data);
1553 inptr->next->data = newline;
1554 } else {
1555 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001556
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001557 /* In this case, the file size changes by +1 for the new line,
1558 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001559#ifndef NANO_SMALL
1560 totsize += indent_len;
1561#endif
1562 totlines++;
1563 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001564 temp->prev = inptr;
1565 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001566 temp->prev->next = temp;
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00001567
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001568 /* If temp->next is NULL, then temp is the last line of the
1569 * file, so we must set filebot. */
1570 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001571 temp->next->prev = temp;
1572 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001573 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001574 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001575
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001576 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1577 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001578
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001579 /* Later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001580 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001581
1582 /* Each line knows its line number. We recalculate these if we
1583 * inserted a new line. */
1584 if (!wrapping)
1585 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001586
Chris Allegretta6df90f52002-07-19 01:08:59 +00001587 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001588 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001589 current = current->next;
1590 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001591#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001592 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001593#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001594 wrap_loc + 1;
1595 wrap_reset();
1596 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001597 }
1598
Chris Allegretta6df90f52002-07-19 01:08:59 +00001599#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001600 /* If the mark was on this line after the wrap point, we move it
1601 * down. If it was on the next line and we wrapped, we move it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001602 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001603 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1604 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001605 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001606 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001607 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001608#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001609
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001610 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001611}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001612#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001613
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001614#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001615/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001616 * return FALSE if the user cancels. */
1617bool do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001618{
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001619 char *save_search, *save_replace;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001620 size_t current_x_save = current_x, pww_save = placewewant;
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001621 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001622 /* Save where we are. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001623 bool canceled = FALSE;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001624 /* The return value. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001625 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001626#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001627 bool reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001628#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001629#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001630 bool regexp_set = ISSET(USE_REGEXP);
1631#endif
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001632#ifndef NANO_SMALL
1633 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001634 bool added_magicline = FALSE;
1635 /* Whether we added a magicline after filebot. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001636 bool right_side_up = FALSE;
1637 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
1638 * FALSE if (current, current_x) is. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001639 filestruct *top, *bot;
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001640 size_t top_x, bot_x;
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001641#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001642
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001643 /* Make sure spell-check is case sensitive. */
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001644 SET(CASE_SENSITIVE);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001645
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001646#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001647 /* Make sure spell-check goes forward only. */
1648 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001649#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001650#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001651 /* Make sure spell-check doesn't use regular expressions. */
1652 UNSET(USE_REGEXP);
1653#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001654
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001655 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001656 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001657 save_search = last_search;
1658 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001659
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001660 /* Set the search/replace strings to the misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001661 last_search = mallocstrcpy(NULL, word);
1662 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001663
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001664#ifndef NANO_SMALL
1665 if (old_mark_set) {
David Lawrence Ramseyf978f042004-11-04 16:45:48 +00001666 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001667 * contains only the marked text, keep track of whether the text
1668 * will have a magicline added when we're done correcting
1669 * misspelled words, and turn the mark off. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001670 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001671 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001672 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001673 added_magicline = (filebot->data[0] != '\0');
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001674 UNSET(MARK_ISSET);
1675 }
1676#endif
1677
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001678 /* Start from the top of the file. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001679 edittop = fileage;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001680 current = fileage;
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001681 current_x = (size_t)-1;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001682 placewewant = 0;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001683
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001684 /* Find the first whole-word occurrence of word. */
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +00001685 findnextstr_wrap_reset();
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +00001686 while (findnextstr(TRUE, TRUE, FALSE, fileage, 0, word, NULL)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001687 if (is_whole_word(current_x, current->data, word)) {
1688 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001689
Chris Allegretta6df90f52002-07-19 01:08:59 +00001690 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001691
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +00001692 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001693 canceled = (statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001694#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001695 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001696#endif
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001697 _("Edit a replacement")) == -1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001698
Chris Allegretta6df90f52002-07-19 01:08:59 +00001699 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001700
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001701 if (!canceled && strcmp(word, answer) != 0) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001702 current_x--;
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001703 do_replace_loop(word, current, &current_x, TRUE,
1704 &canceled);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001705 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001706
1707 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001708 }
David Lawrence Ramsey53752e82004-10-18 22:19:22 +00001709 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001710
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001711#ifndef NANO_SMALL
1712 if (old_mark_set) {
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00001713 /* If the mark was on and we added a magicline, remove it
1714 * now. */
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001715 if (added_magicline)
1716 remove_magicline();
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001717
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001718 /* Put the beginning and the end of the mark at the beginning
1719 * and the end of the spell-checked text. */
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001720 if (fileage == filebot)
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001721 bot_x += top_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001722 if (right_side_up) {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001723 mark_beginx = top_x;
1724 current_x_save = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001725 } else {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001726 current_x_save = top_x;
1727 mark_beginx = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001728 }
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001729
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00001730 /* Unpartition the filestruct so that it contains all the text
1731 * again, and turn the mark back on. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00001732 unpartition_filestruct(&filepart);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001733 SET(MARK_ISSET);
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001734 }
1735#endif
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001736
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001737 /* Restore the search/replace strings. */
1738 free(last_search);
1739 last_search = save_search;
1740 free(last_replace);
1741 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001742
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001743 /* Restore where we were. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001744 edittop = edittop_save;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001745 current = current_save;
1746 current_x = current_x_save;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001747 placewewant = pww_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001748
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001749 /* Restore case sensitivity setting. */
1750 if (!case_sens_set)
1751 UNSET(CASE_SENSITIVE);
1752
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001753#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001754 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001755 if (reverse_search_set)
1756 SET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001757#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001758#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001759 /* Restore regular expression usage setting. */
1760 if (regexp_set)
1761 SET(USE_REGEXP);
1762#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001763
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001764 return !canceled;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001765}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001766
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001767/* Integrated spell checking using 'spell' program. Return value: NULL
1768 * for normal termination, otherwise the error string. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001769const char *do_int_speller(const char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001770{
Chris Allegretta271e9722000-11-10 18:15:43 +00001771 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001772 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001773 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001774 pid_t pid_spell, pid_sort, pid_uniq;
1775 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001776
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001777 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001778 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1779 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001780
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001781 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001782
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001783 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001784 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001785
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001786 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001787
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001788 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001789
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001790 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001791 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1792 goto close_pipes_and_exit;
1793
1794 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1795 goto close_pipes_and_exit;
1796
Chris Allegretta271e9722000-11-10 18:15:43 +00001797 close(tempfile_fd);
1798
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001799 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001800 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1801 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001802
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001803 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001804
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001805 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001806 execlp("spell", "spell", NULL);
1807
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001808 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001809 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001810 }
1811
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001812 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001813 close(spell_fd[1]);
1814
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001815 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001816 if ((pid_sort = fork()) == 0) {
1817
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001818 /* Child continues (i.e, future spell process). Replace the
1819 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001820 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1821 goto close_pipes_and_exit;
1822
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001823 close(spell_fd[0]);
1824
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001825 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001826 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1827 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001828
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001829 close(sort_fd[1]);
1830
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001831 /* Start sort program. Use -f to remove mixed case without
1832 * having to have ANOTHER pipe for tr. If this isn't portable,
1833 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001834 execlp("sort", "sort", "-f", NULL);
1835
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001836 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001837 exit(1);
1838 }
1839
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001840 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001841 close(sort_fd[1]);
1842
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001843 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001844 if ((pid_uniq = fork()) == 0) {
1845
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001846 /* Child continues (i.e, future uniq process). Replace the
1847 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001848 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1849 goto close_pipes_and_exit;
1850
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001851 close(sort_fd[0]);
1852
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001853 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001854 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1855 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001856
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001857 close(uniq_fd[1]);
1858
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001859 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001860 execlp("uniq", "uniq", NULL);
1861
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001862 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001863 exit(1);
1864 }
1865
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001866 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001867 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001868
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001869 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001870 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1871 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001872 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001873 }
1874
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001875 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001876 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1877 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001878 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001879 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001880
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001881 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001882 read_buff_read = 0;
1883 read_buff_size = pipe_buff_size + 1;
1884 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001885
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001886 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001887 read_buff_read += bytesread;
1888 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001889 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001890 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001891
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001892 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001893
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001894 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001895 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001896
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001897 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001898 read_buff_word = read_buff_ptr = read_buff;
1899
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001900 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001901
1902 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001903 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001904 if (read_buff_word != read_buff_ptr) {
1905 if (!do_int_spell_fix(read_buff_word)) {
1906 read_buff_word = read_buff_ptr;
1907 break;
1908 }
1909 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001910 read_buff_word = read_buff_ptr + 1;
1911 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001912 read_buff_ptr++;
1913 }
1914
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001915 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001916 if (read_buff_word != read_buff_ptr)
1917 do_int_spell_fix(read_buff_word);
1918
Chris Allegretta271e9722000-11-10 18:15:43 +00001919 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001920 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001921 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001922
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001923 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001924 waitpid(pid_spell, &spell_status, 0);
1925 waitpid(pid_sort, &sort_status, 0);
1926 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001927
Chris Allegretta334a9402002-12-16 04:25:53 +00001928 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1929 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001930
Chris Allegretta334a9402002-12-16 04:25:53 +00001931 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1932 return _("Error invoking \"sort -f\"");
1933
1934 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1935 return _("Error invoking \"uniq\"");
1936
1937 /* Otherwise... */
1938 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001939
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001940 close_pipes_and_exit:
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001941 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001942 close(tempfile_fd);
1943 close(spell_fd[0]);
1944 close(spell_fd[1]);
1945 close(sort_fd[0]);
1946 close(sort_fd[1]);
1947 close(uniq_fd[0]);
1948 close(uniq_fd[1]);
1949 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001950}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001951
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001952/* External spell checking. Return value: NULL for normal termination,
1953 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001954const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001955{
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001956 int alt_spell_status, lineno_save = current->lineno;
1957 size_t current_x_save = current_x, pww_save = placewewant;
1958 int current_y_save = current_y;
Chris Allegretta271e9722000-11-10 18:15:43 +00001959 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001960 char *ptr;
1961 static int arglen = 3;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001962 static char **spellargs = NULL;
1963 FILE *f;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001964#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001965 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001966 bool added_magicline = FALSE;
1967 /* Whether we added a magicline after filebot. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001968 bool right_side_up = FALSE;
1969 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
1970 * FALSE if (current, current_x) is. */
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001971 filestruct *top, *bot;
1972 size_t top_x, bot_x;
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001973 int mbb_lineno_save = 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001974 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001975 * the alternate spell command. The line that mark_beginbuf
1976 * points to will be freed, so we save the line number and
1977 * restore afterwards. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001978 long old_totsize = totsize;
1979 /* Our saved value of totsize, used when we spell-check a marked
1980 * selection. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001981
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001982 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001983 /* If the mark is on, save the number of the line it starts on,
1984 * and then turn the mark off. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001985 mbb_lineno_save = mark_beginbuf->lineno;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001986 UNSET(MARK_ISSET);
1987 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001988#endif
1989
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001990 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001991
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001992 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001993 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001994 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001995
Chris Allegrettae434b452001-01-27 19:25:00 +00001996 spellargs[0] = strtok(alt_speller, " ");
1997 while ((ptr = strtok(NULL, " ")) != NULL) {
1998 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001999 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00002000 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00002001 }
Chris Allegrettae434b452001-01-27 19:25:00 +00002002 spellargs[arglen - 1] = NULL;
2003 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002004 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00002005
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002006 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002007 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002008 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00002009 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00002010
2011 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00002012 exit(1);
2013 }
2014
2015 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00002016 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00002017 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00002018
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002019 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00002020 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002021
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00002022 if (!WIFEXITED(alt_spell_status) ||
2023 WEXITSTATUS(alt_spell_status) != 0) {
Chris Allegretta334a9402002-12-16 04:25:53 +00002024 char *altspell_error = NULL;
2025 char *invoke_error = _("Could not invoke \"%s\"");
David Lawrence Ramseyf3bea022004-12-20 01:18:49 +00002026 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
Chris Allegretta334a9402002-12-16 04:25:53 +00002027
2028 altspell_error = charalloc(msglen);
2029 snprintf(altspell_error, msglen, invoke_error, alt_speller);
2030 return altspell_error;
2031 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002032
Chris Allegretta8f6c0692000-07-19 01:16:18 +00002033 refresh();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002034
David Lawrence Ramsey439fbe32004-10-16 04:56:34 +00002035 /* Restore the terminal to its previous state. */
2036 terminal_init();
2037
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002038#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002039 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002040 long part_totsize;
2041
2042 /* If the mark was on, partition the filestruct so that it
2043 * contains only the marked text, and keep track of whether the
2044 * temp file (which should contain the spell-checked marked
2045 * text) will have a magicline added when it's reloaded. */
2046 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002047 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002048 filepart = partition_filestruct(top, top_x, bot, bot_x);
2049 added_magicline = (filebot->data[0] != '\0');
2050
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002051 /* Get the number of characters in the marked text, and subtract
2052 * it from the saved value of totsize. Note that we don't need
2053 * to save totlines. */
2054 get_totals(top, bot, NULL, &part_totsize);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002055 old_totsize -= part_totsize;
2056 }
2057#endif
2058
2059 /* Reinitialize the filestruct. */
2060 free_filestruct(fileage);
2061 global_init(TRUE);
2062
2063 /* Reload the temp file. Do what load_buffer() would do, except for
2064 * making a new buffer for the temp file if multibuffer support is
2065 * available. */
2066 open_file(tempfile_name, FALSE, &f);
2067 read_file(f, tempfile_name);
2068 current = fileage;
2069
2070#ifndef NANO_SMALL
2071 if (old_mark_set) {
David Lawrence Ramsey15398372004-11-05 15:03:12 +00002072 filestruct *top_save = fileage;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002073
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00002074 /* If the mark was on and we added a magicline, remove it
2075 * now. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002076 if (added_magicline)
2077 remove_magicline();
2078
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002079 /* Put the beginning and the end of the mark at the beginning
2080 * and the end of the spell-checked text. */
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002081 if (fileage == filebot)
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002082 bot_x += top_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002083 if (right_side_up) {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002084 mark_beginx = top_x;
2085 current_x_save = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002086 } else {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002087 current_x_save = top_x;
2088 mark_beginx = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002089 }
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002090
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00002091 /* Unpartition the filestruct so that it contains all the text
2092 * again. Note that we've replaced the marked text originally
2093 * in the partition with the spell-checked marked text in the
2094 * temp file. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00002095 unpartition_filestruct(&filepart);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002096
2097 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002098 * partition. Also set totlines to the new number of lines in
2099 * the file, add the number of characters in the spell-checked
2100 * marked text to the saved value of totsize, and then make that
2101 * saved value the actual value. */
David Lawrence Ramsey15398372004-11-05 15:03:12 +00002102 renumber(top_save);
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002103 totlines = filebot->lineno;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002104 old_totsize += totsize;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002105 totsize = old_totsize;
2106
2107 /* Assign mark_beginbuf to the line where the mark began
2108 * before. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002109 do_gotopos(mbb_lineno_save, mark_beginx, current_y_save, 0);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002110 mark_beginbuf = current;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002111
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002112 /* Assign mark_beginx to the location in mark_beginbuf where the
2113 * mark began before, adjusted for any shortening of the
2114 * line. */
2115 mark_beginx = current_x;
2116
2117 /* Turn the mark back on. */
2118 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002119 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002120#endif
2121
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002122 /* Go back to the old position, mark the file as modified, and make
2123 * sure that the titlebar is refreshed. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002124 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002125 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00002126 clearok(topwin, FALSE);
2127 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002128
Chris Allegretta334a9402002-12-16 04:25:53 +00002129 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002130}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002131
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002132void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002133{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002134 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002135 char *temp = safe_tempnam(0, "nano.");
2136 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002137
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002138 if (temp == NULL) {
2139 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002140 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00002141 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002142
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002143#ifndef NANO_SMALL
2144 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002145 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002146 else
2147#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002148 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002149
2150 if (i == -1) {
David Lawrence Ramsey95e39e52004-08-12 02:52:14 +00002151 statusbar(_("Error writing temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00002152 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002153 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00002154 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002155
Chris Allegrettae1f14522001-09-19 03:19:43 +00002156#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002157 /* Update the current open_files entry before spell-checking, in
2158 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002159 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00002160#endif
2161
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002162 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
2163 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002164 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00002165 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002166
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002167 if (spell_msg != NULL)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002168 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2169 strerror(errno));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002170 else
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002171 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00002172}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002173#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002174
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002175#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00002176/* The "indentation" of a line is the whitespace between the quote part
2177 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002178size_t indent_length(const char *line)
2179{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002180 size_t len = 0;
2181
2182 assert(line != NULL);
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00002183 while (is_blank_char(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002184 line++;
2185 len++;
2186 }
2187 return len;
2188}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002189#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002190
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002191#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00002192/* justify_format() replaces Tab by Space and multiple spaces by 1
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002193 * (except it maintains 2 after a non-repeated character in punct
2194 * followed by a character in brackets). Note that the terminating \0
2195 * counts as a space.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002196 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002197 * justify_format() might make line->data shorter, and change the actual
2198 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00002199 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002200 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00002201 * skip should be at most strlen(line->data). The character at
2202 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002203void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002204{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002205 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002206
Chris Allegretta6df90f52002-07-19 01:08:59 +00002207 /* These four asserts are assumptions about the input data. */
2208 assert(line != NULL);
2209 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00002210 assert(skip < strlen(line->data));
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00002211 assert(!is_blank_char(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002212
Chris Allegretta6df90f52002-07-19 01:08:59 +00002213 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002214 for (front = back; ; front++) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002215 bool remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002216 /* Do we want to remove this space? */
2217
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002218 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002219 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002220
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00002221 /* These tests are safe since line->data + skip is not a
2222 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002223 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002224 const char *bob = back - 2;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002225
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002226 remove_space = TRUE;
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002227 for (; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002228 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002229 /* If this character is in punct, don't remove the
2230 * space unless this character and the character
2231 * before it are the same. */
2232 remove_space = (bob > line->data + skip &&
2233 *bob == *(bob - 1));
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002234 break;
2235 }
2236 if (strchr(brackets, *bob) == NULL)
2237 break;
2238 }
2239 }
2240
2241 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002242 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002243 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002244#ifndef NANO_SMALL
2245 if (mark_beginbuf == line && back - line->data < mark_beginx)
2246 mark_beginx--;
2247#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002248 if (*front == '\0')
2249 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002250 } else {
2251 *back = *front;
2252 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002253 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002254 if (*front == '\0')
2255 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002256 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002257
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002258 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00002259 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00002260
Chris Allegretta6df90f52002-07-19 01:08:59 +00002261 /* Now back is the new end of line->data. */
2262 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00002263 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002264 null_at(&line->data, back - line->data);
2265#ifndef NANO_SMALL
2266 if (mark_beginbuf == line && back - line->data < mark_beginx)
2267 mark_beginx = back - line->data;
2268#endif
2269 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002270}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002271
2272/* The "quote part" of a line is the largest initial substring matching
2273 * the quote string. This function returns the length of the quote part
2274 * of the given line.
2275 *
2276 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2277 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002278size_t quote_length(const char *line)
2279{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002280#ifdef HAVE_REGEX_H
2281 regmatch_t matches;
2282 int rc = regexec(&quotereg, line, 1, &matches, 0);
2283
2284 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
2285 return 0;
2286 /* matches.rm_so should be 0, since the quote string should start
2287 * with the caret ^. */
2288 return matches.rm_eo;
2289#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002290 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002291
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00002292 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002293 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002294 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002295 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002296#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002297}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002298
Chris Allegretta6df90f52002-07-19 01:08:59 +00002299/* a_line and b_line are lines of text. The quotation part of a_line is
2300 * the first a_quote characters. Check that the quotation part of
2301 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002302bool quotes_match(const char *a_line, size_t a_quote, const char
2303 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002304{
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00002305 /* Here is the assumption about a_quote. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002306 assert(a_quote == quote_length(a_line));
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00002307
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002308 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002309 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002310}
2311
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002312/* We assume a_line and b_line have no quote part. Then, we return
2313 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002314bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002315 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002316{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002317 assert(a_indent == indent_length(a_line));
2318 assert(b_indent == indent_length(b_line));
2319
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002320 return b_indent <= a_indent &&
2321 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002322}
2323
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002324/* Is foo the beginning of a paragraph?
2325 *
2326 * A line of text consists of a "quote part", followed by an
2327 * "indentation part", followed by text. The functions quote_length()
2328 * and indent_length() calculate these parts.
2329 *
2330 * A line is "part of a paragraph" if it has a part not in the quote
2331 * part or the indentation.
2332 *
2333 * A line is "the beginning of a paragraph" if it is part of a
2334 * paragraph and
2335 * 1) it is the top line of the file, or
2336 * 2) the line above it is not part of a paragraph, or
2337 * 3) the line above it does not have precisely the same quote
2338 * part, or
2339 * 4) the indentation of this line is not an initial substring of
2340 * the indentation of the previous line, or
2341 * 5) this line has no quote part and some indentation, and
2342 * AUTOINDENT is not set.
2343 * The reason for number 5) is that if AUTOINDENT is not set, then an
2344 * indented line is expected to start a paragraph, like in books.
2345 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2346 * turned on. */
2347bool begpar(const filestruct *const foo)
2348{
2349 size_t quote_len;
2350 size_t indent_len;
2351 size_t temp_id_len;
2352
2353 /* Case 1). */
2354 if (foo->prev == NULL)
2355 return TRUE;
2356
2357 quote_len = quote_length(foo->data);
2358 indent_len = indent_length(foo->data + quote_len);
2359
2360 /* Not part of a paragraph. */
2361 if (foo->data[quote_len + indent_len] == '\0')
2362 return FALSE;
2363
2364 /* Case 3). */
2365 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2366 return TRUE;
2367
2368 temp_id_len = indent_length(foo->prev->data + quote_len);
2369
2370 /* Case 2) or 5) or 4). */
2371 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2372 (quote_len == 0 && indent_len > 0
2373#ifndef NANO_SMALL
2374 && !ISSET(AUTOINDENT)
2375#endif
2376 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2377 foo->data + quote_len, indent_len))
2378 return TRUE;
2379
2380 return FALSE;
2381}
2382
2383/* We find the last beginning-of-paragraph line before the current
2384 * line. */
2385void do_para_begin(void)
2386{
David Lawrence Ramsey52e5f232005-01-14 21:26:38 +00002387 const filestruct *current_save = current;
2388 const size_t pww_save = placewewant;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002389
2390 current_x = 0;
2391 placewewant = 0;
2392
2393 if (current->prev != NULL) {
2394 do {
2395 current = current->prev;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002396 current_y--;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002397 } while (!begpar(current));
2398 }
2399
David Lawrence Ramsey52e5f232005-01-14 21:26:38 +00002400 edit_redraw(current_save, pww_save);
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002401}
2402
2403bool inpar(const char *str)
2404{
2405 size_t quote_len = quote_length(str);
2406
2407 return str[quote_len + indent_length(str + quote_len)] != '\0';
2408}
2409
2410/* A line is the last line of a paragraph if it is in a paragraph, and
2411 * the next line isn't, or is the beginning of a paragraph. We move
2412 * down to the end of a paragraph, then one line farther. */
2413void do_para_end(void)
2414{
David Lawrence Ramsey52e5f232005-01-14 21:26:38 +00002415 const filestruct *const current_save = current;
2416 const size_t pww_save = placewewant;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002417
2418 current_x = 0;
2419 placewewant = 0;
2420
2421 while (current->next != NULL && !inpar(current->data))
2422 current = current->next;
2423
2424 while (current->next != NULL && inpar(current->next->data) &&
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002425 !begpar(current->next)) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002426 current = current->next;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002427 current_y++;
2428 }
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002429
2430 if (current->next != NULL)
2431 current = current->next;
2432
David Lawrence Ramsey52e5f232005-01-14 21:26:38 +00002433 edit_redraw(current_save, pww_save);
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002434}
2435
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002436/* Put the next par_len lines, starting with first_line, into the
2437 * justify buffer, leaving copies of those lines in place. Assume there
2438 * are enough lines after first_line. Return the new copy of
2439 * first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002440filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2441 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002442{
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002443 filestruct *top = first_line;
2444 /* The top of the paragraph we're backing up. */
2445 filestruct *bot = first_line;
2446 /* The bottom of the paragraph we're backing up. */
2447 size_t i;
2448 /* Generic loop variable. */
2449 size_t current_x_save = current_x;
2450 int fl_lineno_save = first_line->lineno;
2451 int edittop_lineno_save = edittop->lineno;
2452 int current_lineno_save = current->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002453#ifndef NANO_SMALL
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002454 bool old_mark_set = ISSET(MARK_ISSET);
2455 int mbb_lineno_save = 0;
2456
2457 if (old_mark_set)
2458 mbb_lineno_save = mark_beginbuf->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002459#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002460
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002461 /* Move bot down par_len lines to the newline after the last line of
2462 * the paragraph. */
2463 for (i = par_len; i > 0; i--)
2464 bot = bot->next;
2465
2466 /* Move the paragraph from the main filestruct to the justify
2467 * buffer. */
2468 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot, 0);
2469
2470 /* Copy the paragraph from the justify buffer to the main
2471 * filestruct. */
2472 copy_from_filestruct(jusbuffer, jusbottom);
2473
2474 /* Move upward from the last line of the paragraph to the first
2475 * line, putting first_line, edittop, current, and mark_beginbuf at
2476 * the same lines in the copied paragraph that they had in the
2477 * original paragraph. */
2478 top = current->prev;
2479 for (i = par_len; i > 0; i--) {
2480 if (top->lineno == fl_lineno_save)
2481 first_line = top;
2482 if (top->lineno == edittop_lineno_save)
2483 edittop = top;
2484 if (top->lineno == current_lineno_save)
2485 current = top;
2486#ifndef NANO_SMALL
2487 if (old_mark_set && top->lineno == mbb_lineno_save)
2488 mark_beginbuf = top;
2489#endif
2490 top = top->prev;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002491 }
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002492
2493 /* Put current_x at the same place in the copied paragraph that it
2494 * had in the original paragraph. */
2495 current_x = current_x_save;
2496
2497 set_modified();
2498
Chris Allegretta6df90f52002-07-19 01:08:59 +00002499 return first_line;
2500}
2501
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002502/* Is it possible to break line at or before goal? */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002503bool breakable(const char *line, ssize_t goal)
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002504{
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002505 while (*line != '\0' && goal >= 0) {
2506 size_t pos = 0;
2507
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00002508 if (is_blank_char(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002509 return TRUE;
2510
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00002511 line += parse_mbchar(line, NULL
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002512#ifdef NANO_WIDE
2513 , NULL
2514#endif
David Lawrence Ramseyd96851f2005-01-07 22:39:43 +00002515 , &pos);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002516
2517 goal -= pos;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002518 }
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002519
Chris Allegretta428f6202003-02-12 03:21:45 +00002520 /* If goal is not negative, the whole line (one word) was short
2521 * enough. */
David Lawrence Ramsey12054fe2005-01-07 22:37:01 +00002522 return (goal >= 0);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002523}
2524
Chris Allegretta6df90f52002-07-19 01:08:59 +00002525/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002526 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002527 * such space, and force is TRUE, then we find the first space. Anyway,
2528 * we then take the last space in that group of spaces. The terminating
2529 * '\0' counts as a space. */
David Lawrence Ramseyfc54d6e2004-12-02 17:37:09 +00002530ssize_t break_line(const char *line, ssize_t goal, bool force)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002531{
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002532 ssize_t space_loc = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002533 /* Current tentative return value. Index of the last space we
2534 * found with short enough display width. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002535 ssize_t cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002536 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002537
2538 assert(line != NULL);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002539
2540 while (*line != '\0' && goal >= 0) {
2541 size_t pos = 0;
2542 int line_len;
2543
Chris Allegretta6df90f52002-07-19 01:08:59 +00002544 if (*line == ' ')
2545 space_loc = cur_loc;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002546
Chris Allegretta6df90f52002-07-19 01:08:59 +00002547 assert(*line != '\t');
2548
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00002549 line_len = parse_mbchar(line, NULL
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002550#ifdef NANO_WIDE
2551 , NULL
2552#endif
David Lawrence Ramseyd96851f2005-01-07 22:39:43 +00002553 , &pos);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002554
2555 goal -= pos;
2556 line += line_len;
2557 cur_loc += line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002558 }
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002559
Chris Allegretta6df90f52002-07-19 01:08:59 +00002560 if (goal >= 0)
2561 /* In fact, the whole line displays shorter than goal. */
2562 return cur_loc;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002563
Chris Allegretta6df90f52002-07-19 01:08:59 +00002564 if (space_loc == -1) {
2565 /* No space found short enough. */
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002566 if (force) {
2567 for (; *line != '\0'; line++, cur_loc++) {
2568 if (*line == ' ' && *(line + 1) != ' ' &&
2569 *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002570 return cur_loc;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002571 }
2572 return -1;
2573 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002574 }
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002575
Chris Allegretta6df90f52002-07-19 01:08:59 +00002576 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002577 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002578 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2579 *(line - cur_loc + space_loc + 1) == '\0')
2580 space_loc++;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00002581
Chris Allegretta6df90f52002-07-19 01:08:59 +00002582 return space_loc;
2583}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002584
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002585/* Find the beginning of the current paragraph if we're in one, or the
2586 * beginning of the next paragraph if we're not. Afterwards, save the
2587 * quote length and paragraph length in *quote and *par. Return FALSE
2588 * if we found a paragraph, or TRUE if there was an error or we didn't
2589 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002590 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002591 * See the comment at begpar() for more about when a line is the
2592 * beginning of a paragraph. */
2593bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002594{
2595 size_t quote_len;
2596 /* Length of the initial quotation of the paragraph we
2597 * search. */
2598 size_t par_len;
2599 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002600 size_t indent_len;
2601 /* Generic indentation length. */
2602 filestruct *line;
2603 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002604
2605#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002606 if (quoterc != 0) {
2607 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2608 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002609 }
2610#endif
2611
2612 /* Here is an assumption that is always true anyway. */
2613 assert(current != NULL);
2614
2615 current_x = 0;
2616
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002617 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002618 indent_len = indent_length(current->data + quote_len);
2619
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002620 /* Here we find the first line of the paragraph to search. If the
2621 * current line is in a paragraph, then we move back to the first
2622 * line of the paragraph. Otherwise, we move to the first line that
2623 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002624 if (current->data[quote_len + indent_len] != '\0') {
2625 /* This line is part of a paragraph. So we must search back to
2626 * the first line of this paragraph. First we check items 1)
2627 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002628 while (current->prev != NULL && quotes_match(current->data,
2629 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002630 size_t temp_id_len =
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00002631 indent_length(current->prev->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002632 /* The indentation length of the previous line. */
2633
2634 /* Is this line the beginning of a paragraph, according to
2635 * items 2), 5), or 4) above? If so, stop. */
2636 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002637 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002638#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002639 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002640#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002641 ) || !indents_match(current->prev->data + quote_len,
2642 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002643 break;
2644 indent_len = temp_id_len;
2645 current = current->prev;
2646 current_y--;
2647 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002648 } else {
2649 /* This line is not part of a paragraph. Move down until we get
2650 * to a non "blank" line. */
2651 do {
2652 /* There is no next paragraph, so nothing to move to. */
2653 if (current->next == NULL) {
2654 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002655 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002656 }
2657 current = current->next;
2658 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002659 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002660 indent_len = indent_length(current->data + quote_len);
2661 } while (current->data[quote_len + indent_len] == '\0');
2662 }
2663
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002664 /* Now current is the first line of the paragraph, and quote_len is
2665 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002666
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002667 /* Next step, compute par_len, the number of lines in this
2668 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002669 line = current;
2670 par_len = 1;
2671 indent_len = indent_length(line->data + quote_len);
2672
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002673 while (line->next != NULL &&
2674 quotes_match(current->data, quote_len, line->next->data)) {
2675 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002676
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002677 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002678 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002679 line->next->data[quote_len + temp_id_len] == '\0' ||
2680 (quote_len == 0 && temp_id_len > 0
2681#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002682 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002683#endif
2684 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002685 break;
2686 indent_len = temp_id_len;
2687 line = line->next;
2688 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002689 }
2690
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002691 /* Now par_len is the number of lines in this paragraph. We should
2692 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002693
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002694 /* Save the values of quote_len and par_len. */
2695 assert(quote != NULL && par != NULL);
2696 *quote = quote_len;
2697 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002698
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002699 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002700}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002701
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002702/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2703 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002704void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002705{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002706 filestruct *first_par_line = NULL;
2707 /* Will be the first line of the resulting justified paragraph.
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002708 * For restoring after unjustify. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002709 filestruct *last_par_line;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002710 /* Will be the line containing the newline after the last line
2711 * of the result. Also for restoring after unjustify. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002712 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002713 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002714 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002715 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002716
2717 /* We save these global variables to be restored if the user
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002718 * unjustifies. Note that we don't need to save totlines. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00002719 size_t current_x_save = current_x;
2720 int current_y_save = current_y;
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002721 long flags_save = flags, totsize_save = totsize;
2722 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002723#ifndef NANO_SMALL
2724 filestruct *mark_beginbuf_save = mark_beginbuf;
David Lawrence Ramsey687776b2004-10-30 01:16:08 +00002725 size_t mark_beginx_save = mark_beginx;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002726#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002727 int kbinput;
David Lawrence Ramseycac02932005-01-11 23:05:05 +00002728 bool meta_key, func_key, s_or_t, ran_func, finished;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002729
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002730 /* If we're justifying the entire file, start at the beginning. */
2731 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002732 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002733
2734 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002735
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002736 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002737 size_t quote_len;
2738 /* Length of the initial quotation of the paragraph we
2739 * justify. */
2740 size_t par_len;
2741 /* Number of lines in that paragraph. */
2742
2743 /* Find the first line of the paragraph to be justified. That
2744 * is the start of this paragraph if we're in one, or the start
2745 * of the next otherwise. Save the quote length and paragraph
David Lawrence Ramsey68ebb612004-12-04 17:36:14 +00002746 * length (number of lines). Don't refresh the screen yet,
2747 * since we'll do that after we justify. If the search
2748 * failed, we're justifying the whole file, and the search
2749 * didn't leave us on the last line of the file, set the last
2750 * line of the text to be justified to the last line of the file
2751 * and break out of the loop. Otherwise, refresh the screen and
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002752 * get out. */
2753 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey3e819142004-12-31 04:10:28 +00002754 if (full_justify && first_par_line != filebot) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002755 last_par_line = filebot;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002756 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002757 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002758 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002759 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002760 }
2761 }
2762
2763 /* Next step, we loop through the lines of this paragraph,
2764 * justifying each one individually. */
2765 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002766 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002767 size_t line_len;
2768 size_t display_len;
2769 /* The width of current in screen columns. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002770 ssize_t break_pos;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002771 /* Where we will break the line. */
2772
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002773 /* We'll be moving to the next line after justifying the
2774 * current line in almost all cases, so allow changing the
2775 * spacing at the ends of justified lines by default. */
2776 allow_respacing = TRUE;
2777
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002778 indent_len = quote_len + indent_length(current->data +
2779 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002780
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002781 /* If we haven't already done it, copy the original
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002782 * paragraph to the justify buffer. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002783 if (first_par_line == NULL)
2784 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey6b769e52004-11-17 16:59:34 +00002785 filebot->lineno - current->lineno : par_len,
2786 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002787
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002788 /* Now we call justify_format() on the current line of the
2789 * paragraph, which will remove excess spaces from it and
2790 * change tabs to spaces. */
2791 justify_format(current, quote_len +
2792 indent_length(current->data + quote_len));
2793
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002794 line_len = strlen(current->data);
2795 display_len = strlenpt(current->data);
2796
2797 if (display_len > fill) {
2798 /* The line is too long. Try to wrap it to the next. */
2799 break_pos = break_line(current->data + indent_len,
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002800 fill - strnlenpt(current->data, indent_len),
2801 TRUE);
David Lawrence Ramseyabc94232004-12-08 23:24:31 +00002802 if (break_pos == -1 ||
2803 break_pos + indent_len == line_len)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002804 /* We can't break the line, or don't need to, so
2805 * just go on to the next. */
2806 goto continue_loc;
2807 break_pos += indent_len;
2808 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002809 if (par_len == 1) {
2810 /* There is no next line in this paragraph. We make
2811 * a new line and copy text after break_pos into
2812 * it. */
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002813 splice_node(current, make_new_node(current),
2814 current->next);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002815 /* In a non-quoted paragraph, we copy the indent
2816 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002817 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002818#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002819 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002820#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002821 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002822 indent_len = 0;
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002823 current->next->data = charalloc(indent_len +
2824 line_len - break_pos);
2825 strncpy(current->next->data, current->data,
2826 indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002827 strcpy(current->next->data + indent_len,
2828 current->data + break_pos + 1);
2829 assert(strlen(current->next->data) ==
2830 indent_len + line_len - break_pos - 1);
2831 totlines++;
2832 totsize += indent_len;
2833 par_len++;
2834 } else {
2835 size_t next_line_len = strlen(current->next->data);
2836
2837 indent_len = quote_len +
2838 indent_length(current->next->data + quote_len);
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002839 current->next->data =
2840 charealloc(current->next->data, next_line_len +
2841 line_len - break_pos + 1);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002842
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002843 charmove(current->next->data + indent_len +
2844 line_len - break_pos, current->next->data +
2845 indent_len, next_line_len - indent_len + 1);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002846 strcpy(current->next->data + indent_len,
2847 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002848 current->next->data[indent_len + line_len -
2849 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002850#ifndef NANO_SMALL
2851 if (mark_beginbuf == current->next) {
2852 if (mark_beginx < indent_len)
2853 mark_beginx = indent_len;
2854 mark_beginx += line_len - break_pos;
2855 }
2856#endif
2857 }
2858#ifndef NANO_SMALL
David Lawrence Ramsey40a6c8c2004-11-27 21:10:11 +00002859 if (mark_beginbuf == current &&
2860 mark_beginx > break_pos) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002861 mark_beginbuf = current->next;
2862 mark_beginx -= break_pos + 1 - indent_len;
2863 }
2864#endif
2865 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002866
2867 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002868 current = current->next;
2869 } else if (display_len < fill && par_len > 1) {
2870 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002871
2872 indent_len = quote_len +
2873 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002874 /* If we can't pull a word from the next line up to this
2875 * one, just go on. */
2876 if (!breakable(current->next->data + indent_len,
2877 fill - display_len - 1))
2878 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002879
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002880 break_pos = break_line(current->next->data + indent_len,
2881 fill - display_len - 1, FALSE);
2882 assert(break_pos != -1);
2883
2884 current->data = charealloc(current->data,
2885 line_len + break_pos + 2);
2886 current->data[line_len] = ' ';
2887 strncpy(current->data + line_len + 1,
2888 current->next->data + indent_len, break_pos);
2889 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002890#ifndef NANO_SMALL
2891 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002892 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002893 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002894 if (mark_beginx <= indent_len)
2895 mark_beginx = line_len + 1;
2896 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002897 mark_beginx = line_len + 1 + mark_beginx -
2898 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002899 } else
2900 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002901 }
2902#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002903 next_line_len = strlen(current->next->data);
2904 if (indent_len + break_pos == next_line_len) {
2905 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002906
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002907 /* Don't destroy edittop! */
2908 if (line == edittop)
2909 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002910
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002911 unlink_node(line);
2912 delete_node(line);
2913 totlines--;
2914 totsize -= indent_len;
2915 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002916
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002917 /* Don't go to the next line. Accordingly, don't
2918 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002919 * previous justified line, so that we don't end up
2920 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002921 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002922 } else {
2923 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002924 current->next->data + indent_len + break_pos + 1,
2925 next_line_len - break_pos - indent_len);
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002926 null_at(&current->next->data, next_line_len -
2927 break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002928
2929 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002930 current = current->next;
2931 }
2932 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002933 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002934 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002935 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002936
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002937 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002938 * current line. If the justified line was not the last
2939 * line of the paragraph, add a space to the end of it to
2940 * replace the one removed or left out by justify_format().
2941 * If it was the last line of the paragraph, and
2942 * justify_format() left a space on the end of it, remove
2943 * the space. */
2944 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002945 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002946
2947 if (par_len > 1) {
2948 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002949 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002950 current->prev->data[prev_line_len] = ' ';
2951 current->prev->data[prev_line_len + 1] = '\0';
2952 totsize++;
2953 } else if (par_len == 1 &&
2954 current->prev->data[prev_line_len - 1] == ' ') {
David Lawrence Ramsey6e738ac2004-11-23 22:30:32 +00002955 current->prev->data =
2956 charealloc(current->prev->data, prev_line_len);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002957 current->prev->data[prev_line_len - 1] = '\0';
2958 totsize--;
2959 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002960 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002961 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002962
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002963 /* We've just justified a paragraph. If we're not justifying the
2964 * entire file, break out of the loop. Otherwise, continue the
2965 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002966 if (!full_justify)
2967 break;
2968
2969 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002970
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002971 /* We are now done justifying the paragraph or the file, so clean
2972 * up. totlines, totsize, and current_y have been maintained above.
2973 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002974 * fileage, and renumber() since edit_refresh() needs the line
2975 * numbers to be right (but only do the last two if we actually
2976 * justified something). */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002977 last_par_line = current;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002978 if (first_par_line != NULL) {
2979 if (first_par_line->prev == NULL)
2980 fileage = first_par_line;
2981 renumber(first_par_line);
2982 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002983
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002984 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002985
Chris Allegretta9149e612000-11-27 00:23:41 +00002986 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002987
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002988 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002989 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002990 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002991
David Lawrence Ramsey63e73cb2004-11-28 04:52:57 +00002992 /* Now get a keystroke and see if it's unjustify. If not, put back
2993 * the keystroke and return. */
David Lawrence Ramseycac02932005-01-11 23:05:05 +00002994 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
2995 &finished, FALSE);
Chris Allegretta5f071802001-05-06 02:34:31 +00002996
David Lawrence Ramsey74835712004-12-04 17:41:52 +00002997 if (!meta_key && !func_key && s_or_t &&
2998 kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002999 /* Restore the justify we just did (ungrateful user!). */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003000 current = current_save;
3001 current_x = current_x_save;
3002 current_y = current_y_save;
3003 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00003004
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003005 /* Splice the justify buffer back into the file, but only if we
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00003006 * actually justified something. */
3007 if (first_par_line != NULL) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003008 filestruct *bot_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003009
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003010 /* Partition the filestruct so that it contains only the
3011 * text of the justified paragraph. */
3012 filepart = partition_filestruct(first_par_line, 0,
3013 last_par_line, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00003014
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003015 /* Remove the text of the justified paragraph, and
3016 * put the text in the justify buffer in its place. */
3017 free_filestruct(fileage);
3018 fileage = jusbuffer;
3019 filebot = jusbottom;
3020
3021 bot_save = filebot;
3022
3023 /* Unpartition the filestruct so that it contains all the
3024 * text again. Note that the justified paragraph has been
3025 * replaced with the unjustified paragraph. */
3026 unpartition_filestruct(&filepart);
3027
3028 /* Renumber starting with the ending line of the old
3029 * partition. */
3030 if (bot_save->next != NULL)
3031 renumber(bot_save->next);
3032
3033 /* Restore global variables from before the justify. */
3034 totsize = totsize_save;
3035 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003036#ifndef NANO_SMALL
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003037 mark_beginbuf = mark_beginbuf_save;
3038 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003039#endif
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003040 flags = flags_save;
3041
3042 /* Clear the justify buffer. */
3043 jusbuffer = NULL;
3044
3045 if (!ISSET(MODIFIED))
3046 titlebar(NULL);
3047 edit_refresh();
3048 }
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003049 } else {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003050 unget_kbinput(kbinput, meta_key, func_key);
David Lawrence Ramseyd994ad52004-11-23 21:40:26 +00003051
David Lawrence Ramsey53d3db42004-11-28 03:53:01 +00003052 /* Blow away the text in the justify buffer. */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003053 free_filestruct(jusbuffer);
3054 jusbuffer = NULL;
Chris Allegretta9149e612000-11-27 00:23:41 +00003055 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003056
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00003057 blank_statusbar();
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003058
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003059 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003060 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00003061 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003062}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003063
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003064void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003065{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003066 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003067}
3068
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003069void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003070{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003071 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003072}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003073#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003074
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003075void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003076{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003077 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00003078
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003079 if (!ISSET(MODIFIED))
3080 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00003081 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003082 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003083 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003084 i = do_yesno(FALSE,
3085 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
3086
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003087#ifdef DEBUG
3088 dump_buffer(fileage);
3089#endif
3090
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003091 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003092#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +00003093 /* Exit only if there are no more open file buffers. */
David Lawrence Ramsey3e189a82004-10-03 19:18:48 +00003094 if (!close_open_file())
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003095#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00003096 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003097 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003098 statusbar(_("Cancelled"));
3099
3100 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003101}
3102
3103void signal_init(void)
3104{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003105 /* Trap SIGINT and SIGQUIT because we want them to do useful
3106 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003107 memset(&act, 0, sizeof(struct sigaction));
3108 act.sa_handler = SIG_IGN;
3109 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00003110 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003111
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003112 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003113 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003114 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003115 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003116
3117#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003118 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003119 act.sa_handler = handle_sigwinch;
3120 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003121 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003122#endif
3123
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003124 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003125 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003126 act.sa_handler = SIG_IGN;
3127 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003128 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003129 /* Block all other signals in the suspend and continue handlers.
3130 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003131 sigfillset(&act.sa_mask);
3132
3133 act.sa_handler = do_suspend;
3134 sigaction(SIGTSTP, &act, NULL);
3135
3136 act.sa_handler = do_cont;
3137 sigaction(SIGCONT, &act, NULL);
3138 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003139}
3140
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003141/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003142RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003143{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00003144 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003145}
3146
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003147/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003148RETSIGTYPE do_suspend(int signal)
3149{
3150 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00003151 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003152 fflush(stdout);
3153
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003154 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003155 tcsetattr(0, TCSANOW, &oldterm);
3156
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00003157 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003158 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00003159 act.sa_handler = handle_hupterm;
3160 sigaction(SIGHUP, &act, NULL);
3161 sigaction(SIGTERM, &act, NULL);
3162
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003163 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003164 kill(0, SIGSTOP);
3165}
3166
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003167/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003168RETSIGTYPE do_cont(int signal)
3169{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003170#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003171 /* Perhaps the user resized the window while we slept. Handle it
3172 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003173 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003174#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003175 /* Just update the screen. */
3176 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003177#endif
3178}
3179
3180#ifndef NANO_SMALL
3181void handle_sigwinch(int s)
3182{
3183 const char *tty = ttyname(0);
3184 int fd;
3185 int result = 0;
3186 struct winsize win;
3187
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003188 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003189 return;
3190 fd = open(tty, O_RDWR);
3191 if (fd == -1)
3192 return;
3193 result = ioctl(fd, TIOCGWINSZ, &win);
3194 close(fd);
3195 if (result == -1)
3196 return;
3197
3198 /* Could check whether the COLS or LINES changed, and return
3199 * otherwise. EXCEPT, that COLS and LINES are ncurses global
3200 * variables, and in some cases ncurses has already updated them.
3201 * But not in all cases, argh. */
3202 COLS = win.ws_col;
3203 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00003204 editwinrows = LINES - 5 + no_help();
3205 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003206 die_too_small();
3207
3208#ifndef DISABLE_WRAPJUSTIFY
3209 fill = wrap_at;
3210 if (fill <= 0)
3211 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00003212 if (fill < 0)
3213 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003214#endif
3215
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00003216 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003217 memset(hblank, ' ', COLS);
3218 hblank[COLS] = '\0';
3219
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00003220 /* If we've partitioned the filestruct, unpartition it now. */
3221 if (filepart != NULL)
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00003222 unpartition_filestruct(&filepart);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00003223
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003224#ifndef DISABLE_JUSTIFY
David Lawrence Ramseybc3b9262004-11-23 04:17:19 +00003225 /* If the justify buffer isn't empty, blow away the text in it and
3226 * display the shortcut list with UnCut. */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003227 if (jusbuffer != NULL) {
3228 free_filestruct(jusbuffer);
3229 jusbuffer = NULL;
3230 shortcut_init(FALSE);
3231 }
3232#endif
3233
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003234#ifdef USE_SLANG
3235 /* Slang curses emulation brain damage, part 1: If we just do what
3236 * curses does here, it'll only work properly if the resize made the
3237 * window smaller. Do what mutt does: Leave and immediately reenter
3238 * Slang screen management mode. */
3239 SLsmg_reset_smg();
3240 SLsmg_init_smg();
3241#else
3242 /* Do the equivalent of what Minimum Profit does: Leave and
3243 * immediately reenter curses mode. */
3244 endwin();
3245 refresh();
3246#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003247
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003248 /* Restore the terminal to its previous state. */
3249 terminal_init();
3250
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003251 /* Do the equivalent of what both mutt and Minimum Profit do:
3252 * Reinitialize all the windows based on the new screen
3253 * dimensions. */
3254 window_init();
3255
David Lawrence Ramsey907725f2004-11-12 00:09:20 +00003256 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003257 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003258 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003259 total_refresh();
3260
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003261 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003262 curs_set(1);
3263
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00003264 /* Reset all the input routines that rely on character sequences. */
3265 reset_kbinput();
3266
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003267 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003268 siglongjmp(jmpbuf, 1);
3269}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003270
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003271void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003272{
3273 sigset_t winch;
3274 sigemptyset(&winch);
3275 sigaddset(&winch, SIGWINCH);
3276 if (allow)
3277 sigprocmask(SIG_UNBLOCK, &winch, NULL);
3278 else
3279 sigprocmask(SIG_BLOCK, &winch, NULL);
3280}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003281#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003282
Chris Allegrettadab017e2002-04-23 10:56:06 +00003283#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00003284void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00003285{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003286 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00003287
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003288 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00003289
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003290 switch (which->val) {
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003291 case TOGGLE_SUSPEND_KEY:
3292 signal_init();
3293 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003294#ifndef DISABLE_MOUSE
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003295 case TOGGLE_MOUSE_KEY:
3296 mouse_init();
3297 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003298#endif
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003299 case TOGGLE_NOHELP_KEY:
3300 blank_statusbar();
3301 blank_bottombars();
3302 wrefresh(bottomwin);
3303 window_init();
3304 edit_refresh();
3305 display_main_list();
3306 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003307#ifdef ENABLE_COLOR
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003308 case TOGGLE_SYNTAX_KEY:
3309 edit_refresh();
3310 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003311#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003312#ifdef ENABLE_NANORC
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003313 case TOGGLE_WHITESPACE_KEY:
David Lawrence Ramsey846658e2004-12-05 04:18:26 +00003314 titlebar(NULL);
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003315 edit_refresh();
3316 break;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003317#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003318 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003319
Chris Allegretta6df90f52002-07-19 01:08:59 +00003320 /* We are assuming here that shortcut_init() above didn't free and
3321 * reallocate the toggles. */
3322 enabled = ISSET(which->flag);
3323 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3324 enabled = !enabled;
3325 statusbar("%s %s", which->desc,
3326 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003327}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003328#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003329
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003330void disable_extended_input(void)
3331{
3332 struct termios term;
3333
3334 tcgetattr(0, &term);
3335 term.c_lflag &= ~IEXTEN;
3336 tcsetattr(0, TCSANOW, &term);
3337}
3338
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003339void disable_signals(void)
3340{
3341 struct termios term;
3342
3343 tcgetattr(0, &term);
3344 term.c_lflag &= ~ISIG;
3345 tcsetattr(0, TCSANOW, &term);
3346}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003347
3348#ifndef NANO_SMALL
3349void enable_signals(void)
3350{
3351 struct termios term;
3352
3353 tcgetattr(0, &term);
3354 term.c_lflag |= ISIG;
3355 tcsetattr(0, TCSANOW, &term);
3356}
3357#endif
3358
3359void disable_flow_control(void)
3360{
3361 struct termios term;
3362
3363 tcgetattr(0, &term);
3364 term.c_iflag &= ~(IXON|IXOFF);
3365 tcsetattr(0, TCSANOW, &term);
3366}
3367
3368void enable_flow_control(void)
3369{
3370 struct termios term;
3371
3372 tcgetattr(0, &term);
3373 term.c_iflag |= (IXON|IXOFF);
3374 tcsetattr(0, TCSANOW, &term);
3375}
3376
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003377/* Set up the terminal state. Put the terminal in cbreak mode (read one
3378 * character at a time and interpret the special control keys), disable
3379 * translation of carriage return (^M) into newline (^J) so that we can
3380 * tell the difference between the Enter key and Ctrl-J, and disable
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003381 * echoing of characters as they're typed. Finally, disable extended
3382 * input processing, disable interpretation of the special control keys,
3383 * and if we're not in preserve mode, disable interpretation of the flow
3384 * control characters too. */
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003385void terminal_init(void)
3386{
3387 cbreak();
3388 nonl();
3389 noecho();
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003390 disable_extended_input();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003391 disable_signals();
3392 if (!ISSET(PRESERVE))
3393 disable_flow_control();
3394}
3395
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003396int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003397 *ran_func, bool *finished, bool allow_funcs)
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003398{
3399 int input;
3400 /* The character we read in. */
3401 static int *kbinput = NULL;
3402 /* The input buffer. */
3403 static size_t kbinput_len = 0;
3404 /* The length of the input buffer. */
3405 const shortcut *s;
3406 bool have_shortcut;
3407#ifndef NANO_SMALL
3408 const toggle *t;
3409 bool have_toggle;
3410#endif
3411
3412 *s_or_t = FALSE;
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003413 *ran_func = FALSE;
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003414 *finished = FALSE;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003415
3416 /* Read in a character. */
3417 input = get_kbinput(edit, meta_key, func_key);
3418
3419#ifndef DISABLE_MOUSE
3420 /* If we got a mouse click and it was on a shortcut, read in the
3421 * shortcut character. */
David Lawrence Ramseyb8a2a6d2005-01-02 21:13:36 +00003422 if (allow_funcs && *func_key == TRUE && input == KEY_MOUSE) {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003423 if (do_mouse())
3424 input = get_kbinput(edit, meta_key, func_key);
3425 else
3426 input = ERR;
3427 }
3428#endif
3429
3430 /* Check for a shortcut in the main list. */
3431 s = get_shortcut(main_list, &input, meta_key, func_key);
3432
3433 /* If we got a shortcut from the main list, or a "universal"
3434 * edit window shortcut, set have_shortcut to TRUE. */
3435 have_shortcut = (s != NULL || input == NANO_XON_KEY ||
3436 input == NANO_XOFF_KEY || input == NANO_SUSPEND_KEY);
3437
3438#ifndef NANO_SMALL
3439 /* Check for a toggle in the main list. */
3440 t = get_toggle(input, *meta_key);
3441
3442 /* If we got a toggle from the main list, set have_toggle to
3443 * TRUE. */
3444 have_toggle = (t != NULL);
3445#endif
3446
3447 /* Set s_or_t to TRUE if we got a shortcut or toggle. */
3448 *s_or_t = (have_shortcut
3449#ifndef NANO_SMALL
3450 || have_toggle
3451#endif
3452 );
3453
3454 if (allow_funcs) {
3455 /* If we got a character, and it isn't a shortcut, toggle, or
3456 * control character, it's a normal text character. Display the
3457 * warning if we're in view mode, or add the character to the
3458 * input buffer if we're not. */
3459 if (input != ERR && *s_or_t == FALSE && !is_cntrl_char(input)) {
3460 if (ISSET(VIEW_MODE))
3461 print_view_warning();
3462 else {
3463 kbinput_len++;
3464 kbinput = (int *)nrealloc(kbinput, kbinput_len *
3465 sizeof(int));
3466 kbinput[kbinput_len - 1] = input;
3467 }
3468 }
3469
3470 /* If we got a shortcut or toggle, or if there aren't any other
3471 * characters waiting after the one we read in, we need to
3472 * display all the characters in the input buffer if it isn't
3473 * empty. Note that it should be empty if we're in view
3474 * mode. */
3475 if (*s_or_t == TRUE || get_buffer_len() == 0) {
3476 if (kbinput != NULL) {
3477 /* Display all the characters in the input buffer at
3478 * once. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003479 char *output = charalloc(kbinput_len + 1);
3480 size_t i;
3481
3482 for (i = 0; i < kbinput_len; i++)
3483 output[i] = (char)kbinput[i];
3484 output[i] = '\0';
3485
3486 do_output(output, kbinput_len);
3487
3488 free(output);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003489
3490 /* Empty the input buffer. */
3491 kbinput_len = 0;
3492 free(kbinput);
3493 kbinput = NULL;
3494 }
3495 }
3496
3497 if (have_shortcut) {
3498 switch (input) {
David Lawrence Ramsey775d46d2005-01-11 23:08:36 +00003499 /* Handle the "universal" statusbar prompt shortcuts. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003500 case NANO_XON_KEY:
3501 statusbar(_("XON ignored, mumble mumble."));
3502 break;
3503 case NANO_XOFF_KEY:
3504 statusbar(_("XOFF ignored, mumble mumble."));
3505 break;
3506#ifndef NANO_SMALL
3507 case NANO_SUSPEND_KEY:
3508 if (ISSET(SUSPEND))
3509 do_suspend(0);
3510 break;
3511#endif
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003512 /* Handle the normal edit window shortcuts, setting
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003513 * ran_func to TRUE if we try to run their associated
3514 * functions and setting finished to TRUE to indicate
3515 * that we're done after trying to run their associated
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003516 * functions. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003517 default:
3518 /* Blow away the text in the cutbuffer if we aren't
3519 * cutting text. */
3520 if (s->func != do_cut_text)
3521 cutbuffer_reset();
3522
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00003523 if (s->func != NULL) {
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003524 *ran_func = TRUE;
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00003525 if (ISSET(VIEW_MODE) && !s->viewok)
3526 print_view_warning();
3527 else
3528 s->func();
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003529 }
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003530 *finished = TRUE;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003531 break;
3532 }
3533 }
3534#ifndef NANO_SMALL
3535 else if (have_toggle) {
3536 /* Blow away the text in the cutbuffer, since we aren't
3537 * cutting text. */
3538 cutbuffer_reset();
3539 /* Toggle the flag associated with this shortcut. */
3540 if (allow_funcs)
3541 do_toggle(t);
3542 }
3543#endif
3544 else
3545 /* Blow away the text in the cutbuffer, since we aren't
3546 * cutting text. */
3547 cutbuffer_reset();
3548 }
3549
3550 return input;
3551}
3552
3553#ifndef DISABLE_MOUSE
3554bool do_mouse(void)
3555{
3556 int mouse_x, mouse_y;
3557 bool retval;
3558
3559 retval = get_mouseinput(&mouse_x, &mouse_y, TRUE);
3560
3561 if (!retval) {
3562 /* We can click in the edit window to move the cursor. */
3563 if (wenclose(edit, mouse_y, mouse_x)) {
3564 bool sameline;
3565 /* Did they click on the line with the cursor? If they
3566 * clicked on the cursor, we set the mark. */
3567 size_t xcur;
3568 /* The character they clicked on. */
3569
3570 /* Subtract out the size of topwin. Perhaps we need a
3571 * constant somewhere? */
3572 mouse_y -= 2;
3573
3574 sameline = (mouse_y == current_y);
3575
3576 /* Move to where the click occurred. */
3577 for (; current_y < mouse_y && current->next != NULL; current_y++)
3578 current = current->next;
3579 for (; current_y > mouse_y && current->prev != NULL; current_y--)
3580 current = current->prev;
3581
3582 xcur = actual_x(current->data, get_page_start(xplustabs()) +
3583 mouse_x);
3584
3585#ifndef NANO_SMALL
3586 /* Clicking where the cursor is toggles the mark, as does
3587 * clicking beyond the line length with the cursor at the
3588 * end of the line. */
3589 if (sameline && xcur == current_x) {
3590 if (ISSET(VIEW_MODE)) {
3591 print_view_warning();
3592 return retval;
3593 }
3594 do_mark();
3595 }
3596#endif
3597
3598 current_x = xcur;
3599 placewewant = xplustabs();
3600 edit_refresh();
3601 }
3602 }
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003603
3604 return retval;
3605}
3606#endif /* !DISABLE_MOUSE */
3607
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003608/* The user typed kbinput_len multibyte characters. Add them to the
3609 * edit buffer. */
3610void do_output(char *output, size_t output_len)
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003611{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003612 size_t current_len = strlen(current->data), i = 0;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003613 bool old_constupdate = ISSET(CONSTUPDATE);
3614 bool do_refresh = FALSE;
3615 /* Do we have to call edit_refresh(), or can we get away with
3616 * update_line()? */
3617
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003618 char *char_buf = charalloc(mb_cur_max());
3619 int char_buf_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003620
3621 assert(current != NULL && current->data != NULL);
3622
David Lawrence Ramsey846658e2004-12-05 04:18:26 +00003623 /* Turn off constant cursor position display. */
3624 UNSET(CONSTUPDATE);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003625
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003626 while (i < output_len) {
David Lawrence Ramseyabc94232004-12-08 23:24:31 +00003627 /* Null to newline, if needed. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003628 if (output[i] == '\0')
3629 output[i] = '\n';
David Lawrence Ramseyabc94232004-12-08 23:24:31 +00003630 /* Newline to Enter, if needed. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003631 else if (output[i] == '\n') {
David Lawrence Ramseyabc94232004-12-08 23:24:31 +00003632 do_enter();
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003633 i++;
David Lawrence Ramseyabc94232004-12-08 23:24:31 +00003634 continue;
3635 }
3636
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003637 /* Interpret the next multibyte character. If it's an invalid
3638 * multibyte character, interpret it as though it's a byte
3639 * character. */
3640 char_buf_len = parse_mbchar(output + i, char_buf
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003641#ifdef NANO_WIDE
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003642 , NULL
3643#endif
3644 , NULL);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003645
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003646 i += char_buf_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003647
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003648 /* When a character is inserted on the current magicline, it
3649 * means we need a new one! */
3650 if (filebot == current)
3651 new_magicline();
3652
3653 /* More dangerousness fun =) */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003654 current->data = charealloc(current->data, current_len +
3655 (char_buf_len * 2));
David Lawrence Ramsey3e819142004-12-31 04:10:28 +00003656
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003657 assert(current_x <= current_len);
David Lawrence Ramsey3e819142004-12-31 04:10:28 +00003658
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003659 charmove(&current->data[current_x + char_buf_len],
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003660 &current->data[current_x],
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003661 current_len - current_x + char_buf_len);
3662 charcpy(&current->data[current_x], char_buf, char_buf_len);
3663 current_len += char_buf_len;
3664 totsize += char_buf_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003665 set_modified();
3666
3667#ifndef NANO_SMALL
3668 /* Note that current_x has not yet been incremented. */
3669 if (current == mark_beginbuf && current_x < mark_beginx)
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003670 mark_beginx += char_buf_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003671#endif
3672
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00003673 do_right(FALSE);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003674
3675#ifndef DISABLE_WRAPPING
3676 /* If we're wrapping text, we need to call edit_refresh(). */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003677 if (!ISSET(NO_WRAP) && output[i] != '\t') {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003678 bool do_refresh_save = do_refresh;
3679
3680 do_refresh = do_wrap(current);
3681
3682 /* If we needed to call edit_refresh() before this, we'll
3683 * still need to after this. */
3684 if (do_refresh_save)
3685 do_refresh = TRUE;
3686 }
3687#endif
3688
3689#ifdef ENABLE_COLOR
3690 /* If color syntaxes are turned on, we need to call
3691 * edit_refresh(). */
3692 if (ISSET(COLOR_SYNTAX))
3693 do_refresh = TRUE;
3694#endif
3695 }
3696
David Lawrence Ramsey846658e2004-12-05 04:18:26 +00003697 /* Turn constant cursor position display back on if it was on
3698 * before. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003699 if (old_constupdate)
3700 SET(CONSTUPDATE);
3701
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003702 free(char_buf);
David Lawrence Ramsey78ea5e42004-12-12 19:04:56 +00003703
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003704 if (do_refresh)
3705 edit_refresh();
3706 else
3707 update_line(current, current_x);
3708}
3709
David Lawrence Ramseya27bd652004-08-17 05:23:38 +00003710int main(int argc, char **argv)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003711{
3712 int optchr;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003713 int startline = 0;
3714 /* Line to try and start at. */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003715#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003716 bool fill_flag_used = FALSE;
3717 /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003718#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003719#ifdef ENABLE_MULTIBUFFER
3720 bool old_multibuffer;
3721 /* The old value of the multibuffer option, restored after we
3722 * load all files on the command line. */
3723#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003724#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003725 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003726 {"help", 0, 0, 'h'},
3727#ifdef ENABLE_MULTIBUFFER
3728 {"multibuffer", 0, 0, 'F'},
3729#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003730#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003731#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003732 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003733#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003734 {"ignorercfiles", 0, 0, 'I'},
3735#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003736#ifndef DISABLE_JUSTIFY
3737 {"quotestr", 1, 0, 'Q'},
3738#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003739#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003740 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003741#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003742 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003743 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003744#ifdef ENABLE_COLOR
3745 {"syntax", 1, 0, 'Y'},
3746#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003747 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003748 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003749 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003750#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003751 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003752#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003753#ifndef DISABLE_OPERATINGDIR
3754 {"operatingdir", 1, 0, 'o'},
3755#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003756 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003757#ifndef DISABLE_WRAPJUSTIFY
3758 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003759#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003760#ifndef DISABLE_SPELLER
3761 {"speller", 1, 0, 's'},
3762#endif
3763 {"tempfile", 0, 0, 't'},
3764 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003765#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003766 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003767#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003768 {"nohelp", 0, 0, 'x'},
3769 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003770#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003771 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003772 {"backup", 0, 0, 'B'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003773 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003774 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003775 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003776 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003777 {"autoindent", 0, 0, 'i'},
3778 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003779#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003780 {0, 0, 0, 0}
3781 };
3782#endif
3783
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00003784#ifdef NANO_WIDE
3785 {
3786 /* If the locale set doesn't exist, or it exists but doesn't
3787 * include the string "UTF-8", we shouldn't use UTF-8
3788 * support. */
3789 char *locale = setlocale(LC_ALL, "");
3790
3791 if (locale == NULL || (locale != NULL &&
3792 strstr(locale, "UTF-8") == NULL))
3793 SET(NO_UTF8);
3794 }
3795#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003796 setlocale(LC_ALL, "");
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00003797#endif
3798
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003799#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003800 bindtextdomain(PACKAGE, LOCALEDIR);
3801 textdomain(PACKAGE);
3802#endif
3803
Chris Allegretta7662c862003-01-13 01:35:15 +00003804#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003805 /* If we don't have rcfile support, we're root, and
3806 * --disable-wrapping-as-root is used, turn wrapping off. */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003807 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003808 SET(NO_WRAP);
3809#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003810
Chris Allegretta6df90f52002-07-19 01:08:59 +00003811 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003812#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9ec76e52004-12-23 19:55:57 +00003813 getopt_long(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003814#else
David Lawrence Ramsey9ec76e52004-12-23 19:55:57 +00003815 getopt(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003816#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003817 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003818
3819 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003820 case 'a':
3821 case 'b':
3822 case 'e':
3823 case 'f':
3824 case 'g':
3825 case 'j':
3826 /* Pico compatibility flags. */
3827 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003828#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003829 case 'A':
3830 SET(SMART_HOME);
3831 break;
3832 case 'B':
3833 SET(BACKUP_FILE);
3834 break;
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003835 case 'E':
3836 backup_dir = mallocstrcpy(backup_dir, optarg);
3837 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003838#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003839#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003840 case 'F':
3841 SET(MULTIBUFFER);
3842 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003843#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003844#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003845#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003846 case 'H':
3847 SET(HISTORYLOG);
3848 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003849#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003850 case 'I':
3851 SET(NO_RCFILE);
3852 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003853#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003854#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003855 case 'N':
3856 SET(NO_CONVERT);
3857 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003858#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003859#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003860 case 'Q':
3861 quotestr = mallocstrcpy(quotestr, optarg);
3862 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003863#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003864#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003865 case 'R':
3866 SET(USE_REGEXP);
3867 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003868#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003869#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003870 case 'S':
3871 SET(SMOOTHSCROLL);
3872 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003873#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003874 case 'T':
3875 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003876 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
3877 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003878 exit(1);
3879 }
3880 break;
3881 case 'V':
3882 version();
3883 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003884#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003885 case 'Y':
3886 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3887 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00003888#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003889 case 'Z':
3890 SET(RESTRICTED);
3891 break;
3892 case 'c':
3893 SET(CONSTUPDATE);
3894 break;
3895 case 'd':
3896 SET(REBIND_DELETE);
3897 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003898#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003899 case 'i':
3900 SET(AUTOINDENT);
3901 break;
3902 case 'k':
3903 SET(CUT_TO_END);
3904 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003905#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003906 case 'l':
3907 SET(NOFOLLOW_SYMLINKS);
3908 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003909#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003910 case 'm':
3911 SET(USE_MOUSE);
3912 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003913#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003914#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003915 case 'o':
3916 operating_dir = mallocstrcpy(operating_dir, optarg);
3917 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003918#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003919 case 'p':
3920 SET(PRESERVE);
3921 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003922#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003923 case 'r':
3924 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003925 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
3926 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003927 exit(1);
3928 }
3929 fill_flag_used = TRUE;
3930 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003931#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003932#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003933 case 's':
3934 alt_speller = mallocstrcpy(alt_speller, optarg);
3935 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003936#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003937 case 't':
3938 SET(TEMP_FILE);
3939 break;
3940 case 'v':
3941 SET(VIEW_MODE);
3942 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003943#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003944 case 'w':
3945 SET(NO_WRAP);
3946 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003947#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003948 case 'x':
3949 SET(NO_HELP);
3950 break;
3951 case 'z':
3952 SET(SUSPEND);
3953 break;
3954 default:
3955 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003956 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003957 }
3958
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003959 /* If the executable filename starts with 'r', we use restricted
3960 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003961 if (*(tail(argv[0])) == 'r')
3962 SET(RESTRICTED);
3963
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003964 /* If we're using restricted mode, disable suspending, backups, and
3965 * reading rcfiles, since they all would allow reading from or
3966 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003967 if (ISSET(RESTRICTED)) {
3968 UNSET(SUSPEND);
3969 UNSET(BACKUP_FILE);
3970 SET(NO_RCFILE);
3971 }
3972
Chris Allegretta7662c862003-01-13 01:35:15 +00003973/* We've read through the command line options. Now back up the flags
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003974 * and values that are set, and read the rcfile(s). If the values
3975 * haven't changed afterward, restore the backed-up values. */
Chris Allegretta7662c862003-01-13 01:35:15 +00003976#ifdef ENABLE_NANORC
3977 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003978#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003979 char *operating_dir_cpy = operating_dir;
3980#endif
David Lawrence Ramsey7e8dd192004-08-12 20:06:20 +00003981#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003982 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003983#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003984#ifndef NANO_SMALL
3985 char *backup_dir_cpy = backup_dir;
3986#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003987#ifndef DISABLE_JUSTIFY
3988 char *quotestr_cpy = quotestr;
3989#endif
3990#ifndef DISABLE_SPELLER
3991 char *alt_speller_cpy = alt_speller;
3992#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003993 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003994 long flags_cpy = flags;
3995
Chris Allegretta5ec68622003-02-05 02:39:34 +00003996#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003997 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003998#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003999#ifndef NANO_SMALL
4000 backup_dir = NULL;
4001#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00004002#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00004003 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00004004#endif
4005#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00004006 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00004007#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00004008
4009 do_rcfile();
4010
4011#ifndef DISABLE_OPERATINGDIR
4012 if (operating_dir_cpy != NULL) {
4013 free(operating_dir);
4014 operating_dir = operating_dir_cpy;
4015 }
4016#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00004017#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00004018 if (fill_flag_used)
4019 wrap_at = wrap_at_cpy;
4020#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004021#ifndef NANO_SMALL
4022 if (backup_dir_cpy != NULL) {
4023 free(backup_dir);
4024 backup_dir = backup_dir_cpy;
4025 }
4026#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00004027#ifndef DISABLE_JUSTIFY
4028 if (quotestr_cpy != NULL) {
4029 free(quotestr);
4030 quotestr = quotestr_cpy;
4031 }
4032#endif
4033#ifndef DISABLE_SPELLER
4034 if (alt_speller_cpy != NULL) {
4035 free(alt_speller);
4036 alt_speller = alt_speller_cpy;
4037 }
4038#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00004039 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00004040 tabsize = tabsize_cpy;
4041 flags |= flags_cpy;
4042 }
4043#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00004044 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00004045 SET(NO_WRAP);
4046#endif
4047#endif /* ENABLE_NANORC */
4048
Chris Allegrettad8451932003-03-11 03:50:40 +00004049#ifndef NANO_SMALL
4050 history_init();
4051#ifdef ENABLE_NANORC
4052 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
4053 load_history();
4054#endif
4055#endif
4056
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004057#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004058 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004059 * in which case backups are disabled, since they would allow
4060 * reading from or writing to files not specified on the command
4061 * line). This entails making sure it exists and is a directory, so
4062 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004063 if (!ISSET(RESTRICTED))
4064 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004065#endif
4066
Chris Allegretta7662c862003-01-13 01:35:15 +00004067#ifndef DISABLE_OPERATINGDIR
4068 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004069 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00004070 init_operating_dir();
4071#endif
4072
Chris Allegretta7662c862003-01-13 01:35:15 +00004073#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00004074 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004075 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00004076
4077 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004078 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00004079
Chris Allegretta7662c862003-01-13 01:35:15 +00004080 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004081 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00004082#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004083 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00004084#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004085 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00004086#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004087 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00004088#ifdef HAVE_REGEX_H
4089 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
4090
4091 if (quoterc == 0) {
4092 /* We no longer need quotestr, just quotereg. */
4093 free(quotestr);
4094 quotestr = NULL;
4095 } else {
4096 size_t size = regerror(quoterc, &quotereg, NULL, 0);
4097
4098 quoteerr = charalloc(size);
4099 regerror(quoterc, &quotereg, quoteerr, size);
4100 }
4101#else
4102 quotelen = strlen(quotestr);
4103#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00004104#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004105
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00004106#ifndef DISABLE_SPELLER
4107 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004108 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004109 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004110 * checking is disabled, since it would allow reading from or
4111 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004112 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00004113 char *spellenv = getenv("SPELL");
4114 if (spellenv != NULL)
4115 alt_speller = mallocstrcpy(NULL, spellenv);
4116 }
4117#endif
4118
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00004119#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004120 /* If whitespace wasn't specified, set its default value. */
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00004121 if (whitespace == NULL)
4122 whitespace = mallocstrcpy(NULL, " ");
4123#endif
4124
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004125 /* If tabsize wasn't specified, set its default value. */
Chris Allegretta7662c862003-01-13 01:35:15 +00004126 if (tabsize == -1)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004127 tabsize = WIDTH_OF_TAB;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00004128
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00004129 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00004130 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00004131
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004132 /* Curses initialization stuff: Start curses and set up the
4133 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004134 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00004135 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00004136
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00004137 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00004138 global_init(FALSE);
4139 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00004140
4141 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00004142 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004143
4144#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00004145 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004146#endif
4147
Chris Allegretta2a42af12000-09-12 23:02:49 +00004148 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00004149#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00004150 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00004151#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004152
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004153#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00004154 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004155#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004156
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00004157 /* If there's a +LINE flag here, it is the first non-option
4158 * argument, and it is followed by at least one other argument, the
4159 * filename it applies to. */
4160 if (0 < optind && optind < argc - 1 && argv[optind][0] == '+') {
4161 startline = atoi(&argv[optind][1]);
4162 optind++;
4163 }
4164
Chris Allegretta7662c862003-01-13 01:35:15 +00004165#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004166 old_multibuffer = ISSET(MULTIBUFFER);
4167 SET(MULTIBUFFER);
4168
4169 /* Read all the files after the first one on the command line into
4170 * new buffers. */
4171 {
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00004172 int i = optind + 1, iline = 0;
4173 for (; i < argc; i++) {
4174 /* If there's a +LINE flag here, it is followed by at least
4175 * one other argument, the filename it applies to. */
4176 if (i < argc - 1 && argv[i][0] == '+' && iline == 0) {
4177 iline = atoi(&argv[i][1]);
4178 } else {
4179 load_buffer(argv[i]);
4180 if (iline > 0) {
4181 do_gotoline(iline, FALSE);
4182 iline = 0;
4183 }
4184 }
4185 }
Chris Allegretta7662c862003-01-13 01:35:15 +00004186 }
4187#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004188
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004189 /* Read the first file on the command line into either the current
4190 * buffer or a new buffer, depending on whether multibuffer mode is
4191 * enabled. */
4192 if (optind < argc)
4193 load_buffer(argv[optind]);
4194
4195 /* We didn't open any files if all the command line arguments were
4196 * invalid files like directories or if there were no command line
4197 * arguments given. In this case, we have to load a blank buffer.
4198 * Also, we unset view mode to allow editing. */
4199 if (filename == NULL) {
4200 filename = mallocstrcpy(NULL, "");
4201 new_file();
4202 UNSET(VIEW_MODE);
4203
4204 /* Add this new entry to the open_files structure if we have
4205 * multibuffer support, or to the main filestruct if we don't. */
4206 load_file();
4207 }
4208
4209#ifdef ENABLE_MULTIBUFFER
4210 if (!old_multibuffer)
4211 UNSET(MULTIBUFFER);
4212#endif
4213
4214#ifdef DEBUG
4215 fprintf(stderr, "Main: top and bottom win\n");
4216#endif
4217
4218 titlebar(NULL);
4219 display_main_list();
4220
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004221 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00004222 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004223
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00004224#ifndef NANO_SMALL
4225 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00004226 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00004227#endif
Chris Allegretta08020882001-01-29 23:37:54 +00004228
Robert Siemborski6967eec2000-07-08 14:23:32 +00004229 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00004230
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00004231 while (TRUE) {
David Lawrence Ramseycac02932005-01-11 23:05:05 +00004232 bool meta_key, func_key, s_or_t, ran_func, finished;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00004233
4234 /* Make sure the cursor is in the edit window. */
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00004235 reset_cursor();
David Lawrence Ramsey74835712004-12-04 17:41:52 +00004236
4237 /* If constant cursor position display is on, display the cursor
4238 * position. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00004239 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00004240 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00004241
Chris Allegretta6b58acd2001-04-12 03:01:53 +00004242 currshortcut = main_list;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00004243
David Lawrence Ramsey74835712004-12-04 17:41:52 +00004244 /* Read in and interpret characters. */
David Lawrence Ramseycac02932005-01-11 23:05:05 +00004245 do_input(&meta_key, &func_key, &s_or_t, &ran_func, &finished,
4246 TRUE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004247 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00004248 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004249}