blob: f27fbefeddb86a2cbb15f6262b4a7cfe7e1d7206 [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"
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000041
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#ifdef HAVE_TERMIOS_H
43#include <termios.h>
44#endif
45
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000046#ifdef HAVE_GETOPT_H
47#include <getopt.h>
48#endif
49
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000050#ifndef NANO_SMALL
51#include <setjmp.h>
52#endif
53
Chris Allegretta6fe61492001-05-21 12:56:25 +000054#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000055static ssize_t fill = 0; /* Fill - where to wrap lines,
56 basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000057#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000058#ifndef DISABLE_WRAPPING
David Lawrence Ramseyce62e822004-08-05 22:10:22 +000059static bool same_line_wrap = FALSE; /* Whether wrapped text should
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000060 be prepended to the next
61 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000062#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000063
Chris Allegretta6df90f52002-07-19 01:08:59 +000064static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000065static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000066
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000067#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000068static sigjmp_buf jmpbuf; /* Used to return to mainloop after
69 SIGWINCH */
David Lawrence Ramsey22fac782004-08-05 15:16:19 +000070static int pid; /* The PID of the newly forked process
71 * in open_pipe(). It must be global
72 * because the signal handler needs
73 * it. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000074#endif
Chris Allegretta08020882001-01-29 23:37:54 +000075
David Lawrence Ramsey93c84052004-11-23 04:08:28 +000076#ifndef DISABLE_JUSTIFY
77static filestruct *jusbottom = NULL;
78 /* Pointer to end of justify buffer. */
79#endif
80
David Lawrence Ramsey50406662005-01-19 19:52:42 +000081void print_view_warning(void)
82{
83 statusbar(_("Key illegal in VIEW mode"));
84}
85
David Lawrence Ramseyda141062004-05-25 19:41:11 +000086/* What we do when we're all set to exit. */
87void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000089 if (!ISSET(NO_HELP))
90 blank_bottombars();
91 else
92 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000093
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094 wrefresh(bottomwin);
95 endwin();
96
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000097 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000098 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099
Chris Allegrettad8451932003-03-11 03:50:40 +0000100#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
101 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
102 save_history();
103#endif
104
Chris Allegretta6232d662002-05-12 19:52:15 +0000105#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000106 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000107#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000108
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000109 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000110}
111
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000112/* Die (gracefully?). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000113void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000114{
115 va_list ap;
116
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000117 endwin();
118 curses_ended = TRUE;
119
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000120 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000121 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000122
Chris Allegretta6df90f52002-07-19 01:08:59 +0000123 va_start(ap, msg);
124 vfprintf(stderr, msg, ap);
125 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000126
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000127 /* Save the current file buffer if it's been modified. */
Chris Allegretta32da4562002-01-02 15:12:21 +0000128 if (ISSET(MODIFIED))
129 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000130
Chris Allegretta355fbe52001-07-14 19:32:47 +0000131#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000132 /* Save all of the other modified file buffers, if any. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000133 if (open_files != NULL) {
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000134 openfilestruct *tmp = open_files;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000135
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000136 while (tmp != open_files->next) {
137 open_files = open_files->next;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000138
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000139 /* Save the current file buffer if it's been modified. */
140 if (open_files->flags & MODIFIED) {
141 /* Set fileage and filebot to match the current file
142 * buffer, and then write it to disk. */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000143 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000144 filebot = open_files->filebot;
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000145 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000146 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000148 }
149#endif
150
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +0000151 /* Get out. */
152 exit(1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153}
154
Chris Allegretta6df90f52002-07-19 01:08:59 +0000155void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000156{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000157 char *ret;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000158 bool failed = TRUE;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000160 /* If we're using restricted mode, don't write any emergency backup
161 * files, since that would allow reading from or writing to files
162 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000163 if (ISSET(RESTRICTED))
164 return;
165
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 /* If we can't save, we have REAL bad problems, but we might as well
David Lawrence Ramsey6a244b62005-04-14 03:52:28 +0000167 * TRY. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168 if (die_filename[0] == '\0')
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000169 die_filename = "nano";
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000171 ret = get_next_filename(die_filename);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 if (ret[0] != '\0')
David Lawrence Ramsey951d7142004-10-04 15:23:47 +0000173 failed = (write_file(ret, TRUE, FALSE, TRUE) == -1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000174
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000175 if (!failed)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000176 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000177 else
David Lawrence Ramsey6a244b62005-04-14 03:52:28 +0000178 fprintf(stderr,
179 _("\nBuffer not written to %s (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000180
181 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000182}
183
Chris Allegrettae61e8302001-01-14 05:18:27 +0000184/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000185 * screen is too small. */
David Lawrence Ramsey50406662005-01-19 19:52:42 +0000186void check_die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000187{
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +0000188 editwinrows = LINES - 5 + no_more_space() + no_help();
David Lawrence Ramsey50406662005-01-19 19:52:42 +0000189 if (editwinrows < MIN_EDITOR_ROWS)
190 die(_("Window size is too small for nano...\n"));
191}
Chris Allegrettae61e8302001-01-14 05:18:27 +0000192
David Lawrence Ramsey50406662005-01-19 19:52:42 +0000193/* Reassign variables that depend on the window size. That is, fill and
194 * hblank. */
195void resize_variables(void)
196{
Chris Allegretta6fe61492001-05-21 12:56:25 +0000197#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000198 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000199 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000200 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000201 if (fill < 0)
202 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000203#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000204
David Lawrence Ramsey50406662005-01-19 19:52:42 +0000205 hblank = charealloc(hblank, COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000206 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000207 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208}
209
David Lawrence Ramsey50406662005-01-19 19:52:42 +0000210/* Initialize global variables -- no better way for now. If
211 * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
212void global_init(bool save_cutbuffer)
213{
214 check_die_too_small();
215 resize_variables();
216
217 fileage = NULL;
218 edittop = NULL;
219 current = NULL;
220 if (!save_cutbuffer)
221 cutbuffer = NULL;
222 current_x = 0;
223 placewewant = 0;
224 current_y = 0;
225 totlines = 0;
226 totsize = 0;
227}
228
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000229void window_init(void)
230{
David Lawrence Ramsey50406662005-01-19 19:52:42 +0000231 check_die_too_small();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000232
Chris Allegretta1a128af2003-01-26 04:15:56 +0000233 if (topwin != NULL)
234 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000235 if (edit != NULL)
236 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000237 if (bottomwin != NULL)
238 delwin(bottomwin);
239
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000240 /* Set up the windows. */
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +0000241 topwin = newwin(2 - no_more_space(), COLS, 0, 0);
242 edit = newwin(editwinrows, COLS, 2 - no_more_space(), 0);
David Lawrence Ramsey122ae842005-01-19 20:55:42 +0000243 bottomwin = newwin(3 - no_help(), COLS, editwinrows +
244 (2 - no_more_space()), 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000245
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000246 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000247 keypad(edit, TRUE);
248 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249}
250
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000251#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252void mouse_init(void)
253{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000254 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255 mousemask(BUTTON1_RELEASED, NULL);
256 mouseinterval(50);
257 } else
258 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000259}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000260#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000261
262#ifndef DISABLE_HELP
263/* This function allocates help_text, and stores the help string in it.
264 * help_text should be NULL initially. */
265void help_init(void)
266{
David Lawrence Ramseyc4daf5d2005-03-22 02:51:01 +0000267 size_t allocsize = 0; /* Space needed for help_text. */
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000268 const char *htx[3]; /* Untranslated help message. We break
269 * it up into three chunks in case the
270 * full string is too long for the
271 * compiler to handle. */
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000272 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000273 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000274#ifndef NANO_SMALL
275 const toggle *t;
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000276#ifdef ENABLE_NANORC
277 bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
278
279 UNSET(WHITESPACE_DISPLAY);
280#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000281#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000282
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000283 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000284 if (currshortcut == whereis_list || currshortcut == replace_list
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000285 || currshortcut == replace_list_2) {
286 htx[0] = N_("Search Command Help Text\n\n "
287 "Enter the words or characters you would like to "
288 "search for, and then press Enter. If there is a "
289 "match for the text you entered, the screen will be "
290 "updated to the location of the nearest match for the "
291 "search string.\n\n The previous search string will be "
292 "shown in brackets after the search prompt. Hitting "
293 "Enter without entering any text will perform the "
294 "previous search. ");
295 htx[1] = N_("If you have selected text with the mark and then "
296 "search to replace, only matches in the selected text "
297 "will be replaced.\n\n The following function keys are "
298 "available in Search mode:\n\n");
299 htx[2] = NULL;
300 } else if (currshortcut == gotoline_list) {
301 htx[0] = N_("Go To Line Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000302 "Enter the line number that you wish to go to and hit "
303 "Enter. If there are fewer lines of text than the "
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000304 "number you entered, you will be brought to the last "
305 "line of the file.\n\n The following function keys are "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000306 "available in Go To Line mode:\n\n");
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000307 htx[1] = NULL;
308 htx[2] = NULL;
309 } else if (currshortcut == insertfile_list) {
310 htx[0] = N_("Insert File Help Text\n\n "
311 "Type in the name of a file to be inserted into the "
312 "current file buffer at the current cursor "
313 "location.\n\n If you have compiled nano with multiple "
314 "file buffer support, and enable multiple file buffers "
315 "with the -F or --multibuffer command line flags, the "
316 "Meta-F toggle, or a nanorc file, inserting a file "
317 "will cause it to be loaded into a separate buffer "
318 "(use Meta-< and > to switch between file buffers). ");
319 htx[1] = N_("If you need another blank buffer, do not enter "
320 "any filename, or type in a nonexistent filename at "
321 "the prompt and press Enter.\n\n The following "
David Lawrence Ramseyfdd3bec2004-11-07 21:30:55 +0000322 "function keys are available in Insert File mode:\n\n");
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000323 htx[2] = NULL;
324 } else if (currshortcut == writefile_list) {
325 htx[0] = N_("Write File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000326 "Type the name that you wish to save the current file "
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000327 "as and press Enter to save the file.\n\n If you have "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000328 "selected text with the mark, you will be prompted to "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000329 "save only the selected portion to a separate file. To "
330 "reduce the chance of overwriting the current file with "
331 "just a portion of it, the current filename is not the "
332 "default in this mode.\n\n The following function keys "
333 "are available in Write File mode:\n\n");
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000334 htx[1] = NULL;
335 htx[2] = NULL;
336 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000337#ifndef DISABLE_BROWSER
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000338 else if (currshortcut == browser_list) {
339 htx[0] = N_("File Browser Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000340 "The file browser is used to visually browse the "
341 "directory structure to select a file for reading "
342 "or writing. You may use the arrow keys or Page Up/"
343 "Down to browse through the files, and S or Enter to "
344 "choose the selected file or enter the selected "
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000345 "directory. To move up one level, select the "
346 "directory called \"..\" at the top of the file "
347 "list.\n\n The following function keys are available "
348 "in the file browser:\n\n");
349 htx[1] = NULL;
350 htx[2] = NULL;
351 } else if (currshortcut == gotodir_list) {
352 htx[0] = N_("Browser Go To Directory Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000353 "Enter the name of the directory you would like to "
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000354 "browse to.\n\n If tab completion has not been "
355 "disabled, you can use the Tab key to (attempt to) "
356 "automatically complete the directory name.\n\n The "
357 "following function keys are available in Browser Go "
358 "To Directory mode:\n\n");
359 htx[1] = NULL;
360 htx[2] = NULL;
361 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000362#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000363#ifndef DISABLE_SPELLER
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000364 else if (currshortcut == spell_list) {
365 htx[0] = N_("Spell Check Help Text\n\n "
366 "The spell checker checks the spelling of all text in "
367 "the current file. When an unknown word is "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000368 "encountered, it is highlighted and a replacement can "
369 "be edited. It will then prompt to replace every "
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000370 "instance of the given misspelled word in the current "
371 "file, or, if you have selected text with the mark, in "
372 "the selected text.\n\n The following other functions "
373 "are available in Spell Check mode:\n\n");
374 htx[1] = NULL;
375 htx[2] = NULL;
376 }
Chris Allegretta201f1d92003-02-05 02:51:19 +0000377#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000378#ifndef NANO_SMALL
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000379 else if (currshortcut == extcmd_list) {
380 htx[0] = N_("Execute Command Help Text\n\n "
381 "This menu allows you to insert the output of a "
382 "command run by the shell into the current buffer (or "
383 "a new buffer in multiple file buffer mode). If you "
384 "need another blank buffer, do not enter any "
385 "command.\n\n The following keys are available in "
386 "Execute Command mode:\n\n");
387 htx[1] = NULL;
388 htx[2] = NULL;
389 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000390#endif
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000391 else {
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000392 /* Default to the main help list. */
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000393 htx[0] = N_(" nano help text\n\n "
394 "The nano editor is designed to emulate the "
395 "functionality and ease-of-use of the UW Pico text "
396 "editor. There are four main sections of the editor. "
397 "The top line shows the program version, the current "
398 "filename being edited, and whether or not the file "
399 "has been modified. Next is the main editor window "
400 "showing the file being edited. The status line is "
401 "the third line from the bottom and shows important "
402 "messages. The bottom two lines show the most "
David Lawrence Ramsey0bfec6e2005-04-25 20:08:29 +0000403 "commonly used shortcuts in the editor.\n\n ");
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000404 htx[1] = N_("The notation for shortcuts is as follows: "
405 "Control-key sequences are notated with a caret (^) "
406 "symbol and can be entered either by using the Control "
407 "(Ctrl) key or pressing the Escape (Esc) key twice. "
408 "Escape-key sequences are notated with the Meta (M) "
409 "symbol and can be entered using either the Esc, Alt, "
410 "or Meta key depending on your keyboard setup. ");
411 htx[2] = N_("Also, pressing Esc twice and then typing a "
412 "three-digit decimal number from 000 to 255 will enter "
413 "the character with the corresponding value. The "
414 "following keystrokes are available in the main editor "
415 "window. Alternative keys are shown in "
416 "parentheses:\n\n");
417 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000418
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000419 htx[0] = _(htx[0]);
420 if (htx[1] != NULL)
421 htx[1] = _(htx[1]);
422 if (htx[2] != NULL)
423 htx[2] = _(htx[2]);
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000424
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000425 allocsize += strlen(htx[0]);
426 if (htx[1] != NULL)
427 allocsize += strlen(htx[1]);
428 if (htx[2] != NULL)
429 allocsize += strlen(htx[2]);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000430
431 /* The space needed for the shortcut lists, at most COLS characters,
432 * plus '\n'. */
David Lawrence Ramseyc4daf5d2005-03-22 02:51:01 +0000433 allocsize += (COLS < 24 ? (24 * mb_cur_max()) :
434 ((COLS + 1) * mb_cur_max())) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000435
436#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000437 /* If we're on the main list, we also count the toggle help text.
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000438 * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
439 * plus translated text, plus '\n'. */
Chris Allegretta3a784062003-02-10 02:32:58 +0000440 if (currshortcut == main_list) {
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000441 size_t endis_len = strlen(_("enable/disable"));
Chris Allegretta3a784062003-02-10 02:32:58 +0000442
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000443 for (t = toggles; t != NULL; t = t->next)
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000444 allocsize += 8 + strlen(t->desc) + endis_len;
Chris Allegretta3a784062003-02-10 02:32:58 +0000445 }
David Lawrence Ramsey1f1ebb82004-11-11 21:50:01 +0000446#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000447
448 /* help_text has been freed and set to NULL unless the user resized
449 * while in the help screen. */
450 free(help_text);
451
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000452 /* Allocate space for the help text. */
David Lawrence Ramseyc4daf5d2005-03-22 02:51:01 +0000453 help_text = charalloc(allocsize + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000454
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000455 /* Now add the text we want. */
David Lawrence Ramseyaa683852005-03-30 18:11:59 +0000456 strcpy(help_text, htx[0]);
457 if (htx[1] != NULL)
458 strcat(help_text, htx[1]);
459 if (htx[2] != NULL)
460 strcat(help_text, htx[2]);
461
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000462 ptr = help_text + strlen(help_text);
463
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000464 /* Now add our shortcut info. Assume that each shortcut has, at the
465 * very least, an equivalent control key, an equivalent primary meta
466 * key sequence, or both. Also assume that the meta key values are
467 * not control characters. We can display a maximum of 3 shortcut
468 * entries. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000469 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000470 int entries = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000471
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000472 /* Control key. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000473 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000474 entries++;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000475#ifndef NANO_SMALL
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000476 if (s->ctrlval == NANO_HISTORY_KEY) {
477 char *up_ptr = display_string(_("Up"), 0, 7, FALSE);
478
479 ptr += sprintf(ptr, "%s", up_ptr);
480
481 free(up_ptr);
482 } else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000483#endif
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000484 if (s->ctrlval == NANO_CONTROL_SPACE) {
485 char *space_ptr = display_string(_("Space"), 0, 6,
486 FALSE);
487
488 ptr += sprintf(ptr, "^%s", space_ptr);
489
490 free(space_ptr);
491 } else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000492 ptr += sprintf(ptr, "^?");
493 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000494 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000495 *(ptr++) = '\t';
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000496 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000497
498 /* Function key. */
499 if (s->funcval != NANO_NO_KEY) {
500 entries++;
David Lawrence Ramsey2e83a502004-11-01 22:35:26 +0000501 /* If this is the first entry, put it in the middle. */
502 if (entries == 1) {
503 entries++;
504 *(ptr++) = '\t';
505 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000506 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
507 *(ptr++) = '\t';
508 }
509
510 /* Primary meta key sequence. */
511 if (s->metaval != NANO_NO_KEY) {
512 entries++;
513 /* If this is the last entry, put it at the end. */
514 if (entries == 2 && s->miscval == NANO_NO_KEY) {
515 entries++;
516 *(ptr++) = '\t';
517 }
518 /* If the primary meta key sequence is the first entry,
519 * don't put parentheses around it. */
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000520 if (entries == 1 && s->metaval == NANO_ALT_SPACE) {
521 char *space_ptr = display_string(_("Space"), 0, 5,
522 FALSE);
523
524 ptr += sprintf(ptr, "M-%s", space_ptr);
525
526 free(space_ptr);
527 } else
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000528 ptr += sprintf(ptr, entries == 1 ? "M-%c" : "(M-%c)",
529 toupper(s->metaval));
530 *(ptr++) = '\t';
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000531 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000532
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000533 /* Miscellaneous meta key sequence. */
534 if (entries < 3 && s->miscval != NANO_NO_KEY) {
535 entries++;
536 /* If this is the last entry, put it at the end. */
537 if (entries == 2) {
538 entries++;
539 *(ptr++) = '\t';
540 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000541 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000542 *(ptr++) = '\t';
543 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000544
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000545 /* Make sure all the help text starts at the same place. */
546 while (entries < 3) {
547 entries++;
548 *(ptr++) = '\t';
549 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000550
551 assert(s->help != NULL);
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000552
553 if (COLS > 24) {
554 char *help_ptr = display_string(s->help, 0, COLS - 24,
555 FALSE);
556
557 ptr += sprintf(ptr, help_ptr);
558
559 free(help_ptr);
560 }
561 ptr += sprintf(ptr, "\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000562 }
563
564#ifndef NANO_SMALL
565 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000566 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000567 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000568
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000569 assert(t->desc != NULL);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000570
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +0000571 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
572 t->desc, _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000573 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000574 }
David Lawrence Ramseyb6e79fd2005-02-25 19:17:57 +0000575
576#ifdef ENABLE_NANORC
577 if (old_whitespace)
578 SET(WHITESPACE_DISPLAY);
579#endif
580#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000581
582 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000583 * help_text. */
David Lawrence Ramsey4e0b1ae2005-03-22 03:58:51 +0000584 assert(strlen(help_text) <= allocsize + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000585}
586#endif
587
588/* Create a new filestruct node. Note that we specifically do not set
589 * prevnode->next equal to the new line. */
590filestruct *make_new_node(filestruct *prevnode)
591{
592 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000593 newnode->data = NULL;
594 newnode->prev = prevnode;
595 newnode->next = NULL;
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000596 newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000597 return newnode;
598}
599
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000600/* Make a copy of a filestruct node. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000601filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000602{
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000603 filestruct *dst;
604
Chris Allegretta6df90f52002-07-19 01:08:59 +0000605 assert(src != NULL);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000606
607 dst = (filestruct *)nmalloc(sizeof(filestruct));
608
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000609 dst->data = mallocstrcpy(NULL, src->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000610 dst->next = src->next;
611 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000612 dst->lineno = src->lineno;
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000613
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000614 return dst;
615}
616
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000617/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000618void splice_node(filestruct *begin, filestruct *newnode, filestruct
619 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000620{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000621 assert(newnode != NULL && begin != NULL);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000622
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000623 newnode->next = end;
624 newnode->prev = begin;
625 begin->next = newnode;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000626 if (end != NULL)
627 end->prev = newnode;
628}
629
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000630/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000631void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000632{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000633 assert(fileptr != NULL);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000634
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000635 if (fileptr->prev != NULL)
636 fileptr->prev->next = fileptr->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000637 if (fileptr->next != NULL)
638 fileptr->next->prev = fileptr->prev;
639}
640
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000641/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000642void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000643{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000644 assert(fileptr != NULL && fileptr->data != NULL);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000645
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000646 if (fileptr->data != NULL)
647 free(fileptr->data);
648 free(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000649}
650
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000651/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000652filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000653{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000654 filestruct *head; /* copy of src, top of the copied list */
655 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000656
Chris Allegretta6df90f52002-07-19 01:08:59 +0000657 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000658
Chris Allegretta6df90f52002-07-19 01:08:59 +0000659 prev = copy_node(src);
660 prev->prev = NULL;
661 head = prev;
662 src = src->next;
663 while (src != NULL) {
664 prev->next = copy_node(src);
665 prev->next->prev = prev;
666 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000667
Chris Allegretta6df90f52002-07-19 01:08:59 +0000668 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000669 }
670
Chris Allegretta6df90f52002-07-19 01:08:59 +0000671 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000672 return head;
673}
674
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000675/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000676void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000677{
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000678 assert(src != NULL);
679
680 while (src->next != NULL) {
681 src = src->next;
682 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000683 }
David Lawrence Ramsey5b3dd0f2004-11-25 04:39:07 +0000684 delete_node(src);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000685}
686
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000687/* Partition a filestruct so it begins at (top, top_x) and ends at (bot,
688 * bot_x). */
689partition *partition_filestruct(filestruct *top, size_t top_x,
690 filestruct *bot, size_t bot_x)
691{
692 partition *p;
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000693
David Lawrence Ramsey6299b0d2004-11-08 03:22:23 +0000694 assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000695
696 /* Initialize the partition. */
697 p = (partition *)nmalloc(sizeof(partition));
698
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000699 /* If the top and bottom of the partition are different from the top
700 * and bottom of the filestruct, save the latter and then set them
701 * to top and bot. */
702 if (top != fileage) {
703 p->fileage = fileage;
704 fileage = top;
705 } else
706 p->fileage = NULL;
707 if (bot != filebot) {
708 p->filebot = filebot;
709 filebot = bot;
710 } else
711 p->filebot = NULL;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000712
713 /* Save the line above the top of the partition, detach the top of
714 * the partition from it, and save the text before top_x in
715 * top_data. */
716 p->top_prev = top->prev;
717 top->prev = NULL;
718 p->top_data = mallocstrncpy(NULL, top->data, top_x + 1);
719 p->top_data[top_x] = '\0';
720
721 /* Save the line below the bottom of the partition, detach the
722 * bottom of the partition from it, and save the text after bot_x in
723 * bot_data. */
724 p->bot_next = bot->next;
725 bot->next = NULL;
726 p->bot_data = mallocstrcpy(NULL, bot->data + bot_x);
727
728 /* Remove all text after bot_x at the bottom of the partition. */
729 null_at(&bot->data, bot_x);
730
731 /* Remove all text before top_x at the top of the partition. */
732 charmove(top->data, top->data + top_x, strlen(top->data) -
733 top_x + 1);
734 align(&top->data);
735
736 /* Return the partition. */
737 return p;
738}
739
740/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
741 * (filebot, strlen(filebot)) again. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000742void unpartition_filestruct(partition **p)
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000743{
744 char *tmp;
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000745
David Lawrence Ramsey2c315402004-11-08 03:19:10 +0000746 assert(p != NULL && fileage != NULL && filebot != NULL);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000747
748 /* Reattach the line above the top of the partition, and restore the
749 * text before top_x from top_data. Free top_data when we're done
750 * with it. */
751 tmp = mallocstrcpy(NULL, fileage->data);
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000752 fileage->prev = (*p)->top_prev;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000753 if (fileage->prev != NULL)
754 fileage->prev->next = fileage;
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000755 fileage->data = charealloc(fileage->data, strlen((*p)->top_data) +
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000756 strlen(fileage->data) + 1);
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000757 strcpy(fileage->data, (*p)->top_data);
758 free((*p)->top_data);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000759 strcat(fileage->data, tmp);
760 free(tmp);
761
762 /* Reattach the line below the bottom of the partition, and restore
763 * the text after bot_x from bot_data. Free bot_data when we're
764 * done with it. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000765 filebot->next = (*p)->bot_next;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000766 if (filebot->next != NULL)
767 filebot->next->prev = filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000768 filebot->data = charealloc(filebot->data, strlen(filebot->data) +
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000769 strlen((*p)->bot_data) + 1);
770 strcat(filebot->data, (*p)->bot_data);
771 free((*p)->bot_data);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000772
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000773 /* Restore the top and bottom of the filestruct, if they were
774 * different from the top and bottom of the partition. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000775 if ((*p)->fileage != NULL)
776 fileage = (*p)->fileage;
777 if ((*p)->filebot != NULL)
778 filebot = (*p)->filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000779
780 /* Uninitialize the partition. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +0000781 free(*p);
782 *p = NULL;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000783}
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000784
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000785/* Move all the text between (top, top_x) and (bot, bot_x) in the
786 * current filestruct to a filestruct beginning with file_top and ending
787 * with file_bot. If no text is between (top, top_x) and (bot, bot_x),
788 * don't do anything. */
789void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
790 filestruct *top, size_t top_x, filestruct *bot, size_t bot_x)
791{
792 filestruct *top_save;
David Lawrence Ramsey23c44502005-01-27 20:49:07 +0000793 size_t part_totsize;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000794 bool at_edittop;
795#ifndef NANO_SMALL
796 bool mark_inside = FALSE;
797#endif
798
799 assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
800
801 /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
802 if (top == bot && top_x == bot_x)
803 return;
804
805 /* Partition the filestruct so that it contains only the text from
806 * (top, top_x) to (bot, bot_x), keep track of whether the top of
807 * the partition is the top of the edit window, and keep track of
808 * whether the mark begins inside the partition. */
809 filepart = partition_filestruct(top, top_x, bot, bot_x);
810 at_edittop = (fileage == edittop);
811#ifndef NANO_SMALL
812 if (ISSET(MARK_ISSET))
813 mark_inside = (mark_beginbuf->lineno >= fileage->lineno &&
814 mark_beginbuf->lineno <= filebot->lineno &&
815 (mark_beginbuf != fileage || mark_beginx >= top_x) &&
816 (mark_beginbuf != filebot || mark_beginx <= bot_x));
817#endif
818
819 /* Get the number of characters in the text, and subtract it from
820 * totsize. */
821 get_totals(top, bot, NULL, &part_totsize);
822 totsize -= part_totsize;
823
824 if (*file_top == NULL) {
825 /* If file_top is empty, just move all the text directly into
826 * it. This is equivalent to tacking the text in top onto the
827 * (lack of) text at the end of file_top. */
828 *file_top = fileage;
829 *file_bot = filebot;
830 } else {
831 /* Otherwise, tack the text in top onto the text at the end of
832 * file_bot. */
833 (*file_bot)->data = charealloc((*file_bot)->data,
834 strlen((*file_bot)->data) + strlen(fileage->data) + 1);
835 strcat((*file_bot)->data, fileage->data);
836
837 /* Attach the line after top to the line after file_bot. Then,
838 * if there's more than one line after top, move file_bot down
839 * to bot. */
840 (*file_bot)->next = fileage->next;
841 if ((*file_bot)->next != NULL) {
842 (*file_bot)->next->prev = *file_bot;
843 *file_bot = filebot;
844 }
845 }
846
847 /* Since the text has now been saved, remove it from the filestruct.
848 * If the top of the partition was the top of the edit window, set
849 * edittop to where the text used to start. If the mark began
850 * inside the partition, set the beginning of the mark to where the
851 * text used to start. */
852 fileage = (filestruct *)nmalloc(sizeof(filestruct));
853 fileage->data = mallocstrcpy(NULL, "");
854 filebot = fileage;
855 if (at_edittop)
856 edittop = fileage;
857#ifndef NANO_SMALL
858 if (mark_inside) {
859 mark_beginbuf = fileage;
860 mark_beginx = top_x;
861 }
862#endif
863
864 /* Restore the current line and cursor position. */
865 current = fileage;
866 current_x = top_x;
867
868 top_save = fileage;
869
870 /* Unpartition the filestruct so that it contains all the text
871 * again, minus the saved text. */
872 unpartition_filestruct(&filepart);
873
874 /* Renumber starting with the beginning line of the old
875 * partition. */
876 renumber(top_save);
877
878 if (filebot->data[0] != '\0')
879 new_magicline();
880
881 /* Set totlines to the new number of lines in the file. */
882 totlines = filebot->lineno;
883}
884
885/* Copy all the text from the filestruct beginning with file_top and
886 * ending with file_bot to the current filestruct at the current cursor
887 * position. */
888void copy_from_filestruct(filestruct *file_top, filestruct *file_bot)
889{
890 filestruct *top_save;
891 int part_totlines;
David Lawrence Ramsey23c44502005-01-27 20:49:07 +0000892 size_t part_totsize;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +0000893 bool at_edittop;
894
895 assert(file_top != NULL && file_bot != NULL);
896
897 /* Partition the filestruct so that it contains no text, and keep
898 * track of whether the top of the partition is the top of the edit
899 * window. */
900 filepart = partition_filestruct(current, current_x, current,
901 current_x);
902 at_edittop = (fileage == edittop);
903
904 /* Put the top and bottom of the filestruct at copies of file_top
905 * and file_bot. */
906 fileage = copy_filestruct(file_top);
907 filebot = fileage;
908 while (filebot->next != NULL)
909 filebot = filebot->next;
910
911 /* Restore the current line and cursor position. */
912 current = filebot;
913 current_x = strlen(filebot->data);
914 if (fileage == filebot)
915 current_x += strlen(filepart->top_data);
916
917 /* Get the number of lines and the number of characters in the saved
918 * text, and add the latter to totsize. */
919 get_totals(fileage, filebot, &part_totlines, &part_totsize);
920 totsize += part_totsize;
921
922 /* If the top of the partition was the top of the edit window, set
923 * edittop to where the saved text now starts, and update the
924 * current y-coordinate to account for the number of lines it
925 * has, less one since the first line will be tacked onto the
926 * current line. */
927 if (at_edittop)
928 edittop = fileage;
929 current_y += part_totlines - 1;
930
931 top_save = fileage;
932
933 /* Unpartition the filestruct so that it contains all the text
934 * again, minus the saved text. */
935 unpartition_filestruct(&filepart);
936
937 /* Renumber starting with the beginning line of the old
938 * partition. */
939 renumber(top_save);
940
941 if (filebot->data[0] != '\0')
942 new_magicline();
943
944 /* Set totlines to the new number of lines in the file. */
945 totlines = filebot->lineno;
946}
947
Chris Allegretta6df90f52002-07-19 01:08:59 +0000948void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000949{
950 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000951 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000952
Chris Allegretta6df90f52002-07-19 01:08:59 +0000953 assert(fileage == NULL || fileage != fileage->next);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000954
Chris Allegretta6df90f52002-07-19 01:08:59 +0000955 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000956 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000957}
958
Chris Allegretta6df90f52002-07-19 01:08:59 +0000959void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000960{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000961 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000962 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000963 else {
964 int lineno = fileptr->prev->lineno;
965
966 assert(fileptr != fileptr->next);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +0000967
Chris Allegretta6df90f52002-07-19 01:08:59 +0000968 for (; fileptr != NULL; fileptr = fileptr->next)
969 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000970 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000971}
972
David Lawrence Ramseybc6a36e2005-03-22 20:17:38 +0000973#ifdef HAVE_GETOPT_LONG
974#define print1opt(shortflag, longflag, desc) print1opt_full(shortflag, longflag, desc)
975#else
976#define print1opt(shortflag, longflag, desc) print1opt_full(shortflag, desc)
977#endif
978
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000979/* Print one usage string to the screen. This cuts down on duplicate
David Lawrence Ramsey39e8ce62005-03-21 07:24:47 +0000980 * strings to translate, and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000981 * translatable (the flag names). */
David Lawrence Ramsey39e8ce62005-03-21 07:24:47 +0000982void print1opt_full(const char *shortflag
983#ifdef HAVE_GETOPT_LONG
984 , const char *longflag
985#endif
986 , const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000987{
988 printf(" %s\t", shortflag);
989 if (strlen(shortflag) < 8)
990 printf("\t");
991
992#ifdef HAVE_GETOPT_LONG
993 printf("%s\t", longflag);
994 if (strlen(longflag) < 8)
995 printf("\t\t");
996 else if (strlen(longflag) < 16)
997 printf("\t");
998#endif
999
David Lawrence Ramseyc2b07472005-04-14 03:13:49 +00001000 if (desc != NULL)
1001 printf("%s", _(desc));
1002 printf("\n");
Chris Allegretta3fc5d572002-03-09 18:51:58 +00001003}
1004
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001005void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001006{
1007#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +00001008 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
1009 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001010#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00001011 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
1012 printf(_("Option\t\tMeaning\n"));
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00001013#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +00001014
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001015 print1opt("-h, -?", "--help", N_("Show this message"));
1016 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +00001017#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001018 print1opt("-A", "--smarthome", N_("Enable smart home key"));
1019 print1opt("-B", "--backup", N_("Backup existing files on save"));
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001020 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +00001021#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00001022#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001023 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +00001024#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001025#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00001026#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001027 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00001028#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001029 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001030#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00001031#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001032 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +00001033#endif
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00001034 print1opt("-O", "--morespace", N_("Use more space for editing"));
Chris Allegrettae4f940d2002-03-03 22:36:36 +00001035#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001036 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +00001037#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00001038#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001039 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00001040#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00001041#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001042 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +00001043#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001044 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
1045 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +00001046#ifdef ENABLE_COLOR
David Lawrence Ramsey4c75faa2005-02-14 05:37:09 +00001047 print1opt(_("-Y [str]"), _("--syntax=[str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +00001048#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001049 print1opt("-Z", "--restricted", N_("Restricted mode"));
1050 print1opt("-c", "--const", N_("Constantly show cursor position"));
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001051 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
David Lawrence Ramsey39e8ce62005-03-21 07:24:47 +00001052#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001053 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
David Lawrence Ramsey39e8ce62005-03-21 07:24:47 +00001054 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
David Lawrence Ramseyb80d49f2005-03-26 22:49:46 +00001055#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001056 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001057#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001058 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001059#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00001060#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001061 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +00001062#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001063 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +00001064#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001065 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +00001066#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001067#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001068 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001069#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001070 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
1071 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001072#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001073 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001074#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +00001075 print1opt("-x", "--nohelp", N_("Don't show help window"));
1076 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001077
David Lawrence Ramsey22fac782004-08-05 15:16:19 +00001078 /* This is a special case. */
David Lawrence Ramseyc2b07472005-04-14 03:13:49 +00001079 print1opt("-a, -b, -e,", "", NULL);
David Lawrence Ramsey39e8ce62005-03-21 07:24:47 +00001080 print1opt("-f, -g, -j", "", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +00001081
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001082 exit(0);
1083}
1084
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001085void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001086{
David Lawrence Ramseyb1d9b412005-03-11 04:22:34 +00001087 printf(_(" GNU nano version %s (compiled %s, %s)\n"), VERSION,
1088 __TIME__, __DATE__);
1089 printf(
1090 _(" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001091 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +00001092
Chris Allegrettae6600372003-01-17 03:39:41 +00001093#ifndef ENABLE_NLS
1094 printf(" --disable-nls");
1095#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001096#ifdef DEBUG
1097 printf(" --enable-debug");
1098#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001099#ifdef NANO_EXTRA
1100 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +00001101#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001102#ifdef NANO_SMALL
1103 printf(" --enable-tiny");
1104#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001105#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +00001106 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001107#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001108#ifdef DISABLE_HELP
1109 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001110#endif
1111#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00001112 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001113#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00001114#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +00001115 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +00001116#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00001117#ifdef DISABLE_OPERATINGDIR
1118 printf(" --disable-operatingdir");
1119#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001120#ifdef DISABLE_SPELLER
1121 printf(" --disable-speller");
1122#endif
1123#ifdef DISABLE_TABCOMP
1124 printf(" --disable-tabcomp");
1125#endif
Chris Allegretta84de5522001-04-12 14:51:48 +00001126#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001127#ifdef DISABLE_WRAPPING
1128 printf(" --disable-wrapping");
1129#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00001130#ifdef DISABLE_ROOTWRAP
1131 printf(" --disable-wrapping-as-root");
1132#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001133#ifdef ENABLE_COLOR
1134 printf(" --enable-color");
1135#endif
1136#ifdef ENABLE_MULTIBUFFER
1137 printf(" --enable-multibuffer");
1138#endif
1139#ifdef ENABLE_NANORC
1140 printf(" --enable-nanorc");
1141#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +00001142#ifdef USE_SLANG
1143 printf(" --with-slang");
1144#endif
1145 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001146}
1147
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00001148int no_more_space(void)
1149{
1150 return ISSET(MORE_SPACE) ? 1 : 0;
1151}
1152
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001153int no_help(void)
1154{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001155 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001156}
1157
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001158void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +00001159{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001160 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +00001161}
1162
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001163#ifndef NANO_SMALL
David Lawrence Ramsey50406662005-01-19 19:52:42 +00001164void cancel_fork(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001165{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001166 if (kill(pid, SIGKILL) == -1)
1167 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001168}
1169
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001170/* Return TRUE on success. */
1171bool open_pipe(const char *command)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001172{
1173 int fd[2];
1174 FILE *f;
1175 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +00001176 /* Original and temporary handlers for
1177 * SIGINT. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001178 bool sig_failed = FALSE;
1179 /* sig_failed means that sigaction() failed without changing the
1180 * signal handlers.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001181 *
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001182 * We use this variable since it is important to put things back
1183 * when we finish, even if we get errors. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001184
1185 /* Make our pipes. */
1186
1187 if (pipe(fd) == -1) {
1188 statusbar(_("Could not pipe"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001189 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001190 }
1191
1192 /* Fork a child. */
1193
1194 if ((pid = fork()) == 0) {
1195 close(fd[0]);
1196 dup2(fd[1], fileno(stdout));
1197 dup2(fd[1], fileno(stderr));
1198 /* If execl() returns at all, there was an error. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001199
David Lawrence Ramsey0df875a2005-02-10 02:26:08 +00001200 execl("/bin/sh", "sh", "-c", command, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001201 exit(0);
1202 }
1203
1204 /* Else continue as parent. */
1205
1206 close(fd[1]);
1207
1208 if (pid == -1) {
1209 close(fd[0]);
1210 statusbar(_("Could not fork"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001211 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001212 }
1213
1214 /* Before we start reading the forked command's output, we set
1215 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001216
David Lawrence Ramseye608f942004-05-19 16:04:27 +00001217 /* Enable interpretation of the special control keys so that we get
1218 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001219 enable_signals();
1220
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001221 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001222 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001223 nperror("sigaction");
1224 } else {
1225 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001226 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001227 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001228 nperror("sigaction");
1229 }
1230 }
1231 /* Note that now oldaction is the previous SIGINT signal handler,
1232 * to be restored later. */
1233
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001234 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001235 if (f == NULL)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001236 nperror("fdopen");
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001237
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001238 read_file(f, "stdin");
David Lawrence Ramseyb41df4a2005-03-22 02:50:24 +00001239
David Lawrence Ramsey22fac782004-08-05 15:16:19 +00001240 /* If multibuffer mode is on, we could be here in view mode. If so,
1241 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001242 if (!ISSET(VIEW_MODE))
1243 set_modified();
1244
1245 if (wait(NULL) == -1)
1246 nperror("wait");
1247
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001248 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001249 nperror("sigaction");
1250
David Lawrence Ramseye608f942004-05-19 16:04:27 +00001251 /* Disable interpretation of the special control keys so that we can
1252 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00001253 disable_signals();
1254
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001255 return TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001256}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +00001257#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001258
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001259void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001260{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001261 int *kbinput;
1262 size_t kbinput_len, i;
1263 char *output;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001264
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001265 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001266
David Lawrence Ramsey74835712004-12-04 17:41:52 +00001267 /* Read in all the verbatim characters. */
1268 kbinput = get_verbatim_kbinput(edit, &kbinput_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001269
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00001270 /* Display all the verbatim characters at once, not filtering out
1271 * control characters. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001272 output = charalloc(kbinput_len + 1);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001273
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001274 for (i = 0; i < kbinput_len; i++)
1275 output[i] = (char)kbinput[i];
1276 output[i] = '\0';
1277
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00001278 do_output(output, kbinput_len, TRUE);
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001279
1280 free(output);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001281}
1282
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001283void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001284{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001285 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001286 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001287 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001288 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001289}
1290
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001291void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001292{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001293 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001294 /* Do we have to call edit_refresh(), or can we get away with
1295 * update_line()? */
1296
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +00001297 assert(current != NULL && current->data != NULL && current_x <= strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001298
1299 placewewant = xplustabs();
1300
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001301 if (current->data[current_x] != '\0') {
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00001302 int char_buf_len = parse_mbchar(current->data + current_x, NULL,
1303 NULL, NULL);
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001304 size_t line_len = strlen(current->data + current_x);
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001305
1306 assert(current_x < strlen(current->data));
1307
1308 /* Let's get dangerous. */
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001309 charmove(&current->data[current_x],
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001310 &current->data[current_x + char_buf_len],
1311 line_len - char_buf_len + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001312
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001313 null_at(&current->data, current_x + line_len - char_buf_len);
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001314#ifndef NANO_SMALL
1315 if (current_x < mark_beginx && mark_beginbuf == current)
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001316 mark_beginx -= char_buf_len;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001317#endif
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00001318 totsize--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001319 } else if (current != filebot && (current->next != filebot ||
1320 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001321 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001322 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001323 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001324
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001325 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001326
1327 /* If we're deleting at the end of a line, we need to call
1328 * edit_refresh(). */
1329 if (current->data[current_x] == '\0')
1330 do_refresh = TRUE;
1331
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001332 current->data = charealloc(current->data,
1333 current_x + strlen(foo->data) + 1);
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001334 strcpy(current->data + current_x, foo->data);
1335#ifndef NANO_SMALL
1336 if (mark_beginbuf == current->next) {
1337 mark_beginx += current_x;
1338 mark_beginbuf = current;
1339 }
1340#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001341 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001342 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001343
1344 unlink_node(foo);
1345 delete_node(foo);
1346 renumber(current);
1347 totlines--;
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00001348 totsize--;
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001349#ifndef DISABLE_WRAPPING
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001350 wrap_reset();
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001351#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001352 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001353 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001354
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001355 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001356
1357#ifdef ENABLE_COLOR
1358 /* If color syntaxes are turned on, we need to call
1359 * edit_refresh(). */
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00001360 if (!ISSET(NO_COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001361 do_refresh = TRUE;
1362#endif
1363
1364 if (do_refresh)
1365 edit_refresh();
1366 else
1367 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001368}
1369
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001370void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001371{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00001372 char *kbinput = "\t";
1373
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00001374 do_output(kbinput, 1, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001375}
1376
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001377/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001378void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001379{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001380 filestruct *newnode = make_new_node(current);
1381 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001382
Chris Allegretta6df90f52002-07-19 01:08:59 +00001383 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001384
Chris Allegrettaff989832001-09-17 13:48:00 +00001385#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001386 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001387 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001388 /* If we are breaking the line in the indentation, the new
1389 * indentation should have only current_x characters, and
1390 * current_x should not change. */
1391 extra = indent_length(current->data);
1392 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001393 extra = current_x;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001394 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001395#endif
1396 newnode->data = charalloc(strlen(current->data + current_x) +
1397 extra + 1);
1398 strcpy(&newnode->data[extra], current->data + current_x);
1399#ifndef NANO_SMALL
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +00001400 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001401 strncpy(newnode->data, current->data, extra);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +00001402 totsize += mbstrlen(newnode->data);
1403 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001404#endif
1405 null_at(&current->data, current_x);
1406#ifndef NANO_SMALL
1407 if (current == mark_beginbuf && current_x < mark_beginx) {
1408 mark_beginbuf = newnode;
1409 mark_beginx += extra - current_x;
1410 }
1411#endif
1412 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001413
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001414 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001415 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001416 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001417
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001418 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001419 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001420
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001421 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001422
1423 totlines++;
David Lawrence Ramsey4d97a582004-12-29 16:42:48 +00001424 totsize++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001425 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001426 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001427}
1428
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001429#ifndef NANO_SMALL
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001430/* Move to the next word. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001431void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001432{
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001433 size_t pww_save = placewewant;
1434 const filestruct *current_save = current;
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00001435 char *char_mb;
David Lawrence Ramsey7801d7b2005-01-14 21:59:01 +00001436 int char_mb_len;
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001437
Chris Allegretta6df90f52002-07-19 01:08:59 +00001438 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001439
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00001440 char_mb = charalloc(mb_cur_max());
1441
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001442 /* Move forward until we find the character after the last letter of
1443 * the current word. */
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001444 while (current->data[current_x] != '\0') {
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00001445 char_mb_len = parse_mbchar(current->data + current_x, char_mb,
1446 NULL, NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001447
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001448 /* If we've found it, stop moving forward through the current
1449 * line. */
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001450 if (!is_alnum_mbchar(char_mb))
1451 break;
1452
David Lawrence Ramsey7801d7b2005-01-14 21:59:01 +00001453 current_x += char_mb_len;
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001454 }
1455
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001456 /* Move forward until we find the first letter of the next word. */
David Lawrence Ramsey776cf372005-01-15 15:05:20 +00001457 if (current->data[current_x] != '\0')
1458 current_x += char_mb_len;
1459
Chris Allegretta6df90f52002-07-19 01:08:59 +00001460 for (; current != NULL; current = current->next) {
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001461 while (current->data[current_x] != '\0') {
David Lawrence Ramsey7801d7b2005-01-14 21:59:01 +00001462 char_mb_len = parse_mbchar(current->data + current_x,
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00001463 char_mb, NULL, NULL);
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001464
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001465 /* If we've found it, stop moving forward through the
1466 * current line. */
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001467 if (is_alnum_mbchar(char_mb))
1468 break;
1469
David Lawrence Ramsey7801d7b2005-01-14 21:59:01 +00001470 current_x += char_mb_len;
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001471 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001472
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001473 /* If we've found it, stop moving forward to the beginnings of
1474 * subsequent lines. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001475 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001476 break;
1477
Chris Allegretta6df90f52002-07-19 01:08:59 +00001478 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001479 }
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001480
David Lawrence Ramsey31055b32005-01-14 22:08:18 +00001481 free(char_mb);
1482
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001483 /* If we haven't found it, leave the cursor at the end of the
1484 * file. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001485 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001486 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001487
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001488 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001489
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001490 /* Update the screen. */
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001491 edit_redraw(current_save, pww_save);
Chris Allegretta6232d662002-05-12 19:52:15 +00001492}
1493
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001494/* Move to the previous word. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001495void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001496{
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001497 size_t pww_save = placewewant;
1498 const filestruct *current_save = current;
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00001499 char *char_mb;
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001500 int char_mb_len;
1501 bool begin_line = FALSE;
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001502
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001503 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001504
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00001505 char_mb = charalloc(mb_cur_max());
1506
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001507 /* Move backward until we find the character before the first letter
1508 * of the current word. */
1509 while (!begin_line) {
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00001510 char_mb_len = parse_mbchar(current->data + current_x, char_mb,
1511 NULL, NULL);
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001512
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001513 /* If we've found it, stop moving backward through the current
1514 * line. */
1515 if (!is_alnum_mbchar(char_mb))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001516 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001517
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001518 if (current_x == 0)
1519 begin_line = TRUE;
1520 else
1521 current_x = move_mbleft(current->data, current_x);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001522 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001523
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001524 /* Move backward until we find the last letter of the previous
1525 * word. */
David Lawrence Ramsey776cf372005-01-15 15:05:20 +00001526 if (current_x == 0)
1527 begin_line = TRUE;
1528 else
1529 current_x = move_mbleft(current->data, current_x);
1530
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001531 for (; current != NULL; current = current->prev) {
1532 while (!begin_line) {
1533 char_mb_len = parse_mbchar(current->data + current_x,
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00001534 char_mb, NULL, NULL);
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001535
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001536 /* If we've found it, stop moving backward through the
1537 * current line. */
1538 if (is_alnum_mbchar(char_mb))
1539 break;
1540
1541 if (current_x == 0)
1542 begin_line = TRUE;
1543 else
1544 current_x = move_mbleft(current->data, current_x);
1545 }
1546
1547 /* If we've found it, stop moving backward to the ends of
1548 * previous lines. */
1549 if (!begin_line)
1550 break;
1551
1552 if (current->prev != NULL) {
1553 begin_line = FALSE;
1554 current_x = strlen(current->prev->data);
1555 }
1556 }
1557
1558 /* If we haven't found it, leave the cursor at the beginning of the
1559 * file. */
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001560 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001561 current = fileage;
1562 current_x = 0;
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001563 /* If we've found it, move backward until we find the character
1564 * before the first letter of the previous word. */
1565 } else if (!begin_line) {
1566 if (current_x == 0)
1567 begin_line = TRUE;
1568 else
1569 current_x = move_mbleft(current->data, current_x);
1570
1571 while (!begin_line) {
1572 char_mb_len = parse_mbchar(current->data + current_x,
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00001573 char_mb, NULL, NULL);
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001574
1575 /* If we've found it, stop moving backward through the
1576 * current line. */
1577 if (!is_alnum_mbchar(char_mb))
1578 break;
1579
1580 if (current_x == 0)
1581 begin_line = TRUE;
1582 else
1583 current_x = move_mbleft(current->data, current_x);
1584 }
1585
1586 /* If we've found it, move forward to the first letter of the
1587 * previous word. */
1588 if (!begin_line)
1589 current_x += char_mb_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001590 }
1591
David Lawrence Ramseyce045132005-01-15 00:34:57 +00001592 free(char_mb);
1593
Chris Allegretta76e291b2001-10-14 19:05:10 +00001594 placewewant = xplustabs();
1595
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001596 /* Update the screen. */
David Lawrence Ramsey1fe2eeb2005-01-14 21:33:47 +00001597 edit_redraw(current_save, pww_save);
Chris Allegretta6232d662002-05-12 19:52:15 +00001598}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001599
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001600void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001601{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001602 TOGGLE(MARK_ISSET);
1603 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001604 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001605 mark_beginbuf = current;
1606 mark_beginx = current_x;
1607 } else {
1608 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001609 edit_refresh();
1610 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001611}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001612#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001613
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001614#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001615void wrap_reset(void)
1616{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001617 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001618}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001619#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001620
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001621#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001622/* We wrap the given line. Precondition: we assume the cursor has been
1623 * moved forward since the last typed character. Return value: whether
1624 * we wrapped. */
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001625bool do_wrap(filestruct *line)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001626{
David Lawrence Ramseyd96ee522005-03-20 03:10:31 +00001627 size_t line_len;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001628 /* Length of the line we wrap. */
David Lawrence Ramseyd96ee522005-03-20 03:10:31 +00001629 ssize_t wrap_loc;
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001630 /* Index of line->data where we wrap. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001631#ifndef NANO_SMALL
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001632 const char *indent_string = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001633 /* Indentation to prepend to the new line. */
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001634 size_t indent_len = 0; /* The length of indent_string. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001635#endif
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001636 const char *after_break; /* The text after the wrap point. */
1637 size_t after_break_len; /* The length of after_break. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001638 bool wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001639 const char *next_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001640 /* The next line, minus indentation. */
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001641 size_t next_line_len = 0; /* The length of next_line. */
1642 char *new_line = NULL; /* The line we create. */
1643 size_t new_line_len = 0; /* The eventual length of new_line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001644
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001645 /* There are three steps. First, we decide where to wrap. Then, we
1646 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001647
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001648 /* Step 1, finding where to wrap. We are going to add a new line
1649 * after a blank character. In this step, we call break_line() to
1650 * get the location of the last blank we can break the line at, and
1651 * and set wrap_loc to the location of the character after it, so
1652 * that the blank is preserved at the end of the line.
1653 *
1654 * If there is no legal wrap point, or we reach the last character
1655 * of the line while trying to find one, we should return without
1656 * wrapping. Note that if autoindent is turned on, we don't break
1657 * at the end of it! */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001658
David Lawrence Ramseyd96ee522005-03-20 03:10:31 +00001659 assert(line != NULL && line->data != NULL);
1660
1661 /* Save the length of the line. */
1662 line_len = strlen(line->data);
1663
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001664 /* Find the last blank where we can break the line. */
1665 wrap_loc = break_line(line->data, fill, FALSE);
1666
1667 /* If we couldn't break the line, or we've reached the end of it, we
1668 * don't wrap. */
1669 if (wrap_loc == -1 || line->data[wrap_loc] == '\0')
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001670 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001671
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001672 /* Otherwise, move forward to the character just after the blank. */
1673 wrap_loc += move_mbright(line->data + wrap_loc, 0);
1674
1675 /* If we've reached the end of the line, we don't wrap. */
1676 if (line->data[wrap_loc] == '\0')
1677 return FALSE;
1678
1679#ifndef NANO_SMALL
1680 /* If autoindent is turned on, and we're on the character just after
1681 * the indentation, we don't wrap. */
1682 if (ISSET(AUTOINDENT)) {
1683 /* Get the indentation of this line. */
1684 indent_string = line->data;
1685 indent_len = indent_length(indent_string);
1686
1687 if (wrap_loc == indent_len)
1688 return FALSE;
1689 }
1690#endif
1691
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001692 /* Step 2, making the new wrap line. It will consist of indentation
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001693 * followed by the text after the wrap point, optionally followed by
1694 * a space (if the text after the wrap point doesn't end in a blank)
1695 * and the text of the next line, if they can fit without
1696 * wrapping, the next line exists, and the same_line_wrap flag is
1697 * set. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001698
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001699 /* after_break is the text that will be wrapped to the next line. */
1700 after_break = line->data + wrap_loc;
1701 after_break_len = line_len - wrap_loc;
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00001702
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001703 assert(strlen(after_break) == after_break_len);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001704
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001705 /* We prepend the wrapped text to the next line, if the
1706 * same_line_wrap flag is set, there is a next line, and prepending
1707 * would not make the line too long. */
1708 if (same_line_wrap && line->next != NULL) {
1709 const char *end = after_break + move_mbleft(after_break,
1710 after_break_len);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001711
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001712 /* If after_break doesn't end in a blank, make sure it ends in a
1713 * space. */
1714 if (!is_blank_mbchar(end)) {
1715 line_len++;
1716 line->data = charealloc(line->data, line_len + 1);
1717 line->data[line_len - 1] = ' ';
1718 line->data[line_len] = '\0';
1719 after_break = line->data + wrap_loc;
1720 after_break_len++;
1721 totsize++;
1722 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001723
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001724 next_line = line->next->data;
1725 next_line_len = strlen(next_line);
1726
1727 if ((after_break_len + next_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001728 wrapping = TRUE;
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001729 new_line_len += next_line_len;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001730 }
1731 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001732
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001733 /* new_line_len is now the length of the text that will be wrapped
1734 * to the next line, plus (if we're prepending to it) the length of
1735 * the text of the next line. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001736 new_line_len += after_break_len;
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00001737
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001738#ifndef NANO_SMALL
1739 if (ISSET(AUTOINDENT)) {
1740 if (wrapping) {
1741 /* If we're wrapping, the indentation will come from the
1742 * next line. */
1743 indent_string = next_line;
1744 indent_len = indent_length(indent_string);
1745 next_line += indent_len;
1746 } else {
1747 /* Otherwise, it will come from this line, in which case
1748 * we should increase new_line_len to make room for it. */
1749 new_line_len += indent_len;
1750 totsize += mbstrnlen(indent_string, indent_len);
1751 }
1752 }
1753#endif
1754
1755 /* Now we allocate the new line and copy the text into it. */
1756 new_line = charalloc(new_line_len + 1);
1757 new_line[0] = '\0';
1758
1759#ifndef NANO_SMALL
1760 if (ISSET(AUTOINDENT)) {
1761 /* Copy the indentation. */
1762 charcpy(new_line, indent_string, indent_len);
1763 new_line[indent_len] = '\0';
1764 new_line_len += indent_len;
1765 }
1766#endif
1767
1768 /* Copy all the text after the wrap point of the current line. */
1769 strcat(new_line, after_break);
1770
1771 /* Break the current line at the wrap point. */
1772 null_at(&line->data, wrap_loc);
1773
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001774 if (wrapping) {
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001775 /* If we're wrapping, copy the text from the next line, minus
1776 * the indentation that we already copied above. */
1777 strcat(new_line, next_line);
1778
1779 free(line->next->data);
1780 line->next->data = new_line;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001781 } else {
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001782 /* Otherwise, make a new line and copy the text after where we
1783 * broke this line to the beginning of the new line. */
1784 splice_node(current, make_new_node(current), current->next);
1785
1786 current->next->data = new_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001787
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001788 totlines++;
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001789 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001790 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001791
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001792 /* Step 3, clean up. Reposition the cursor and mark, and do some
1793 * other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001794
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001795 /* Set the same_line_wrap flag, so that later wraps of this line
1796 * will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001797 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001798
1799 /* Each line knows its line number. We recalculate these if we
1800 * inserted a new line. */
1801 if (!wrapping)
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001802 renumber(line);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001803
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001804 /* If the cursor was after the break point, we must move it. We
1805 * also clear the same_line_wrap flag in this case. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001806 if (current_x > wrap_loc) {
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001807 same_line_wrap = FALSE;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001808 current = current->next;
1809 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001810#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001811 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001812#endif
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001813 wrap_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001814 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001815 }
1816
Chris Allegretta6df90f52002-07-19 01:08:59 +00001817#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001818 /* If the mark was on this line after the wrap point, we move it
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001819 * down. If it was on the next line and we wrapped onto that line,
1820 * we move it right. */
1821 if (mark_beginbuf == line && mark_beginx > wrap_loc) {
1822 mark_beginbuf = line->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001823 mark_beginx -= wrap_loc - indent_len + 1;
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001824 } else if (wrapping && mark_beginbuf == line->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001825 mark_beginx += after_break_len;
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00001826#endif
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001827
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001828 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001829}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001830#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001831
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001832#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001833/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001834 * return FALSE if the user cancels. */
1835bool do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001836{
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001837 char *save_search, *save_replace;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001838 size_t current_x_save = current_x, pww_save = placewewant;
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001839 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001840 /* Save where we are. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001841 bool canceled = FALSE;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001842 /* The return value. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001843 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001844#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001845 bool reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001846#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001847#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001848 bool regexp_set = ISSET(USE_REGEXP);
1849#endif
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001850#ifndef NANO_SMALL
1851 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001852 bool added_magicline = FALSE;
1853 /* Whether we added a magicline after filebot. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001854 bool right_side_up = FALSE;
1855 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
1856 * FALSE if (current, current_x) is. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001857 filestruct *top, *bot;
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001858 size_t top_x, bot_x;
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001859#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001860
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001861 /* Make sure spell-check is case sensitive. */
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001862 SET(CASE_SENSITIVE);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001863
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001864#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001865 /* Make sure spell-check goes forward only. */
1866 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001867#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001868#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001869 /* Make sure spell-check doesn't use regular expressions. */
1870 UNSET(USE_REGEXP);
1871#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001872
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001873 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001874 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001875 save_search = last_search;
1876 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001877
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001878 /* Set the search/replace strings to the misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001879 last_search = mallocstrcpy(NULL, word);
1880 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001881
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001882#ifndef NANO_SMALL
1883 if (old_mark_set) {
David Lawrence Ramseyf978f042004-11-04 16:45:48 +00001884 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001885 * contains only the marked text, keep track of whether the text
1886 * will have a magicline added when we're done correcting
1887 * misspelled words, and turn the mark off. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001888 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001889 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001890 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001891 added_magicline = (filebot->data[0] != '\0');
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001892 UNSET(MARK_ISSET);
1893 }
1894#endif
1895
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001896 /* Start from the top of the file. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001897 edittop = fileage;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001898 current = fileage;
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001899 current_x = (size_t)-1;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001900 placewewant = 0;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001901
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001902 /* Find the first whole-word occurrence of word. */
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +00001903 findnextstr_wrap_reset();
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +00001904 while (findnextstr(TRUE, TRUE, FALSE, fileage, 0, word, NULL)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001905 if (is_whole_word(current_x, current->data, word)) {
1906 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001907
Chris Allegretta6df90f52002-07-19 01:08:59 +00001908 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001909
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +00001910 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001911 canceled = (statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001912#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001913 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001914#endif
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001915 _("Edit a replacement")) == -1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001916
Chris Allegretta6df90f52002-07-19 01:08:59 +00001917 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001918
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001919 if (!canceled && strcmp(word, answer) != 0) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001920 current_x--;
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001921 do_replace_loop(word, current, &current_x, TRUE,
1922 &canceled);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001923 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001924
1925 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001926 }
David Lawrence Ramsey53752e82004-10-18 22:19:22 +00001927 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001928
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001929#ifndef NANO_SMALL
1930 if (old_mark_set) {
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00001931 /* If the mark was on and we added a magicline, remove it
1932 * now. */
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001933 if (added_magicline)
1934 remove_magicline();
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001935
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001936 /* Put the beginning and the end of the mark at the beginning
1937 * and the end of the spell-checked text. */
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001938 if (fileage == filebot)
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001939 bot_x += top_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001940 if (right_side_up) {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001941 mark_beginx = top_x;
1942 current_x_save = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001943 } else {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00001944 current_x_save = top_x;
1945 mark_beginx = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00001946 }
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001947
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00001948 /* Unpartition the filestruct so that it contains all the text
1949 * again, and turn the mark back on. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00001950 unpartition_filestruct(&filepart);
David Lawrence Ramseycb093372004-11-06 00:18:27 +00001951 SET(MARK_ISSET);
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001952 }
1953#endif
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001954
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001955 /* Restore the search/replace strings. */
1956 free(last_search);
1957 last_search = save_search;
1958 free(last_replace);
1959 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001960
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001961 /* Restore where we were. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001962 edittop = edittop_save;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001963 current = current_save;
1964 current_x = current_x_save;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001965 placewewant = pww_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001966
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001967 /* Restore case sensitivity setting. */
1968 if (!case_sens_set)
1969 UNSET(CASE_SENSITIVE);
1970
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001971#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001972 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001973 if (reverse_search_set)
1974 SET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001975#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001976#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001977 /* Restore regular expression usage setting. */
1978 if (regexp_set)
1979 SET(USE_REGEXP);
1980#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001981
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001982 return !canceled;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001983}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001984
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001985/* Integrated spell checking using 'spell' program. Return value: NULL
1986 * for normal termination, otherwise the error string. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001987const char *do_int_speller(const char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001988{
Chris Allegretta271e9722000-11-10 18:15:43 +00001989 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001990 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001991 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001992 pid_t pid_spell, pid_sort, pid_uniq;
1993 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001994
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001995 /* Create all three pipes up front. */
David Lawrence Ramseyac71fdd2005-04-15 17:48:20 +00001996 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 ||
1997 pipe(uniq_fd) == -1)
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001998 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001999
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00002000 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002001
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002002 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002003 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002004
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002005 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002006
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002007 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002008
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002009 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002010 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
2011 goto close_pipes_and_exit;
2012
2013 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
2014 goto close_pipes_and_exit;
2015
Chris Allegretta271e9722000-11-10 18:15:43 +00002016 close(tempfile_fd);
2017
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002018 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002019 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2020 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00002021
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002022 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00002023
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002024 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002025 execlp("spell", "spell", NULL);
2026
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002027 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00002028 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002029 }
2030
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002031 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002032 close(spell_fd[1]);
2033
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002034 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002035 if ((pid_sort = fork()) == 0) {
2036
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002037 /* Child continues (i.e, future spell process). Replace the
2038 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002039 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
2040 goto close_pipes_and_exit;
2041
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002042 close(spell_fd[0]);
2043
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002044 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002045 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2046 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002047
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002048 close(sort_fd[1]);
2049
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002050 /* Start sort program. Use -f to remove mixed case without
2051 * having to have ANOTHER pipe for tr. If this isn't portable,
2052 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002053 execlp("sort", "sort", "-f", NULL);
2054
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002055 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002056 exit(1);
2057 }
2058
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00002059 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002060 close(sort_fd[1]);
2061
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002062 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002063 if ((pid_uniq = fork()) == 0) {
2064
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002065 /* Child continues (i.e, future uniq process). Replace the
2066 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002067 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
2068 goto close_pipes_and_exit;
2069
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002070 close(sort_fd[0]);
2071
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002072 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002073 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
2074 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002075
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002076 close(uniq_fd[1]);
2077
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002078 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002079 execlp("uniq", "uniq", NULL);
2080
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002081 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002082 exit(1);
2083 }
2084
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00002085 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002086 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00002087
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002088 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002089 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
2090 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00002091 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002092 }
2093
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002094 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002095 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
2096 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00002097 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00002098 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002099
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002100 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002101 read_buff_read = 0;
2102 read_buff_size = pipe_buff_size + 1;
2103 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002104
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002105 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002106 read_buff_read += bytesread;
2107 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002108 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002109 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002110
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002111 }
Chris Allegretta271e9722000-11-10 18:15:43 +00002112
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002113 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002114 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002115
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002116 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002117 read_buff_word = read_buff_ptr = read_buff;
2118
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002119 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002120
2121 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002122 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002123 if (read_buff_word != read_buff_ptr) {
2124 if (!do_int_spell_fix(read_buff_word)) {
2125 read_buff_word = read_buff_ptr;
2126 break;
2127 }
2128 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002129 read_buff_word = read_buff_ptr + 1;
2130 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002131 read_buff_ptr++;
2132 }
2133
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002134 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00002135 if (read_buff_word != read_buff_ptr)
2136 do_int_spell_fix(read_buff_word);
2137
Chris Allegretta271e9722000-11-10 18:15:43 +00002138 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002139 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00002140 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002141
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002142 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00002143 waitpid(pid_spell, &spell_status, 0);
2144 waitpid(pid_sort, &sort_status, 0);
2145 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00002146
Chris Allegretta334a9402002-12-16 04:25:53 +00002147 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
2148 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00002149
Chris Allegretta334a9402002-12-16 04:25:53 +00002150 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
2151 return _("Error invoking \"sort -f\"");
2152
2153 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
2154 return _("Error invoking \"uniq\"");
2155
2156 /* Otherwise... */
2157 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002158
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002159 close_pipes_and_exit:
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002160 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00002161 close(tempfile_fd);
2162 close(spell_fd[0]);
2163 close(spell_fd[1]);
2164 close(sort_fd[0]);
2165 close(sort_fd[1]);
2166 close(uniq_fd[0]);
2167 close(uniq_fd[1]);
2168 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002169}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002170
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002171/* External spell checking. Return value: NULL for normal termination,
2172 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002173const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002174{
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002175 int alt_spell_status, lineno_save = current->lineno;
2176 size_t current_x_save = current_x, pww_save = placewewant;
2177 int current_y_save = current_y;
Chris Allegretta271e9722000-11-10 18:15:43 +00002178 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00002179 char *ptr;
2180 static int arglen = 3;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002181 static char **spellargs = NULL;
2182 FILE *f;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002183#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002184 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002185 bool added_magicline = FALSE;
2186 /* Whether we added a magicline after filebot. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002187 bool right_side_up = FALSE;
2188 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
2189 * FALSE if (current, current_x) is. */
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002190 filestruct *top, *bot;
2191 size_t top_x, bot_x;
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002192 int mbb_lineno_save = 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002193 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002194 * the alternate spell command. The line that mark_beginbuf
2195 * points to will be freed, so we save the line number and
2196 * restore afterwards. */
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00002197 size_t totsize_save = totsize;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002198 /* Our saved value of totsize, used when we spell-check a marked
2199 * selection. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002200
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002201 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002202 /* If the mark is on, save the number of the line it starts on,
2203 * and then turn the mark off. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002204 mbb_lineno_save = mark_beginbuf->lineno;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002205 UNSET(MARK_ISSET);
2206 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002207#endif
2208
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002209 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002210
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002211 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00002212 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002213 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00002214
Chris Allegrettae434b452001-01-27 19:25:00 +00002215 spellargs[0] = strtok(alt_speller, " ");
2216 while ((ptr = strtok(NULL, " ")) != NULL) {
2217 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002218 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00002219 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00002220 }
Chris Allegrettae434b452001-01-27 19:25:00 +00002221 spellargs[arglen - 1] = NULL;
2222 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002223 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00002224
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002225 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002226 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002227 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00002228 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00002229
2230 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00002231 exit(1);
2232 }
2233
2234 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00002235 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00002236 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00002237
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002238 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00002239 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002240
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00002241 if (!WIFEXITED(alt_spell_status) ||
2242 WEXITSTATUS(alt_spell_status) != 0) {
Chris Allegretta334a9402002-12-16 04:25:53 +00002243 char *altspell_error = NULL;
2244 char *invoke_error = _("Could not invoke \"%s\"");
David Lawrence Ramseyf3bea022004-12-20 01:18:49 +00002245 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
Chris Allegretta334a9402002-12-16 04:25:53 +00002246
2247 altspell_error = charalloc(msglen);
2248 snprintf(altspell_error, msglen, invoke_error, alt_speller);
2249 return altspell_error;
2250 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002251
Chris Allegretta8f6c0692000-07-19 01:16:18 +00002252 refresh();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002253
David Lawrence Ramsey439fbe32004-10-16 04:56:34 +00002254 /* Restore the terminal to its previous state. */
2255 terminal_init();
2256
David Lawrence Ramsey2d825ba2005-03-20 21:20:47 +00002257 /* Turn the cursor back on for sure. */
2258 curs_set(1);
2259
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002260#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002261 if (old_mark_set) {
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00002262 size_t part_totsize;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002263
2264 /* If the mark was on, partition the filestruct so that it
2265 * contains only the marked text, and keep track of whether the
2266 * temp file (which should contain the spell-checked marked
2267 * text) will have a magicline added when it's reloaded. */
2268 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002269 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002270 filepart = partition_filestruct(top, top_x, bot, bot_x);
2271 added_magicline = (filebot->data[0] != '\0');
2272
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002273 /* Get the number of characters in the marked text, and subtract
2274 * it from the saved value of totsize. Note that we don't need
2275 * to save totlines. */
2276 get_totals(top, bot, NULL, &part_totsize);
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00002277 totsize_save -= part_totsize;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002278 }
2279#endif
2280
2281 /* Reinitialize the filestruct. */
2282 free_filestruct(fileage);
2283 global_init(TRUE);
2284
2285 /* Reload the temp file. Do what load_buffer() would do, except for
2286 * making a new buffer for the temp file if multibuffer support is
2287 * available. */
2288 open_file(tempfile_name, FALSE, &f);
2289 read_file(f, tempfile_name);
2290 current = fileage;
2291
2292#ifndef NANO_SMALL
2293 if (old_mark_set) {
David Lawrence Ramsey15398372004-11-05 15:03:12 +00002294 filestruct *top_save = fileage;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002295
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00002296 /* If the mark was on and we added a magicline, remove it
2297 * now. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002298 if (added_magicline)
2299 remove_magicline();
2300
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002301 /* Put the beginning and the end of the mark at the beginning
2302 * and the end of the spell-checked text. */
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002303 if (fileage == filebot)
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002304 bot_x += top_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002305 if (right_side_up) {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002306 mark_beginx = top_x;
2307 current_x_save = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002308 } else {
David Lawrence Ramseyf6159042004-11-17 20:47:14 +00002309 current_x_save = top_x;
2310 mark_beginx = bot_x;
David Lawrence Ramseybde3e0e2004-11-06 02:37:25 +00002311 }
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002312
David Lawrence Ramsey56cf0342004-11-15 18:44:30 +00002313 /* Unpartition the filestruct so that it contains all the text
2314 * again. Note that we've replaced the marked text originally
2315 * in the partition with the spell-checked marked text in the
2316 * temp file. */
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00002317 unpartition_filestruct(&filepart);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002318
2319 /* Renumber starting with the beginning line of the old
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002320 * partition. Also set totlines to the new number of lines in
2321 * the file, add the number of characters in the spell-checked
2322 * marked text to the saved value of totsize, and then make that
2323 * saved value the actual value. */
David Lawrence Ramsey15398372004-11-05 15:03:12 +00002324 renumber(top_save);
David Lawrence Ramsey3f358642004-11-22 16:04:18 +00002325 totlines = filebot->lineno;
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00002326 totsize_save += totsize;
2327 totsize = totsize_save;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002328
2329 /* Assign mark_beginbuf to the line where the mark began
2330 * before. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002331 do_gotopos(mbb_lineno_save, mark_beginx, current_y_save, 0);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002332 mark_beginbuf = current;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002333
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002334 /* Assign mark_beginx to the location in mark_beginbuf where the
2335 * mark began before, adjusted for any shortening of the
2336 * line. */
2337 mark_beginx = current_x;
2338
2339 /* Turn the mark back on. */
2340 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002341 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002342#endif
2343
David Lawrence Ramseyad114602005-04-16 18:27:57 +00002344 /* Go back to the old position, mark the file as modified, and
2345 * update the titlebar. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002346 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
David Lawrence Ramseyad114602005-04-16 18:27:57 +00002347 SET(MODIFIED);
Chris Allegrettae1f14522001-09-19 03:19:43 +00002348 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002349
Chris Allegretta334a9402002-12-16 04:25:53 +00002350 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002351}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002352
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002353void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002354{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002355 int i;
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00002356 char *temp = safe_tempnam();
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002357 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002358
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002359 if (temp == NULL) {
2360 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002361 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00002362 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002363
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002364#ifndef NANO_SMALL
2365 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002366 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002367 else
2368#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002369 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002370
2371 if (i == -1) {
David Lawrence Ramsey95e39e52004-08-12 02:52:14 +00002372 statusbar(_("Error writing temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00002373 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002374 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00002375 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002376
Chris Allegrettae1f14522001-09-19 03:19:43 +00002377#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002378 /* Update the current open_files entry before spell-checking, in
2379 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002380 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00002381#endif
2382
David Lawrence Ramseyffda7042005-04-14 17:08:35 +00002383 spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) :
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002384 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002385 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00002386 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002387
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002388 if (spell_msg != NULL)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002389 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2390 strerror(errno));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002391 else
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002392 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00002393}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002394#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002395
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002396#if !defined(DISABLE_HELP) || !defined(DISABLE_JUSTIFY) || !defined(DISABLE_WRAPPING)
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002397/* We are trying to break a chunk off line. We find the last blank such
2398 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002399 * such blank, then we find the first blank. We then take the last
2400 * blank in that group of blanks. The terminating '\0' counts as a
2401 * blank, as does a '\n' if newline is TRUE. */
2402ssize_t break_line(const char *line, ssize_t goal, bool newline)
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002403{
2404 ssize_t blank_loc = -1;
2405 /* Current tentative return value. Index of the last blank we
2406 * found with short enough display width. */
2407 ssize_t cur_loc = 0;
2408 /* Current index in line. */
2409 int line_len;
2410
2411 assert(line != NULL);
2412
2413 while (*line != '\0' && goal >= 0) {
2414 size_t pos = 0;
2415
2416 line_len = parse_mbchar(line, NULL, NULL, &pos);
2417
2418 if (is_blank_mbchar(line) || (newline && *line == '\n')) {
2419 blank_loc = cur_loc;
2420
2421 if (newline && *line == '\n')
2422 break;
2423 }
2424
2425 goal -= pos;
2426 line += line_len;
2427 cur_loc += line_len;
2428 }
2429
2430 if (goal >= 0)
2431 /* In fact, the whole line displays shorter than goal. */
2432 return cur_loc;
2433
2434 if (blank_loc == -1) {
2435 /* No blank was found that was short enough. */
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002436 bool found_blank = FALSE;
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002437
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002438 while (*line != '\0') {
2439 line_len = parse_mbchar(line, NULL, NULL, NULL);
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002440
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002441 if (is_blank_mbchar(line) || (newline && *line == '\n')) {
2442 if (!found_blank)
2443 found_blank = TRUE;
2444 } else if (found_blank)
2445 return cur_loc - line_len;
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002446
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002447 line += line_len;
2448 cur_loc += line_len;
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002449 }
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002450
2451 return -1;
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002452 }
2453
2454 /* Move to the last blank after blank_loc, if there is one. */
2455 line -= cur_loc;
2456 line += blank_loc;
2457 line_len = parse_mbchar(line, NULL, NULL, NULL);
2458 line += line_len;
2459
2460 while (*line != '\0' && (is_blank_mbchar(line) ||
2461 (newline && *line == '\n'))) {
2462 line_len = parse_mbchar(line, NULL, NULL, NULL);
2463
2464 line += line_len;
2465 blank_loc += line_len;
2466 }
2467
2468 return blank_loc;
2469}
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00002470#endif /* !DISABLE_HELP || !DISABLE_JUSTIFY || !DISABLE_WRAPPING */
David Lawrence Ramsey9bd56202005-03-18 21:29:33 +00002471
David Lawrence Ramseyd44a0052005-03-18 05:20:54 +00002472#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00002473/* The "indentation" of a line is the whitespace between the quote part
2474 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002475size_t indent_length(const char *line)
2476{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002477 size_t len = 0;
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00002478 char *blank_mb;
2479 int blank_mb_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002480
2481 assert(line != NULL);
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00002482
2483 blank_mb = charalloc(mb_cur_max());
2484
2485 while (*line != '\0') {
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00002486 blank_mb_len = parse_mbchar(line, blank_mb, NULL, NULL);
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00002487
2488 if (!is_blank_mbchar(blank_mb))
2489 break;
2490
2491 line += blank_mb_len;
2492 len += blank_mb_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002493 }
David Lawrence Ramsey3eeb8232005-01-31 18:59:30 +00002494
2495 free(blank_mb);
2496
Chris Allegretta6df90f52002-07-19 01:08:59 +00002497 return len;
2498}
David Lawrence Ramseyd44a0052005-03-18 05:20:54 +00002499#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002500
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002501#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyaf40eea2005-03-14 04:31:44 +00002502/* justify_format() replaces blanks with spaces and multiple spaces by 1
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002503 * (except it maintains up to 2 after a character in punct optionally
2504 * followed by a character in brackets, and removes all from the end).
Chris Allegretta6df90f52002-07-19 01:08:59 +00002505 *
David Lawrence Ramsey666644e2005-03-14 20:32:00 +00002506 * justify_format() might make paragraph->data shorter, and change the
2507 * actual pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00002508 *
David Lawrence Ramsey666644e2005-03-14 20:32:00 +00002509 * justify_format() will not look at the first skip characters of
2510 * paragraph. skip should be at most strlen(paragraph->data). The
2511 * character at paragraph[skip + 1] must not be blank. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002512void justify_format(filestruct *paragraph, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002513{
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002514 char *end, *new_end, *new_paragraph_data;
2515 size_t shift = 0;
2516#ifndef NANO_SMALL
2517 size_t mark_shift = 0;
2518#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002519
Chris Allegretta6df90f52002-07-19 01:08:59 +00002520 /* These four asserts are assumptions about the input data. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002521 assert(paragraph != NULL);
2522 assert(paragraph->data != NULL);
2523 assert(skip < strlen(paragraph->data));
2524 assert(!is_blank_char(paragraph->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002525
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002526 end = paragraph->data + skip;
2527 new_paragraph_data = charalloc(strlen(paragraph->data) + 1);
2528 charcpy(new_paragraph_data, paragraph->data, skip);
2529 new_end = new_paragraph_data + skip;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002530
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002531 while (*end != '\0') {
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002532 int end_len;
2533
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002534 /* If this character is blank, make sure that it's a space with
2535 * no blanks after it. */
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002536 if (is_blank_mbchar(end)) {
2537 end_len = parse_mbchar(end, NULL, NULL, NULL);
2538
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002539 *new_end = ' ';
2540 new_end++;
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002541 end += end_len;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002542
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002543 while (*end != '\0' && is_blank_mbchar(end)) {
2544 end_len = parse_mbchar(end, NULL, NULL, NULL);
2545
2546 end += end_len;
2547 shift += end_len;
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002548
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002549#ifndef NANO_SMALL
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002550 /* Keep track of the change in the current line. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002551 if (mark_beginbuf == paragraph &&
2552 mark_beginx >= end - paragraph->data)
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002553 mark_shift += end_len;
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002554#endif
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002555 }
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002556 /* If this character is punctuation optionally followed by a
2557 * bracket and then followed by blanks, make sure there are no
2558 * more than two blanks after it, and make sure that the blanks
2559 * are spaces. */
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002560 } else if (mbstrchr(punct, end) != NULL) {
2561 end_len = parse_mbchar(end, NULL, NULL, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002562
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002563 while (end_len > 0) {
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002564 *new_end = *end;
2565 new_end++;
2566 end++;
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002567 end_len--;
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002568 }
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002569
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002570 if (*end != '\0' && mbstrchr(brackets, end) != NULL) {
2571 end_len = parse_mbchar(end, NULL, NULL, NULL);
2572
2573 while (end_len > 0) {
2574 *new_end = *end;
2575 new_end++;
2576 end++;
2577 end_len--;
2578 }
2579 }
2580
2581 if (*end != '\0' && is_blank_mbchar(end)) {
2582 end_len = parse_mbchar(end, NULL, NULL, NULL);
2583
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002584 *new_end = ' ';
2585 new_end++;
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002586 end += end_len;
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002587 }
2588
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002589 if (*end != '\0' && is_blank_mbchar(end)) {
2590 end_len = parse_mbchar(end, NULL, NULL, NULL);
2591
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002592 *new_end = ' ';
2593 new_end++;
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002594 end += end_len;
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002595 }
2596
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002597 while (*end != '\0' && is_blank_mbchar(end)) {
2598 end_len = parse_mbchar(end, NULL, NULL, NULL);
2599
2600 end += end_len;
2601 shift += end_len;
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002602
2603#ifndef NANO_SMALL
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002604 /* Keep track of the change in the current line. */
2605 if (mark_beginbuf == paragraph &&
2606 mark_beginx >= end - paragraph->data)
2607 mark_shift += end_len;
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002608#endif
2609 }
2610 /* If this character is neither blank nor punctuation, leave it
2611 * alone. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612 } else {
David Lawrence Ramsey38156d42005-03-15 05:44:03 +00002613 end_len = parse_mbchar(end, NULL, NULL, NULL);
2614
2615 while (end_len > 0) {
2616 *new_end = *end;
2617 new_end++;
2618 end++;
2619 end_len--;
2620 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002621 }
2622 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002623
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002624 assert(*end == '\0');
David Lawrence Ramsey7e110bd2005-03-01 23:21:21 +00002625
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002626 *new_end = *end;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002627
David Lawrence Ramsey15540052005-03-14 20:06:23 +00002628 /* Make sure that there are no spaces at the end of the line. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002629 while (new_end > new_paragraph_data + skip &&
2630 *(new_end - 1) == ' ') {
2631 new_end--;
2632 shift++;
2633 }
2634
2635 if (shift > 0) {
2636 totsize -= shift;
2637 null_at(&new_paragraph_data, new_end - new_paragraph_data);
2638 free(paragraph->data);
2639 paragraph->data = new_paragraph_data;
2640
Chris Allegretta6df90f52002-07-19 01:08:59 +00002641#ifndef NANO_SMALL
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002642 /* Adjust the mark coordinates to compensate for the change in
2643 * the current line. */
2644 if (mark_beginbuf == paragraph) {
2645 mark_beginx -= mark_shift;
2646 if (mark_beginx > new_end - new_paragraph_data)
2647 mark_beginx = new_end - new_paragraph_data;
2648 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002649#endif
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00002650 } else
2651 free(new_paragraph_data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002652}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002653
2654/* The "quote part" of a line is the largest initial substring matching
2655 * the quote string. This function returns the length of the quote part
2656 * of the given line.
2657 *
2658 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2659 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002660size_t quote_length(const char *line)
2661{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002662#ifdef HAVE_REGEX_H
2663 regmatch_t matches;
2664 int rc = regexec(&quotereg, line, 1, &matches, 0);
2665
2666 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
2667 return 0;
2668 /* matches.rm_so should be 0, since the quote string should start
2669 * with the caret ^. */
2670 return matches.rm_eo;
2671#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002672 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002673
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00002674 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002675 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002676 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002677 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002678#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002679}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002680
Chris Allegretta6df90f52002-07-19 01:08:59 +00002681/* a_line and b_line are lines of text. The quotation part of a_line is
2682 * the first a_quote characters. Check that the quotation part of
2683 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002684bool quotes_match(const char *a_line, size_t a_quote, const char
2685 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002686{
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00002687 /* Here is the assumption about a_quote. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002688 assert(a_quote == quote_length(a_line));
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00002689
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00002690 return (a_quote == quote_length(b_line) &&
2691 strncmp(a_line, b_line, a_quote) == 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002692}
2693
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002694/* We assume a_line and b_line have no quote part. Then, we return
2695 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002696bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002697 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002698{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002699 assert(a_indent == indent_length(a_line));
2700 assert(b_indent == indent_length(b_line));
2701
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00002702 return (b_indent <= a_indent &&
2703 strncmp(a_line, b_line, b_indent) == 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002704}
2705
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002706/* Is foo the beginning of a paragraph?
2707 *
2708 * A line of text consists of a "quote part", followed by an
2709 * "indentation part", followed by text. The functions quote_length()
2710 * and indent_length() calculate these parts.
2711 *
2712 * A line is "part of a paragraph" if it has a part not in the quote
2713 * part or the indentation.
2714 *
2715 * A line is "the beginning of a paragraph" if it is part of a
2716 * paragraph and
2717 * 1) it is the top line of the file, or
2718 * 2) the line above it is not part of a paragraph, or
2719 * 3) the line above it does not have precisely the same quote
2720 * part, or
2721 * 4) the indentation of this line is not an initial substring of
2722 * the indentation of the previous line, or
2723 * 5) this line has no quote part and some indentation, and
David Lawrence Ramsey8d0d3ab2005-03-13 16:42:36 +00002724 * autoindent isn't turned on.
2725 * The reason for number 5) is that if autoindent isn't turned on,
2726 * then an indented line is expected to start a paragraph, as in
2727 * books. Thus, nano can justify an indented paragraph only if
2728 * autoindent is turned on. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002729bool begpar(const filestruct *const foo)
2730{
2731 size_t quote_len;
2732 size_t indent_len;
2733 size_t temp_id_len;
2734
2735 /* Case 1). */
2736 if (foo->prev == NULL)
2737 return TRUE;
2738
2739 quote_len = quote_length(foo->data);
2740 indent_len = indent_length(foo->data + quote_len);
2741
2742 /* Not part of a paragraph. */
2743 if (foo->data[quote_len + indent_len] == '\0')
2744 return FALSE;
2745
2746 /* Case 3). */
2747 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2748 return TRUE;
2749
2750 temp_id_len = indent_length(foo->prev->data + quote_len);
2751
2752 /* Case 2) or 5) or 4). */
2753 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2754 (quote_len == 0 && indent_len > 0
2755#ifndef NANO_SMALL
2756 && !ISSET(AUTOINDENT)
2757#endif
2758 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2759 foo->data + quote_len, indent_len))
2760 return TRUE;
2761
2762 return FALSE;
2763}
2764
2765/* We find the last beginning-of-paragraph line before the current
2766 * line. */
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002767void do_para_begin(bool allow_update)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002768{
David Lawrence Ramsey52e5f232005-01-14 21:26:38 +00002769 const filestruct *current_save = current;
2770 const size_t pww_save = placewewant;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002771
2772 current_x = 0;
2773 placewewant = 0;
2774
2775 if (current->prev != NULL) {
2776 do {
2777 current = current->prev;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002778 current_y--;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002779 } while (!begpar(current));
2780 }
2781
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002782 if (allow_update)
2783 edit_redraw(current_save, pww_save);
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002784}
2785
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002786void do_para_begin_void(void)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002787{
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002788 do_para_begin(TRUE);
2789}
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002790
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002791/* Is foo inside a paragraph? */
2792bool inpar(const filestruct *const foo)
2793{
2794 size_t quote_len;
2795
2796 if (foo == NULL)
2797 return FALSE;
2798
2799 quote_len = quote_length(foo->data);
2800
2801 return foo->data[quote_len + indent_length(foo->data +
2802 quote_len)] != '\0';
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002803}
2804
2805/* A line is the last line of a paragraph if it is in a paragraph, and
2806 * the next line isn't, or is the beginning of a paragraph. We move
2807 * down to the end of a paragraph, then one line farther. */
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002808void do_para_end(bool allow_update)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002809{
David Lawrence Ramsey52e5f232005-01-14 21:26:38 +00002810 const filestruct *const current_save = current;
2811 const size_t pww_save = placewewant;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002812
2813 current_x = 0;
2814 placewewant = 0;
2815
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002816 while (current->next != NULL && !inpar(current))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002817 current = current->next;
2818
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002819 while (current->next != NULL && inpar(current->next) &&
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002820 !begpar(current->next)) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002821 current = current->next;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002822 current_y++;
2823 }
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002824
2825 if (current->next != NULL)
2826 current = current->next;
2827
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002828 if (allow_update)
2829 edit_redraw(current_save, pww_save);
2830}
2831
2832void do_para_end_void(void)
2833{
2834 do_para_end(TRUE);
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002835}
2836
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002837/* Put the next par_len lines, starting with first_line, into the
2838 * justify buffer, leaving copies of those lines in place. Assume there
2839 * are enough lines after first_line. Return the new copy of
2840 * first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002841filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2842 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002843{
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002844 filestruct *top = first_line;
2845 /* The top of the paragraph we're backing up. */
2846 filestruct *bot = first_line;
2847 /* The bottom of the paragraph we're backing up. */
2848 size_t i;
2849 /* Generic loop variable. */
2850 size_t current_x_save = current_x;
2851 int fl_lineno_save = first_line->lineno;
2852 int edittop_lineno_save = edittop->lineno;
2853 int current_lineno_save = current->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002854#ifndef NANO_SMALL
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002855 bool old_mark_set = ISSET(MARK_ISSET);
2856 int mbb_lineno_save = 0;
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00002857 size_t mark_beginx_save = 0;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002858
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00002859 if (old_mark_set) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002860 mbb_lineno_save = mark_beginbuf->lineno;
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00002861 mark_beginx_save = mark_beginx;
2862 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002863#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002864
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002865 /* Move bot down par_len lines to the newline after the last line of
2866 * the paragraph. */
2867 for (i = par_len; i > 0; i--)
2868 bot = bot->next;
2869
2870 /* Move the paragraph from the main filestruct to the justify
2871 * buffer. */
2872 move_to_filestruct(&jusbuffer, &jusbottom, top, 0, bot, 0);
2873
2874 /* Copy the paragraph from the justify buffer to the main
2875 * filestruct. */
2876 copy_from_filestruct(jusbuffer, jusbottom);
2877
2878 /* Move upward from the last line of the paragraph to the first
2879 * line, putting first_line, edittop, current, and mark_beginbuf at
2880 * the same lines in the copied paragraph that they had in the
2881 * original paragraph. */
2882 top = current->prev;
2883 for (i = par_len; i > 0; i--) {
2884 if (top->lineno == fl_lineno_save)
2885 first_line = top;
2886 if (top->lineno == edittop_lineno_save)
2887 edittop = top;
2888 if (top->lineno == current_lineno_save)
2889 current = top;
2890#ifndef NANO_SMALL
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00002891 if (old_mark_set && top->lineno == mbb_lineno_save) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002892 mark_beginbuf = top;
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00002893 mark_beginx = mark_beginx_save;
2894 }
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002895#endif
2896 top = top->prev;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002897 }
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002898
2899 /* Put current_x at the same place in the copied paragraph that it
2900 * had in the original paragraph. */
2901 current_x = current_x_save;
2902
2903 set_modified();
2904
Chris Allegretta6df90f52002-07-19 01:08:59 +00002905 return first_line;
2906}
2907
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002908/* Find the beginning of the current paragraph if we're in one, or the
2909 * beginning of the next paragraph if we're not. Afterwards, save the
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002910 * quote length and paragraph length in *quote and *par. Return TRUE if
2911 * we found a paragraph, or FALSE if there was an error or we didn't
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002912 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002913 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002914 * See the comment at begpar() for more about when a line is the
2915 * beginning of a paragraph. */
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002916bool find_paragraph(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002917{
2918 size_t quote_len;
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002919 /* Length of the initial quotation of the paragraph we search
2920 * for. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002921 size_t par_len;
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002922 /* Number of lines in the paragraph we search for. */
2923 filestruct *current_save;
2924 /* The line at the beginning of the paragraph we search for. */
2925 size_t current_y_save;
2926 /* The y-coordinate at the beginning of the paragraph we search
2927 * for. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002928
2929#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002930 if (quoterc != 0) {
2931 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002932 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002933 }
2934#endif
2935
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002936 assert(current != NULL);
2937
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002938 /* Move back to the beginning of the current line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002939 current_x = 0;
2940
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002941 /* Find the first line of the current or next paragraph. First, if
2942 * the current line isn't in a paragraph, move forward to the line
David Lawrence Ramsey6b94e952005-03-22 01:53:57 +00002943 * after the last line of the next paragraph. If we end up on the
2944 * same line, or the line before that isn't in a paragraph, it means
2945 * that there aren't any paragraphs left, so get out. Otherwise,
2946 * move back to the last line of the paragraph. If the current line
2947 * is in a paragraph and it isn't the first line of that paragraph,
2948 * move back to the first line. */
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002949 if (!inpar(current)) {
David Lawrence Ramseyfd81a712005-03-17 04:24:12 +00002950 filestruct *current_save = current;
2951
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002952 do_para_end(FALSE);
David Lawrence Ramseyfd81a712005-03-17 04:24:12 +00002953 if (current == current_save || !inpar(current->prev))
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002954 return FALSE;
David Lawrence Ramsey6b94e952005-03-22 01:53:57 +00002955 if (current->prev != NULL)
2956 current = current->prev;
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002957 }
2958 if (!begpar(current))
2959 do_para_begin(FALSE);
2960
2961 /* Now current is the first line of the paragraph. Set quote_len to
2962 * the quotation length of that line, and set par_len to the number
2963 * of lines in this paragraph. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002964 quote_len = quote_length(current->data);
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002965 current_save = current;
2966 current_y_save = current_y;
2967 do_para_end(FALSE);
2968 par_len = current->lineno - current_save->lineno;
2969 current = current_save;
2970 current_y = current_y_save;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002971
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002972 /* Save the values of quote_len and par_len. */
2973 assert(quote != NULL && par != NULL);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +00002974
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002975 *quote = quote_len;
2976 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002977
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00002978 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002979}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002980
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002981/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2982 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002983void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002984{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002985 filestruct *first_par_line = NULL;
2986 /* Will be the first line of the resulting justified paragraph.
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002987 * For restoring after unjustify. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002988 filestruct *last_par_line;
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00002989 /* Will be the line containing the newline after the last line
2990 * of the result. Also for restoring after unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002991
2992 /* We save these global variables to be restored if the user
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002993 * unjustifies. Note that we don't need to save totlines. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00002994 size_t current_x_save = current_x;
2995 int current_y_save = current_y;
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00002996 unsigned long flags_save = flags;
2997 size_t totsize_save = totsize;
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002998 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002999#ifndef NANO_SMALL
3000 filestruct *mark_beginbuf_save = mark_beginbuf;
David Lawrence Ramsey687776b2004-10-30 01:16:08 +00003001 size_t mark_beginx_save = mark_beginx;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003002#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003003 int kbinput;
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003004 bool meta_key, func_key, s_or_t, ran_func, finished;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003005
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00003006 /* If we're justifying the entire file, start at the beginning. */
3007 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003008 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00003009
3010 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00003011
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003012 while (TRUE) {
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003013 size_t i;
3014 /* Generic loop variable. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003015 size_t quote_len;
3016 /* Length of the initial quotation of the paragraph we
3017 * justify. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003018 size_t indent_len;
3019 /* Length of the initial indentation of the paragraph we
3020 * justify. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003021 size_t par_len;
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003022 /* Number of lines in the paragraph we justify. */
3023 ssize_t break_pos;
3024 /* Where we will break lines. */
David Lawrence Ramsey27f2b252005-03-17 05:08:15 +00003025 char *indent_string;
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003026 /* The first indentation that doesn't match the initial
3027 * indentation of the paragraph we justify. This is put at
3028 * the beginning of every line broken off the first
David Lawrence Ramsey9ec5db82005-03-13 20:39:33 +00003029 * justified line of the paragraph. (Note that this works
3030 * because a paragraph can only contain two indentations at
3031 * most: the initial one, and a different one starting on a
3032 * line after the first. See the comment at begpar() for
3033 * more about when a line is part of a paragraph.) */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003034
3035 /* Find the first line of the paragraph to be justified. That
3036 * is the start of this paragraph if we're in one, or the start
3037 * of the next otherwise. Save the quote length and paragraph
David Lawrence Ramsey68ebb612004-12-04 17:36:14 +00003038 * length (number of lines). Don't refresh the screen yet,
David Lawrence Ramsey102d01d2005-03-17 04:48:14 +00003039 * since we'll do that after we justify.
3040 *
3041 * If the search failed, we do one of two things. If we're
3042 * justifying the whole file, we've found at least one
3043 * paragraph, and the search didn't leave us on the last line of
3044 * the file, it means that we should justify all the way to the
3045 * last line of the file, so set the last line of the text to be
3046 * justified to the last line of the file and break out of the
3047 * loop. Otherwise, it means that there are no paragraph(s) to
3048 * justify, so refresh the screen and get out. */
David Lawrence Ramseyff4a4872005-03-13 21:12:25 +00003049 if (!find_paragraph(&quote_len, &par_len)) {
David Lawrence Ramsey102d01d2005-03-17 04:48:14 +00003050 if (full_justify && first_par_line != NULL &&
3051 first_par_line != filebot) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003052 last_par_line = filebot;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003053 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003054 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003055 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003056 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003057 }
3058 }
3059
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003060 /* If we haven't already done it, copy the original paragraph(s)
3061 * to the justify buffer. */
3062 if (first_par_line == NULL)
3063 first_par_line = backup_lines(current, full_justify ?
3064 filebot->lineno - current->lineno : par_len, quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003065
David Lawrence Ramsey27f2b252005-03-17 05:08:15 +00003066 /* Initialize indent_string to a blank string. */
3067 indent_string = mallocstrcpy(NULL, "");
3068
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003069 /* Find the first indentation in the paragraph that doesn't
3070 * match the indentation of the first line, and save it in
3071 * indent_string. If all the indentations are the same, save
3072 * the indentation of the first line in indent_string. */
3073 {
3074 const filestruct *indent_line = current;
3075 bool past_first_line = FALSE;
3076
3077 for (i = 0; i < par_len; i++) {
David Lawrence Ramsey7f9ed902005-03-13 16:05:47 +00003078 indent_len = quote_len +
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003079 indent_length(indent_line->data + quote_len);
3080
3081 if (indent_len != strlen(indent_string)) {
3082 indent_string = mallocstrncpy(indent_string,
3083 indent_line->data, indent_len + 1);
3084 indent_string[indent_len] = '\0';
3085
3086 if (past_first_line)
3087 break;
3088 }
3089
3090 if (indent_line == current)
3091 past_first_line = TRUE;
3092
3093 indent_line = indent_line->next;
3094 }
3095 }
3096
3097 /* Now tack all the lines of the paragraph together, skipping
3098 * the quoting and indentation on all lines after the first. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003099 for (i = 0; i < par_len - 1; i++) {
3100 filestruct *next_line = current->next;
3101 size_t line_len = strlen(current->data);
3102 size_t next_line_len = strlen(current->next->data);
3103
3104 indent_len = quote_len + indent_length(current->next->data +
3105 quote_len);
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003106
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003107 next_line_len -= indent_len;
3108 totsize -= indent_len;
3109
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003110 /* We're just about to tack the next line onto this one. If
David Lawrence Ramseyd44a0052005-03-18 05:20:54 +00003111 * this line isn't empty, make sure it ends in a space. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003112 if (line_len > 0 && current->data[line_len - 1] != ' ') {
3113 line_len++;
3114 current->data = charealloc(current->data, line_len + 1);
3115 current->data[line_len - 1] = ' ';
3116 current->data[line_len] = '\0';
3117 totsize++;
3118 }
3119
3120 current->data = charealloc(current->data, line_len +
3121 next_line_len + 1);
3122 strcat(current->data, next_line->data + indent_len);
3123
3124 /* Don't destroy edittop! */
3125 if (edittop == next_line)
3126 edittop = current;
3127
3128#ifndef NANO_SMALL
3129 /* Adjust the mark coordinates to compensate for the change
3130 * in the next line. */
3131 if (mark_beginbuf == next_line) {
3132 mark_beginbuf = current;
David Lawrence Ramsey7f9ed902005-03-13 16:05:47 +00003133 mark_beginx += line_len - indent_len;
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003134 }
3135#endif
3136
3137 unlink_node(next_line);
3138 delete_node(next_line);
3139
3140 /* If we've removed the next line, we need to go through
3141 * this line again. */
3142 i--;
3143
3144 par_len--;
3145 totlines--;
3146 totsize--;
3147 }
3148
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003149 /* Call justify_format() on the paragraph, which will remove
3150 * excess spaces from it and change all blank characters to
3151 * spaces. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003152 justify_format(current, quote_len +
3153 indent_length(current->data + quote_len));
3154
3155 while (par_len > 0 && strlenpt(current->data) > fill) {
3156 size_t line_len = strlen(current->data);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00003157
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003158 indent_len = strlen(indent_string);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003159
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003160 /* If this line is too long, try to wrap it to the next line
3161 * to make it short enough. */
3162 break_pos = break_line(current->data + indent_len,
David Lawrence Ramsey40e211b2005-03-19 21:15:30 +00003163 fill - strnlenpt(current->data, indent_len), FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003164
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003165 /* We can't break the line, or don't need to, so get out. */
3166 if (break_pos == -1 || break_pos + indent_len == line_len)
3167 break;
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00003168
David Lawrence Ramseya853e2d2005-03-22 02:17:36 +00003169 /* Move forward to the character after the indentation and
3170 * just after the space. */
3171 break_pos += indent_len + 1;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003172
David Lawrence Ramseya853e2d2005-03-22 02:17:36 +00003173 assert(break_pos <= line_len);
David Lawrence Ramsey65ef1662005-02-25 20:21:45 +00003174
David Lawrence Ramseyaad85152005-03-22 01:25:34 +00003175 /* Make a new line, and copy the text after where we're
3176 * going to break this line to the beginning of the new
3177 * line. */
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003178 splice_node(current, make_new_node(current), current->next);
David Lawrence Ramsey65ef1662005-02-25 20:21:45 +00003179
David Lawrence Ramsey72539292005-03-13 06:03:33 +00003180 /* If this paragraph is non-quoted, and autoindent isn't
3181 * turned on, set the indentation length to zero so that the
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003182 * indentation is treated as part of the line. */
3183 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003184#ifndef NANO_SMALL
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003185 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003186#endif
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003187 )
3188 indent_len = 0;
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +00003189
David Lawrence Ramseya853e2d2005-03-22 02:17:36 +00003190 /* Copy the text after where we're going to break the
3191 * current line to the next line. */
3192 current->next->data = charalloc(indent_len + 1 + line_len -
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003193 break_pos);
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003194 charcpy(current->next->data, indent_string, indent_len);
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003195 strcpy(current->next->data + indent_len, current->data +
David Lawrence Ramseya853e2d2005-03-22 02:17:36 +00003196 break_pos);
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +00003197
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003198 par_len++;
3199 totlines++;
David Lawrence Ramseyaad85152005-03-22 01:25:34 +00003200 totsize += indent_len + 1;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003201
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003202#ifndef NANO_SMALL
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003203 /* Adjust the mark coordinates to compensate for the change
3204 * in the current line. */
3205 if (mark_beginbuf == current && mark_beginx > break_pos) {
3206 mark_beginbuf = current->next;
David Lawrence Ramseya853e2d2005-03-22 02:17:36 +00003207 mark_beginx -= break_pos - indent_len;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00003208 }
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003209#endif
3210
David Lawrence Ramseya853e2d2005-03-22 02:17:36 +00003211 /* Break the current line. */
3212 null_at(&current->data, break_pos);
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003213
3214 /* Go to the next line. */
3215 par_len--;
3216 current_y++;
3217 current = current->next;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003218 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003219
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003220 /* We're done breaking lines, so we don't need indent_string
3221 * anymore. */
3222 free(indent_string);
David Lawrence Ramsey96b21be2005-03-13 15:48:36 +00003223
David Lawrence Ramseye9ac1d72005-03-13 03:28:37 +00003224 /* Go to the next line, the line after the last line of the
3225 * paragraph. */
3226 current_y++;
3227 current = current->next;
3228
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00003229 /* We've just justified a paragraph. If we're not justifying the
3230 * entire file, break out of the loop. Otherwise, continue the
3231 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003232 if (!full_justify)
3233 break;
David Lawrence Ramsey59fe7582005-03-12 20:29:22 +00003234 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00003235
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00003236 /* We are now done justifying the paragraph or the file, so clean
3237 * up. totlines, totsize, and current_y have been maintained above.
3238 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00003239 * fileage, and renumber() since edit_refresh() needs the line
3240 * numbers to be right (but only do the last two if we actually
3241 * justified something). */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003242 last_par_line = current;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00003243 if (first_par_line != NULL) {
3244 if (first_par_line->prev == NULL)
3245 fileage = first_par_line;
3246 renumber(first_par_line);
3247 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00003248
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00003249 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00003250
Chris Allegretta9149e612000-11-27 00:23:41 +00003251 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003252
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003253 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003254 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00003255 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00003256
David Lawrence Ramsey63e73cb2004-11-28 04:52:57 +00003257 /* Now get a keystroke and see if it's unjustify. If not, put back
3258 * the keystroke and return. */
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003259 kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func,
3260 &finished, FALSE);
Chris Allegretta5f071802001-05-06 02:34:31 +00003261
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003262 if (!meta_key && !func_key && s_or_t &&
3263 kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003264 /* Restore the justify we just did (ungrateful user!). */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003265 current = current_save;
3266 current_x = current_x_save;
3267 current_y = current_y_save;
3268 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00003269
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003270 /* Splice the justify buffer back into the file, but only if we
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00003271 * actually justified something. */
3272 if (first_par_line != NULL) {
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003273 filestruct *bot_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003274
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003275 /* Partition the filestruct so that it contains only the
3276 * text of the justified paragraph. */
3277 filepart = partition_filestruct(first_par_line, 0,
3278 last_par_line, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00003279
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003280 /* Remove the text of the justified paragraph, and
3281 * put the text in the justify buffer in its place. */
3282 free_filestruct(fileage);
3283 fileage = jusbuffer;
3284 filebot = jusbottom;
3285
3286 bot_save = filebot;
3287
3288 /* Unpartition the filestruct so that it contains all the
3289 * text again. Note that the justified paragraph has been
3290 * replaced with the unjustified paragraph. */
3291 unpartition_filestruct(&filepart);
3292
3293 /* Renumber starting with the ending line of the old
3294 * partition. */
3295 if (bot_save->next != NULL)
3296 renumber(bot_save->next);
3297
3298 /* Restore global variables from before the justify. */
3299 totsize = totsize_save;
3300 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003301#ifndef NANO_SMALL
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003302 mark_beginbuf = mark_beginbuf_save;
3303 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003304#endif
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003305 flags = flags_save;
3306
3307 /* Clear the justify buffer. */
3308 jusbuffer = NULL;
3309
3310 if (!ISSET(MODIFIED))
3311 titlebar(NULL);
3312 edit_refresh();
3313 }
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003314 } else {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003315 unget_kbinput(kbinput, meta_key, func_key);
David Lawrence Ramseyd994ad52004-11-23 21:40:26 +00003316
David Lawrence Ramsey53d3db42004-11-28 03:53:01 +00003317 /* Blow away the text in the justify buffer. */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003318 free_filestruct(jusbuffer);
3319 jusbuffer = NULL;
Chris Allegretta9149e612000-11-27 00:23:41 +00003320 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003321
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00003322 blank_statusbar();
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003323
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003324 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003325 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00003326 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003327}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003328
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003329void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003330{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003331 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003332}
3333
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003334void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003335{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003336 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00003337}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003338#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003339
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003340void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003341{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003342 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00003343
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003344 if (!ISSET(MODIFIED))
3345 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00003346 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003347 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003348 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003349 i = do_yesno(FALSE,
3350 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
3351
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003352#ifdef DEBUG
3353 dump_buffer(fileage);
3354#endif
3355
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003356 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003357#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey3ece0b92004-12-01 15:11:27 +00003358 /* Exit only if there are no more open file buffers. */
David Lawrence Ramsey3e189a82004-10-03 19:18:48 +00003359 if (!close_open_file())
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003360#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00003361 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003362 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003363 statusbar(_("Cancelled"));
3364
3365 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003366}
3367
3368void signal_init(void)
3369{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003370 /* Trap SIGINT and SIGQUIT because we want them to do useful
3371 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003372 memset(&act, 0, sizeof(struct sigaction));
3373 act.sa_handler = SIG_IGN;
3374 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00003375 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003376
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003377 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003378 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003379 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003380 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003381
3382#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003383 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003384 act.sa_handler = handle_sigwinch;
3385 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003386 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003387#endif
3388
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003389 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003390 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003391 act.sa_handler = SIG_IGN;
3392 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003393 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003394 /* Block all other signals in the suspend and continue handlers.
3395 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003396 sigfillset(&act.sa_mask);
3397
3398 act.sa_handler = do_suspend;
3399 sigaction(SIGTSTP, &act, NULL);
3400
3401 act.sa_handler = do_cont;
3402 sigaction(SIGCONT, &act, NULL);
3403 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003404}
3405
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003406/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey50406662005-01-19 19:52:42 +00003407void handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003408{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00003409 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003410}
3411
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003412/* Handler for SIGTSTP (suspend). */
David Lawrence Ramsey50406662005-01-19 19:52:42 +00003413void do_suspend(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003414{
3415 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00003416 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003417 fflush(stdout);
3418
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003419 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003420 tcsetattr(0, TCSANOW, &oldterm);
3421
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00003422 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003423 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00003424 act.sa_handler = handle_hupterm;
3425 sigaction(SIGHUP, &act, NULL);
3426 sigaction(SIGTERM, &act, NULL);
3427
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003428 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003429 kill(0, SIGSTOP);
3430}
3431
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003432/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramsey50406662005-01-19 19:52:42 +00003433void do_cont(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003434{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003435#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003436 /* Perhaps the user resized the window while we slept. Handle it
3437 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003438 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003439#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003440 /* Just update the screen. */
3441 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003442#endif
3443}
3444
3445#ifndef NANO_SMALL
3446void handle_sigwinch(int s)
3447{
3448 const char *tty = ttyname(0);
David Lawrence Ramsey9d691692005-03-08 16:41:53 +00003449 int fd, result = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003450 struct winsize win;
3451
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003452 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003453 return;
3454 fd = open(tty, O_RDWR);
3455 if (fd == -1)
3456 return;
3457 result = ioctl(fd, TIOCGWINSZ, &win);
3458 close(fd);
3459 if (result == -1)
3460 return;
3461
3462 /* Could check whether the COLS or LINES changed, and return
3463 * otherwise. EXCEPT, that COLS and LINES are ncurses global
3464 * variables, and in some cases ncurses has already updated them.
3465 * But not in all cases, argh. */
3466 COLS = win.ws_col;
3467 LINES = win.ws_row;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003468
David Lawrence Ramsey50406662005-01-19 19:52:42 +00003469 check_die_too_small();
3470 resize_variables();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003471
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00003472 /* If we've partitioned the filestruct, unpartition it now. */
3473 if (filepart != NULL)
David Lawrence Ramsey74d87072004-11-22 00:16:23 +00003474 unpartition_filestruct(&filepart);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00003475
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003476#ifndef DISABLE_JUSTIFY
David Lawrence Ramseybc3b9262004-11-23 04:17:19 +00003477 /* If the justify buffer isn't empty, blow away the text in it and
3478 * display the shortcut list with UnCut. */
David Lawrence Ramsey93c84052004-11-23 04:08:28 +00003479 if (jusbuffer != NULL) {
3480 free_filestruct(jusbuffer);
3481 jusbuffer = NULL;
3482 shortcut_init(FALSE);
3483 }
3484#endif
3485
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003486#ifdef USE_SLANG
3487 /* Slang curses emulation brain damage, part 1: If we just do what
3488 * curses does here, it'll only work properly if the resize made the
3489 * window smaller. Do what mutt does: Leave and immediately reenter
3490 * Slang screen management mode. */
3491 SLsmg_reset_smg();
3492 SLsmg_init_smg();
3493#else
3494 /* Do the equivalent of what Minimum Profit does: Leave and
3495 * immediately reenter curses mode. */
3496 endwin();
3497 refresh();
3498#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003499
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003500 /* Restore the terminal to its previous state. */
3501 terminal_init();
3502
David Lawrence Ramsey2d825ba2005-03-20 21:20:47 +00003503 /* Turn the cursor back on for sure. */
3504 curs_set(1);
3505
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003506 /* Do the equivalent of what both mutt and Minimum Profit do:
3507 * Reinitialize all the windows based on the new screen
3508 * dimensions. */
3509 window_init();
3510
David Lawrence Ramsey907725f2004-11-12 00:09:20 +00003511 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003512 blank_statusbar();
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00003513 currshortcut = main_list;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003514 total_refresh();
3515
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00003516 /* Reset all the input routines that rely on character sequences. */
3517 reset_kbinput();
3518
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003519 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003520 siglongjmp(jmpbuf, 1);
3521}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003522
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003523void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003524{
3525 sigset_t winch;
3526 sigemptyset(&winch);
3527 sigaddset(&winch, SIGWINCH);
3528 if (allow)
3529 sigprocmask(SIG_UNBLOCK, &winch, NULL);
3530 else
3531 sigprocmask(SIG_BLOCK, &winch, NULL);
3532}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003533#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003534
Chris Allegrettadab017e2002-04-23 10:56:06 +00003535#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00003536void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00003537{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003538 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00003539
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003540 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00003541
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003542 switch (which->val) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003543#ifndef DISABLE_MOUSE
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003544 case TOGGLE_MOUSE_KEY:
3545 mouse_init();
3546 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003547#endif
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00003548 case TOGGLE_MORESPACE_KEY:
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003549 case TOGGLE_NOHELP_KEY:
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003550 window_init();
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00003551 total_refresh();
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003552 break;
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00003553 case TOGGLE_SUSPEND_KEY:
3554 signal_init();
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003555 break;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003556#ifdef ENABLE_NANORC
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003557 case TOGGLE_WHITESPACE_KEY:
David Lawrence Ramsey846658e2004-12-05 04:18:26 +00003558 titlebar(NULL);
David Lawrence Ramsey62a217d2004-11-27 16:54:00 +00003559 edit_refresh();
3560 break;
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003561#endif
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00003562#ifdef ENABLE_COLOR
3563 case TOGGLE_SYNTAX_KEY:
3564 edit_refresh();
3565 break;
3566#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003567 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003568
Chris Allegretta6df90f52002-07-19 01:08:59 +00003569 /* We are assuming here that shortcut_init() above didn't free and
3570 * reallocate the toggles. */
3571 enabled = ISSET(which->flag);
3572 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3573 enabled = !enabled;
3574 statusbar("%s %s", which->desc,
3575 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003576}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003577#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003578
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003579void disable_extended_input(void)
3580{
3581 struct termios term;
3582
3583 tcgetattr(0, &term);
3584 term.c_lflag &= ~IEXTEN;
3585 tcsetattr(0, TCSANOW, &term);
3586}
3587
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003588void disable_signals(void)
3589{
3590 struct termios term;
3591
3592 tcgetattr(0, &term);
3593 term.c_lflag &= ~ISIG;
3594 tcsetattr(0, TCSANOW, &term);
3595}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003596
3597#ifndef NANO_SMALL
3598void enable_signals(void)
3599{
3600 struct termios term;
3601
3602 tcgetattr(0, &term);
3603 term.c_lflag |= ISIG;
3604 tcsetattr(0, TCSANOW, &term);
3605}
3606#endif
3607
3608void disable_flow_control(void)
3609{
3610 struct termios term;
3611
3612 tcgetattr(0, &term);
3613 term.c_iflag &= ~(IXON|IXOFF);
3614 tcsetattr(0, TCSANOW, &term);
3615}
3616
3617void enable_flow_control(void)
3618{
3619 struct termios term;
3620
3621 tcgetattr(0, &term);
3622 term.c_iflag |= (IXON|IXOFF);
3623 tcsetattr(0, TCSANOW, &term);
3624}
3625
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003626/* Set up the terminal state. Put the terminal in cbreak mode (read one
3627 * character at a time and interpret the special control keys), disable
3628 * translation of carriage return (^M) into newline (^J) so that we can
3629 * tell the difference between the Enter key and Ctrl-J, and disable
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003630 * echoing of characters as they're typed. Finally, disable extended
3631 * input processing, disable interpretation of the special control keys,
3632 * and if we're not in preserve mode, disable interpretation of the flow
3633 * control characters too. */
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003634void terminal_init(void)
3635{
3636 cbreak();
3637 nonl();
3638 noecho();
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003639 disable_extended_input();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003640 disable_signals();
3641 if (!ISSET(PRESERVE))
3642 disable_flow_control();
3643}
3644
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003645int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003646 *ran_func, bool *finished, bool allow_funcs)
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003647{
3648 int input;
3649 /* The character we read in. */
3650 static int *kbinput = NULL;
3651 /* The input buffer. */
3652 static size_t kbinput_len = 0;
3653 /* The length of the input buffer. */
3654 const shortcut *s;
3655 bool have_shortcut;
3656#ifndef NANO_SMALL
3657 const toggle *t;
3658 bool have_toggle;
3659#endif
3660
3661 *s_or_t = FALSE;
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003662 *ran_func = FALSE;
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003663 *finished = FALSE;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003664
3665 /* Read in a character. */
3666 input = get_kbinput(edit, meta_key, func_key);
3667
3668#ifndef DISABLE_MOUSE
3669 /* If we got a mouse click and it was on a shortcut, read in the
3670 * shortcut character. */
David Lawrence Ramseyb8a2a6d2005-01-02 21:13:36 +00003671 if (allow_funcs && *func_key == TRUE && input == KEY_MOUSE) {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003672 if (do_mouse())
3673 input = get_kbinput(edit, meta_key, func_key);
3674 else
3675 input = ERR;
3676 }
3677#endif
3678
3679 /* Check for a shortcut in the main list. */
3680 s = get_shortcut(main_list, &input, meta_key, func_key);
3681
3682 /* If we got a shortcut from the main list, or a "universal"
3683 * edit window shortcut, set have_shortcut to TRUE. */
3684 have_shortcut = (s != NULL || input == NANO_XON_KEY ||
3685 input == NANO_XOFF_KEY || input == NANO_SUSPEND_KEY);
3686
3687#ifndef NANO_SMALL
3688 /* Check for a toggle in the main list. */
3689 t = get_toggle(input, *meta_key);
3690
3691 /* If we got a toggle from the main list, set have_toggle to
3692 * TRUE. */
3693 have_toggle = (t != NULL);
3694#endif
3695
3696 /* Set s_or_t to TRUE if we got a shortcut or toggle. */
3697 *s_or_t = (have_shortcut
3698#ifndef NANO_SMALL
3699 || have_toggle
3700#endif
3701 );
3702
3703 if (allow_funcs) {
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00003704 /* If we got a character, and it isn't a shortcut or toggle,
3705 * it's a normal text character. Display the warning if we're
3706 * in view mode, or add the character to the input buffer if
3707 * we're not. */
3708 if (input != ERR && *s_or_t == FALSE) {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003709 if (ISSET(VIEW_MODE))
3710 print_view_warning();
3711 else {
3712 kbinput_len++;
3713 kbinput = (int *)nrealloc(kbinput, kbinput_len *
3714 sizeof(int));
3715 kbinput[kbinput_len - 1] = input;
3716 }
3717 }
3718
3719 /* If we got a shortcut or toggle, or if there aren't any other
3720 * characters waiting after the one we read in, we need to
3721 * display all the characters in the input buffer if it isn't
3722 * empty. Note that it should be empty if we're in view
3723 * mode. */
3724 if (*s_or_t == TRUE || get_buffer_len() == 0) {
3725 if (kbinput != NULL) {
3726 /* Display all the characters in the input buffer at
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00003727 * once, filtering out control characters. */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003728 char *output = charalloc(kbinput_len + 1);
3729 size_t i;
3730
3731 for (i = 0; i < kbinput_len; i++)
3732 output[i] = (char)kbinput[i];
3733 output[i] = '\0';
3734
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00003735 do_output(output, kbinput_len, FALSE);
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003736
3737 free(output);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003738
3739 /* Empty the input buffer. */
3740 kbinput_len = 0;
3741 free(kbinput);
3742 kbinput = NULL;
3743 }
3744 }
3745
3746 if (have_shortcut) {
3747 switch (input) {
David Lawrence Ramsey775d46d2005-01-11 23:08:36 +00003748 /* Handle the "universal" statusbar prompt shortcuts. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003749 case NANO_XON_KEY:
3750 statusbar(_("XON ignored, mumble mumble."));
3751 break;
3752 case NANO_XOFF_KEY:
3753 statusbar(_("XOFF ignored, mumble mumble."));
3754 break;
3755#ifndef NANO_SMALL
3756 case NANO_SUSPEND_KEY:
3757 if (ISSET(SUSPEND))
3758 do_suspend(0);
3759 break;
3760#endif
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003761 /* Handle the normal edit window shortcuts, setting
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003762 * ran_func to TRUE if we try to run their associated
3763 * functions and setting finished to TRUE to indicate
3764 * that we're done after trying to run their associated
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003765 * functions. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003766 default:
3767 /* Blow away the text in the cutbuffer if we aren't
3768 * cutting text. */
3769 if (s->func != do_cut_text)
3770 cutbuffer_reset();
3771
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00003772 if (s->func != NULL) {
David Lawrence Ramseycac02932005-01-11 23:05:05 +00003773 *ran_func = TRUE;
David Lawrence Ramsey6a2f0682004-12-20 01:13:55 +00003774 if (ISSET(VIEW_MODE) && !s->viewok)
3775 print_view_warning();
3776 else
3777 s->func();
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003778 }
David Lawrence Ramseyc13b7f02005-01-01 07:28:15 +00003779 *finished = TRUE;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003780 break;
3781 }
3782 }
3783#ifndef NANO_SMALL
3784 else if (have_toggle) {
3785 /* Blow away the text in the cutbuffer, since we aren't
3786 * cutting text. */
3787 cutbuffer_reset();
3788 /* Toggle the flag associated with this shortcut. */
3789 if (allow_funcs)
3790 do_toggle(t);
3791 }
3792#endif
3793 else
3794 /* Blow away the text in the cutbuffer, since we aren't
3795 * cutting text. */
3796 cutbuffer_reset();
3797 }
3798
3799 return input;
3800}
3801
3802#ifndef DISABLE_MOUSE
3803bool do_mouse(void)
3804{
3805 int mouse_x, mouse_y;
3806 bool retval;
3807
3808 retval = get_mouseinput(&mouse_x, &mouse_y, TRUE);
3809
3810 if (!retval) {
3811 /* We can click in the edit window to move the cursor. */
3812 if (wenclose(edit, mouse_y, mouse_x)) {
3813 bool sameline;
3814 /* Did they click on the line with the cursor? If they
3815 * clicked on the cursor, we set the mark. */
3816 size_t xcur;
3817 /* The character they clicked on. */
3818
3819 /* Subtract out the size of topwin. Perhaps we need a
3820 * constant somewhere? */
David Lawrence Ramsey7c60eab2005-01-27 06:35:56 +00003821 mouse_y -= (2 - no_more_space());
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003822
3823 sameline = (mouse_y == current_y);
3824
3825 /* Move to where the click occurred. */
3826 for (; current_y < mouse_y && current->next != NULL; current_y++)
3827 current = current->next;
3828 for (; current_y > mouse_y && current->prev != NULL; current_y--)
3829 current = current->prev;
3830
3831 xcur = actual_x(current->data, get_page_start(xplustabs()) +
3832 mouse_x);
3833
3834#ifndef NANO_SMALL
3835 /* Clicking where the cursor is toggles the mark, as does
3836 * clicking beyond the line length with the cursor at the
3837 * end of the line. */
3838 if (sameline && xcur == current_x) {
3839 if (ISSET(VIEW_MODE)) {
3840 print_view_warning();
3841 return retval;
3842 }
3843 do_mark();
3844 }
3845#endif
3846
3847 current_x = xcur;
3848 placewewant = xplustabs();
3849 edit_refresh();
3850 }
3851 }
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003852
3853 return retval;
3854}
3855#endif /* !DISABLE_MOUSE */
3856
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003857/* The user typed kbinput_len multibyte characters. Add them to the
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00003858 * edit buffer, filtering out all control characters if allow_cntrls is
3859 * TRUE. */
3860void do_output(char *output, size_t output_len, bool allow_cntrls)
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003861{
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003862 size_t current_len = strlen(current->data), i = 0;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003863 bool old_constupdate = ISSET(CONSTUPDATE);
3864 bool do_refresh = FALSE;
3865 /* Do we have to call edit_refresh(), or can we get away with
3866 * update_line()? */
3867
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003868 char *char_buf = charalloc(mb_cur_max());
3869 int char_buf_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003870
3871 assert(current != NULL && current->data != NULL);
3872
David Lawrence Ramsey846658e2004-12-05 04:18:26 +00003873 /* Turn off constant cursor position display. */
3874 UNSET(CONSTUPDATE);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003875
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003876 while (i < output_len) {
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00003877 /* If allow_cntrls is FALSE, filter out nulls and newlines,
3878 * since they're control characters. */
3879 if (allow_cntrls) {
3880 /* Null to newline, if needed. */
3881 if (output[i] == '\0')
3882 output[i] = '\n';
3883 /* Newline to Enter, if needed. */
3884 else if (output[i] == '\n') {
3885 do_enter();
3886 i++;
3887 continue;
3888 }
David Lawrence Ramseyabc94232004-12-08 23:24:31 +00003889 }
3890
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003891 /* Interpret the next multibyte character. If it's an invalid
3892 * multibyte character, interpret it as though it's a byte
3893 * character. */
David Lawrence Ramsey1b9d3f92005-02-11 20:09:11 +00003894 char_buf_len = parse_mbchar(output + i, char_buf, NULL, NULL);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003895
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003896 i += char_buf_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003897
David Lawrence Ramseyefec6412005-03-17 03:52:08 +00003898 /* If allow_cntrls is FALSE, filter out a control character. */
3899 if (!allow_cntrls && is_cntrl_mbchar(output + i - char_buf_len))
3900 continue;
3901
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003902 /* When a character is inserted on the current magicline, it
3903 * means we need a new one! */
3904 if (filebot == current)
3905 new_magicline();
3906
3907 /* More dangerousness fun =) */
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003908 current->data = charealloc(current->data, current_len +
3909 (char_buf_len * 2));
David Lawrence Ramsey3e819142004-12-31 04:10:28 +00003910
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003911 assert(current_x <= current_len);
David Lawrence Ramsey3e819142004-12-31 04:10:28 +00003912
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003913 charmove(&current->data[current_x + char_buf_len],
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003914 &current->data[current_x],
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003915 current_len - current_x + char_buf_len);
3916 charcpy(&current->data[current_x], char_buf, char_buf_len);
3917 current_len += char_buf_len;
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00003918 totsize++;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003919 set_modified();
3920
3921#ifndef NANO_SMALL
3922 /* Note that current_x has not yet been incremented. */
3923 if (current == mark_beginbuf && current_x < mark_beginx)
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003924 mark_beginx += char_buf_len;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003925#endif
3926
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00003927 do_right(FALSE);
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003928
3929#ifndef DISABLE_WRAPPING
David Lawrence Ramsey6595b712005-04-26 17:21:47 +00003930 /* If we're wrapping text, we need to call edit_refresh(). */
3931 if (!ISSET(NO_WRAP)) {
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003932 bool do_refresh_save = do_refresh;
3933
3934 do_refresh = do_wrap(current);
3935
3936 /* If we needed to call edit_refresh() before this, we'll
3937 * still need to after this. */
3938 if (do_refresh_save)
3939 do_refresh = TRUE;
3940 }
3941#endif
3942
3943#ifdef ENABLE_COLOR
3944 /* If color syntaxes are turned on, we need to call
3945 * edit_refresh(). */
David Lawrence Ramsey202d3c22005-03-10 20:55:11 +00003946 if (!ISSET(NO_COLOR_SYNTAX))
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003947 do_refresh = TRUE;
3948#endif
3949 }
3950
David Lawrence Ramsey846658e2004-12-05 04:18:26 +00003951 /* Turn constant cursor position display back on if it was on
3952 * before. */
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003953 if (old_constupdate)
3954 SET(CONSTUPDATE);
3955
David Lawrence Ramseyb54155c2005-01-12 03:25:57 +00003956 free(char_buf);
David Lawrence Ramsey78ea5e42004-12-12 19:04:56 +00003957
David Lawrence Ramsey74835712004-12-04 17:41:52 +00003958 if (do_refresh)
3959 edit_refresh();
3960 else
3961 update_line(current, current_x);
3962}
3963
David Lawrence Ramseya27bd652004-08-17 05:23:38 +00003964int main(int argc, char **argv)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003965{
3966 int optchr;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003967 int startline = 0;
3968 /* Line to try and start at. */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003969#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003970 bool fill_flag_used = FALSE;
3971 /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003972#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003973#ifdef ENABLE_MULTIBUFFER
3974 bool old_multibuffer;
3975 /* The old value of the multibuffer option, restored after we
3976 * load all files on the command line. */
3977#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003978#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003979 const struct option long_options[] = {
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003980 {"help", 0, NULL, 'h'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003981#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003982 {"multibuffer", 0, NULL, 'F'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003983#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003984#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003985#ifndef NANO_SMALL
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003986 {"historylog", 0, NULL, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003987#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003988 {"ignorercfiles", 0, NULL, 'I'},
Chris Allegretta6df90f52002-07-19 01:08:59 +00003989#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003990 {"morespace", 0, NULL, 'O'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003991#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003992 {"quotestr", 1, NULL, 'Q'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003993#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003994#ifdef HAVE_REGEX_H
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003995 {"regexp", 0, NULL, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003996#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00003997 {"tabsize", 1, NULL, 'T'},
3998 {"version", 0, NULL, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003999#ifdef ENABLE_COLOR
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004000 {"syntax", 1, NULL, 'Y'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00004001#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004002 {"const", 0, NULL, 'c'},
4003 {"rebinddelete", 0, NULL, 'd'},
4004 {"nofollow", 0, NULL, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00004005#ifndef DISABLE_MOUSE
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004006 {"mouse", 0, NULL, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00004007#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00004008#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004009 {"operatingdir", 1, NULL, 'o'},
Chris Allegrettae1f14522001-09-19 03:19:43 +00004010#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004011 {"preserve", 0, NULL, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00004012#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004013 {"fill", 1, NULL, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00004014#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00004015#ifndef DISABLE_SPELLER
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004016 {"speller", 1, NULL, 's'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00004017#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004018 {"tempfile", 0, NULL, 't'},
4019 {"view", 0, NULL, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00004020#ifndef DISABLE_WRAPPING
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004021 {"nowrap", 0, NULL, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00004022#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004023 {"nohelp", 0, NULL, 'x'},
4024 {"suspend", 0, NULL, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00004025#ifndef NANO_SMALL
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004026 {"smarthome", 0, NULL, 'A'},
4027 {"backup", 0, NULL, 'B'},
4028 {"backupdir", 1, NULL, 'E'},
4029 {"noconvert", 0, NULL, 'N'},
4030 {"smooth", 0, NULL, 'S'},
4031 {"restricted", 0, NULL, 'Z'},
4032 {"autoindent", 0, NULL, 'i'},
4033 {"cut", 0, NULL, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00004034#endif
David Lawrence Ramseyfe605242005-03-26 22:49:08 +00004035 {NULL, 0, NULL, 0}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004036 };
4037#endif
4038
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00004039#ifdef NANO_WIDE
4040 {
4041 /* If the locale set doesn't exist, or it exists but doesn't
David Lawrence Ramseyd456bfa2005-03-18 19:07:25 +00004042 * include the case-insensitive string "UTF8" or "UTF-8", we
4043 * shouldn't go into UTF-8 mode. */
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00004044 char *locale = setlocale(LC_ALL, "");
4045
4046 if (locale == NULL || (locale != NULL &&
David Lawrence Ramseyd456bfa2005-03-18 19:07:25 +00004047 strcasestr(locale, "UTF8") == NULL &&
David Lawrence Ramsey3dd744f2005-03-20 07:26:47 +00004048 strcasestr(locale, "UTF-8") == NULL))
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00004049 SET(NO_UTF8);
David Lawrence Ramseyd15de732005-01-28 19:37:23 +00004050
4051#ifdef USE_SLANG
4052 if (!ISSET(NO_UTF8))
David Lawrence Ramsey800dd182005-03-11 17:46:01 +00004053 SLutf8_enable(TRUE);
David Lawrence Ramseyd15de732005-01-28 19:37:23 +00004054#endif
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00004055 }
4056#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004057 setlocale(LC_ALL, "");
David Lawrence Ramseyfc693212004-12-23 17:43:27 +00004058#endif
4059
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00004060#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004061 bindtextdomain(PACKAGE, LOCALEDIR);
4062 textdomain(PACKAGE);
4063#endif
4064
Chris Allegretta7662c862003-01-13 01:35:15 +00004065#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004066 /* If we don't have rcfile support, we're root, and
4067 * --disable-wrapping-as-root is used, turn wrapping off. */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00004068 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00004069 SET(NO_WRAP);
4070#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00004071
Chris Allegretta6df90f52002-07-19 01:08:59 +00004072 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004073#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00004074 getopt_long(argc, argv, "h?ABE:FHINOQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004075#else
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00004076 getopt(argc, argv, "h?ABE:FHINOQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004077#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004078 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004079
4080 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004081 case 'a':
4082 case 'b':
4083 case 'e':
4084 case 'f':
4085 case 'g':
4086 case 'j':
4087 /* Pico compatibility flags. */
4088 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00004089#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004090 case 'A':
4091 SET(SMART_HOME);
4092 break;
4093 case 'B':
4094 SET(BACKUP_FILE);
4095 break;
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004096 case 'E':
4097 backup_dir = mallocstrcpy(backup_dir, optarg);
4098 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00004099#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00004100#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004101 case 'F':
4102 SET(MULTIBUFFER);
4103 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00004104#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00004105#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00004106#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004107 case 'H':
4108 SET(HISTORYLOG);
4109 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00004110#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004111 case 'I':
4112 SET(NO_RCFILE);
4113 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00004114#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00004115#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004116 case 'N':
4117 SET(NO_CONVERT);
4118 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00004119#endif
David Lawrence Ramsey637b8bb2005-01-17 05:06:55 +00004120 case 'O':
4121 SET(MORE_SPACE);
4122 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00004123#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004124 case 'Q':
4125 quotestr = mallocstrcpy(quotestr, optarg);
4126 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00004127#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00004128#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004129 case 'R':
4130 SET(USE_REGEXP);
4131 break;
Chris Allegretta47805612000-07-07 02:35:34 +00004132#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00004133#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004134 case 'S':
4135 SET(SMOOTHSCROLL);
4136 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00004137#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004138 case 'T':
4139 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00004140 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
4141 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004142 exit(1);
4143 }
4144 break;
4145 case 'V':
4146 version();
4147 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00004148#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004149 case 'Y':
4150 syntaxstr = mallocstrcpy(syntaxstr, optarg);
4151 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00004152#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004153 case 'Z':
4154 SET(RESTRICTED);
4155 break;
4156 case 'c':
4157 SET(CONSTUPDATE);
4158 break;
4159 case 'd':
4160 SET(REBIND_DELETE);
4161 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00004162#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004163 case 'i':
4164 SET(AUTOINDENT);
4165 break;
4166 case 'k':
4167 SET(CUT_TO_END);
4168 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00004169#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004170 case 'l':
4171 SET(NOFOLLOW_SYMLINKS);
4172 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00004173#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004174 case 'm':
4175 SET(USE_MOUSE);
4176 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00004177#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00004178#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004179 case 'o':
4180 operating_dir = mallocstrcpy(operating_dir, optarg);
4181 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00004182#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004183 case 'p':
4184 SET(PRESERVE);
4185 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00004186#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004187 case 'r':
4188 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00004189 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
4190 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004191 exit(1);
4192 }
4193 fill_flag_used = TRUE;
4194 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00004195#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00004196#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004197 case 's':
4198 alt_speller = mallocstrcpy(alt_speller, optarg);
4199 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00004200#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004201 case 't':
4202 SET(TEMP_FILE);
4203 break;
4204 case 'v':
4205 SET(VIEW_MODE);
4206 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00004207#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004208 case 'w':
4209 SET(NO_WRAP);
4210 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00004211#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00004212 case 'x':
4213 SET(NO_HELP);
4214 break;
4215 case 'z':
4216 SET(SUSPEND);
4217 break;
4218 default:
4219 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004220 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004221 }
4222
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004223 /* If the executable filename starts with 'r', we use restricted
4224 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00004225 if (*(tail(argv[0])) == 'r')
4226 SET(RESTRICTED);
4227
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004228 /* If we're using restricted mode, disable suspending, backups, and
4229 * reading rcfiles, since they all would allow reading from or
4230 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00004231 if (ISSET(RESTRICTED)) {
4232 UNSET(SUSPEND);
4233 UNSET(BACKUP_FILE);
4234 SET(NO_RCFILE);
4235 }
4236
Chris Allegretta7662c862003-01-13 01:35:15 +00004237/* We've read through the command line options. Now back up the flags
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004238 * and values that are set, and read the rcfile(s). If the values
4239 * haven't changed afterward, restore the backed-up values. */
Chris Allegretta7662c862003-01-13 01:35:15 +00004240#ifdef ENABLE_NANORC
4241 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00004242#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00004243 char *operating_dir_cpy = operating_dir;
4244#endif
David Lawrence Ramsey7e8dd192004-08-12 20:06:20 +00004245#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00004246 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00004247#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004248#ifndef NANO_SMALL
4249 char *backup_dir_cpy = backup_dir;
4250#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00004251#ifndef DISABLE_JUSTIFY
4252 char *quotestr_cpy = quotestr;
4253#endif
4254#ifndef DISABLE_SPELLER
4255 char *alt_speller_cpy = alt_speller;
4256#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00004257 ssize_t tabsize_cpy = tabsize;
David Lawrence Ramsey23c44502005-01-27 20:49:07 +00004258 unsigned long flags_cpy = flags;
Chris Allegretta7662c862003-01-13 01:35:15 +00004259
Chris Allegretta5ec68622003-02-05 02:39:34 +00004260#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00004261 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00004262#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004263#ifndef NANO_SMALL
4264 backup_dir = NULL;
4265#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00004266#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00004267 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00004268#endif
4269#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00004270 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00004271#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00004272
4273 do_rcfile();
4274
4275#ifndef DISABLE_OPERATINGDIR
4276 if (operating_dir_cpy != NULL) {
4277 free(operating_dir);
4278 operating_dir = operating_dir_cpy;
4279 }
4280#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00004281#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00004282 if (fill_flag_used)
4283 wrap_at = wrap_at_cpy;
4284#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004285#ifndef NANO_SMALL
4286 if (backup_dir_cpy != NULL) {
4287 free(backup_dir);
4288 backup_dir = backup_dir_cpy;
4289 }
4290#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00004291#ifndef DISABLE_JUSTIFY
4292 if (quotestr_cpy != NULL) {
4293 free(quotestr);
4294 quotestr = quotestr_cpy;
4295 }
4296#endif
4297#ifndef DISABLE_SPELLER
4298 if (alt_speller_cpy != NULL) {
4299 free(alt_speller);
4300 alt_speller = alt_speller_cpy;
4301 }
4302#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00004303 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00004304 tabsize = tabsize_cpy;
4305 flags |= flags_cpy;
4306 }
4307#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00004308 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00004309 SET(NO_WRAP);
4310#endif
4311#endif /* ENABLE_NANORC */
4312
Chris Allegrettad8451932003-03-11 03:50:40 +00004313#ifndef NANO_SMALL
4314 history_init();
4315#ifdef ENABLE_NANORC
4316 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
4317 load_history();
4318#endif
4319#endif
4320
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004321#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004322 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004323 * in which case backups are disabled, since they would allow
4324 * reading from or writing to files not specified on the command
4325 * line). This entails making sure it exists and is a directory, so
4326 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004327 if (!ISSET(RESTRICTED))
4328 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004329#endif
4330
Chris Allegretta7662c862003-01-13 01:35:15 +00004331#ifndef DISABLE_OPERATINGDIR
4332 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004333 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00004334 init_operating_dir();
4335#endif
4336
Chris Allegretta7662c862003-01-13 01:35:15 +00004337#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00004338 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004339 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00004340
4341 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004342 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00004343
Chris Allegretta7662c862003-01-13 01:35:15 +00004344 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004345 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00004346#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004347 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00004348#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004349 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00004350#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00004351 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00004352#ifdef HAVE_REGEX_H
4353 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
4354
4355 if (quoterc == 0) {
4356 /* We no longer need quotestr, just quotereg. */
4357 free(quotestr);
4358 quotestr = NULL;
4359 } else {
4360 size_t size = regerror(quoterc, &quotereg, NULL, 0);
4361
4362 quoteerr = charalloc(size);
4363 regerror(quoterc, &quotereg, quoteerr, size);
4364 }
4365#else
4366 quotelen = strlen(quotestr);
4367#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00004368#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00004369
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00004370#ifndef DISABLE_SPELLER
4371 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004372 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004373 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00004374 * checking is disabled, since it would allow reading from or
4375 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00004376 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00004377 char *spellenv = getenv("SPELL");
4378 if (spellenv != NULL)
4379 alt_speller = mallocstrcpy(NULL, spellenv);
4380 }
4381#endif
4382
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00004383#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004384 /* If whitespace wasn't specified, set its default value. */
David Lawrence Ramsey6e60db62005-03-10 22:52:21 +00004385 if (whitespace == NULL) {
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00004386 whitespace = mallocstrcpy(NULL, " ");
David Lawrence Ramsey6e60db62005-03-10 22:52:21 +00004387 whitespace_len[0] = 1;
4388 whitespace_len[1] = 1;
4389 }
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00004390#endif
4391
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004392 /* If tabsize wasn't specified, set its default value. */
Chris Allegretta7662c862003-01-13 01:35:15 +00004393 if (tabsize == -1)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004394 tabsize = WIDTH_OF_TAB;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00004395
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00004396 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00004397 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00004398
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004399 /* Curses initialization stuff: Start curses and set up the
4400 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004401 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00004402 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00004403
David Lawrence Ramsey2d825ba2005-03-20 21:20:47 +00004404 /* Turn the cursor on for sure. */
4405 curs_set(1);
4406
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00004407 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00004408 global_init(FALSE);
4409 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00004410
4411 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00004412 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004413
4414#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00004415 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004416#endif
4417
Chris Allegretta2a42af12000-09-12 23:02:49 +00004418 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00004419#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00004420 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00004421#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004422
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004423#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00004424 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004425#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004426
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00004427 /* If there's a +LINE flag here, it is the first non-option
4428 * argument, and it is followed by at least one other argument, the
4429 * filename it applies to. */
4430 if (0 < optind && optind < argc - 1 && argv[optind][0] == '+') {
4431 startline = atoi(&argv[optind][1]);
4432 optind++;
4433 }
4434
Chris Allegretta7662c862003-01-13 01:35:15 +00004435#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004436 old_multibuffer = ISSET(MULTIBUFFER);
4437 SET(MULTIBUFFER);
4438
4439 /* Read all the files after the first one on the command line into
4440 * new buffers. */
4441 {
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00004442 int i = optind + 1, iline = 0;
4443 for (; i < argc; i++) {
4444 /* If there's a +LINE flag here, it is followed by at least
4445 * one other argument, the filename it applies to. */
4446 if (i < argc - 1 && argv[i][0] == '+' && iline == 0) {
4447 iline = atoi(&argv[i][1]);
4448 } else {
4449 load_buffer(argv[i]);
4450 if (iline > 0) {
4451 do_gotoline(iline, FALSE);
4452 iline = 0;
4453 }
4454 }
4455 }
Chris Allegretta7662c862003-01-13 01:35:15 +00004456 }
4457#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004458
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00004459 /* Read the first file on the command line into either the current
4460 * buffer or a new buffer, depending on whether multibuffer mode is
4461 * enabled. */
4462 if (optind < argc)
4463 load_buffer(argv[optind]);
4464
4465 /* We didn't open any files if all the command line arguments were
4466 * invalid files like directories or if there were no command line
4467 * arguments given. In this case, we have to load a blank buffer.
4468 * Also, we unset view mode to allow editing. */
4469 if (filename == NULL) {
4470 filename = mallocstrcpy(NULL, "");
4471 new_file();
4472 UNSET(VIEW_MODE);
4473
4474 /* Add this new entry to the open_files structure if we have
4475 * multibuffer support, or to the main filestruct if we don't. */
4476 load_file();
4477 }
4478
4479#ifdef ENABLE_MULTIBUFFER
4480 if (!old_multibuffer)
4481 UNSET(MULTIBUFFER);
4482#endif
4483
4484#ifdef DEBUG
4485 fprintf(stderr, "Main: top and bottom win\n");
4486#endif
4487
4488 titlebar(NULL);
4489 display_main_list();
4490
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004491 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00004492 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004493
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00004494#ifndef NANO_SMALL
4495 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00004496 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00004497#endif
Chris Allegretta08020882001-01-29 23:37:54 +00004498
Robert Siemborski6967eec2000-07-08 14:23:32 +00004499 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00004500
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00004501 while (TRUE) {
David Lawrence Ramseycac02932005-01-11 23:05:05 +00004502 bool meta_key, func_key, s_or_t, ran_func, finished;
David Lawrence Ramsey74835712004-12-04 17:41:52 +00004503
4504 /* Make sure the cursor is in the edit window. */
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00004505 reset_cursor();
David Lawrence Ramsey74835712004-12-04 17:41:52 +00004506
4507 /* If constant cursor position display is on, display the cursor
4508 * position. */
Chris Allegrettad26ab912003-01-28 01:16:47 +00004509 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00004510 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00004511
Chris Allegretta6b58acd2001-04-12 03:01:53 +00004512 currshortcut = main_list;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00004513
David Lawrence Ramsey74835712004-12-04 17:41:52 +00004514 /* Read in and interpret characters. */
David Lawrence Ramseycac02932005-01-11 23:05:05 +00004515 do_input(&meta_key, &func_key, &s_or_t, &ran_func, &finished,
4516 TRUE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004517 }
David Lawrence Ramsey5f9acfe2005-03-04 17:09:41 +00004518
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00004519 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00004520}