blob: 7b09708d70cd922bb92db0809673684ff7d849f0 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/stat.h>
32#include <sys/ioctl.h>
33#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000034#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000035#include <errno.h>
36#include <ctype.h>
37#include <locale.h>
38#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000039#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000040#include "proto.h"
41#include "nano.h"
42
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000043#ifdef HAVE_TERMIOS_H
44#include <termios.h>
45#endif
46
47#ifdef HAVE_TERMIO_H
48#include <termio.h>
49#endif
50
51#ifdef HAVE_GETOPT_H
52#include <getopt.h>
53#endif
54
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000055#ifndef NANO_SMALL
56#include <setjmp.h>
57#endif
58
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000060static ssize_t fill = 0; /* Fill - where to wrap lines,
61 basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000062#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000063#ifndef DISABLE_WRAPPING
David Lawrence Ramseyce62e822004-08-05 22:10:22 +000064static bool same_line_wrap = FALSE; /* Whether wrapped text should
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000065 be prepended to the next
66 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000067#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000068
Chris Allegretta6df90f52002-07-19 01:08:59 +000069static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000070static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000071
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000072#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000073static sigjmp_buf jmpbuf; /* Used to return to mainloop after
74 SIGWINCH */
David Lawrence Ramsey22fac782004-08-05 15:16:19 +000075static int pid; /* The PID of the newly forked process
76 * in open_pipe(). It must be global
77 * because the signal handler needs
78 * it. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000079#endif
Chris Allegretta08020882001-01-29 23:37:54 +000080
David Lawrence Ramseyda141062004-05-25 19:41:11 +000081/* What we do when we're all set to exit. */
82void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000084 if (!ISSET(NO_HELP))
85 blank_bottombars();
86 else
87 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000088
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000089 wrefresh(bottomwin);
90 endwin();
91
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000092 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000093 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094
Chris Allegrettad8451932003-03-11 03:50:40 +000095#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
96 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
97 save_history();
98#endif
99
Chris Allegretta6232d662002-05-12 19:52:15 +0000100#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000101 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000102#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000103
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000104 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105}
106
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000107/* Die (gracefully?). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000108void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000109{
110 va_list ap;
111
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000112 endwin();
113 curses_ended = TRUE;
114
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000115 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000116 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000117
Chris Allegretta6df90f52002-07-19 01:08:59 +0000118 va_start(ap, msg);
119 vfprintf(stderr, msg, ap);
120 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000121
Chris Allegretta32da4562002-01-02 15:12:21 +0000122 /* save the currently loaded file if it's been modified */
123 if (ISSET(MODIFIED))
124 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000125
Chris Allegretta355fbe52001-07-14 19:32:47 +0000126#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000127 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000128 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000129 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000130
131 tmp = open_files;
132
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000133 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000134 open_files = open_files->prev;
135
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000136 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000137
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000138 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000139 currently loaded file), don't save it again */
140 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000141 /* make sure open_files->fileage and fileage, and
142 open_files->filebot and filebot, are in sync; they
143 might not be if lines have been cut from the top or
144 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000145 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000146 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000147 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000148 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000149 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000151 open_files = open_files->next;
152 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153 }
154#endif
155
Chris Allegretta6df90f52002-07-19 01:08:59 +0000156 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000157}
158
Chris Allegretta6df90f52002-07-19 01:08:59 +0000159void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000160{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000161 char *ret;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000162 bool failed = TRUE;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000163
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000164 /* If we're using restricted mode, don't write any emergency backup
165 * files, since that would allow reading from or writing to files
166 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000167 if (ISSET(RESTRICTED))
168 return;
169
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170 /* If we can't save, we have REAL bad problems, but we might as well
171 TRY. */
172 if (die_filename[0] == '\0')
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000173 die_filename = "nano";
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000175 ret = get_next_filename(die_filename);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000176 if (ret[0] != '\0')
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000177 failed = -1 == write_file(ret, TRUE, FALSE, TRUE);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000178
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000179 if (!failed)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000180 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000181 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000182 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000183
184 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000185}
186
Chris Allegrettae61e8302001-01-14 05:18:27 +0000187/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000188 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000189void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000190{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000191 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000192}
193
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000194void print_view_warning(void)
195{
196 statusbar(_("Key illegal in VIEW mode"));
197}
198
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000199/* Initialize global variables -- no better way for now. If
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000200 * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
201void global_init(bool save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000202{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000203 current_x = 0;
204 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000205
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000206 editwinrows = LINES - 5 + no_help();
207 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000208 die_too_small();
209
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000210 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000211 if (!save_cutbuffer)
212 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 current = NULL;
214 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000216 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000217 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000218
Chris Allegretta6fe61492001-05-21 12:56:25 +0000219#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000220 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000221 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000222 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000223 if (fill < 0)
224 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000225#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000226
Chris Allegretta88b09152001-05-17 11:35:43 +0000227 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000228 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000229 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000230}
231
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000232void window_init(void)
233{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000234 editwinrows = LINES - 5 + no_help();
235 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000236 die_too_small();
237
Chris Allegretta1a128af2003-01-26 04:15:56 +0000238 if (topwin != NULL)
239 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000240 if (edit != NULL)
241 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000242 if (bottomwin != NULL)
243 delwin(bottomwin);
244
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000245 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000247 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
249
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000250 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251 keypad(edit, TRUE);
252 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000253}
254
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000255#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256void mouse_init(void)
257{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000259 mousemask(BUTTON1_RELEASED, NULL);
260 mouseinterval(50);
261 } else
262 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000263}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000264#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000265
266#ifndef DISABLE_HELP
267/* This function allocates help_text, and stores the help string in it.
268 * help_text should be NULL initially. */
269void help_init(void)
270{
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000271 size_t allocsize = 1; /* Space needed for help_text. */
272 const char *htx; /* Untranslated help message. */
273 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000274 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000275#ifndef NANO_SMALL
276 const toggle *t;
277#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000278
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000279 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000280 if (currshortcut == whereis_list || currshortcut == replace_list
281 || currshortcut == replace_list_2)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000282 htx = N_("Search Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000283 "Enter the words or characters you would like to search "
284 "for, then hit enter. If there is a match for the text you "
285 "entered, the screen will be updated to the location of the "
286 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000287 "The previous search string will be shown in brackets after "
288 "the Search: prompt. Hitting Enter without entering any text "
289 "will perform the previous search.\n\n The following function "
290 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000291 else if (currshortcut == goto_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000292 htx = N_("Go To Line Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000293 "Enter the line number that you wish to go to and hit "
294 "Enter. If there are fewer lines of text than the "
295 "number you entered, you will be brought to the last line "
296 "of the file.\n\n The following function keys are "
297 "available in Go To Line mode:\n\n");
298 else if (currshortcut == insertfile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000299 htx = N_("Insert File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000300 "Type in the name of a file to be inserted into the current "
301 "file buffer at the current cursor location.\n\n "
302 "If you have compiled nano with multiple file buffer "
303 "support, and enable multiple buffers with the -F "
304 "or --multibuffer command line flags, the Meta-F toggle, or "
305 "a nanorc file, inserting a file will cause it to be "
306 "loaded into a separate buffer (use Meta-< and > to switch "
307 "between file buffers).\n\n If you need another blank "
308 "buffer, do not enter any filename, or type in a "
309 "nonexistent filename at the prompt and press "
310 "Enter.\n\n The following function keys are "
311 "available in Insert File mode:\n\n");
312 else if (currshortcut == writefile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000313 htx = N_("Write File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000314 "Type the name that you wish to save the current file "
315 "as and hit Enter to save the file.\n\n If you have "
316 "selected text with Ctrl-^, you will be prompted to "
317 "save only the selected portion to a separate file. To "
318 "reduce the chance of overwriting the current file with "
319 "just a portion of it, the current filename is not the "
320 "default in this mode.\n\n The following function keys "
321 "are available in Write File mode:\n\n");
322#ifndef DISABLE_BROWSER
323 else if (currshortcut == browser_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000324 htx = N_("File Browser Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000325 "The file browser is used to visually browse the "
326 "directory structure to select a file for reading "
327 "or writing. You may use the arrow keys or Page Up/"
328 "Down to browse through the files, and S or Enter to "
329 "choose the selected file or enter the selected "
330 "directory. To move up one level, select the directory "
331 "called \"..\" at the top of the file list.\n\n The "
332 "following function keys are available in the file "
333 "browser:\n\n");
334 else if (currshortcut == gotodir_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000335 htx = N_("Browser Go To Directory Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000336 "Enter the name of the directory you would like to "
337 "browse to.\n\n If tab completion has not been disabled, "
338 "you can use the TAB key to (attempt to) automatically "
339 "complete the directory name.\n\n The following function "
340 "keys are available in Browser Go To Directory mode:\n\n");
341#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000342#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000343 else if (currshortcut == spell_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000344 htx = N_("Spell Check Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000345 "The spell checker checks the spelling of all text "
346 "in the current file. When an unknown word is "
347 "encountered, it is highlighted and a replacement can "
348 "be edited. It will then prompt to replace every "
349 "instance of the given misspelled word in the "
350 "current file.\n\n The following other functions are "
351 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000352#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000353#ifndef NANO_SMALL
354 else if (currshortcut == extcmd_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000355 htx = N_("External Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000356 "This menu allows you to insert the output of a command "
357 "run by the shell into the current buffer (or a new "
358 "buffer in multibuffer mode).\n\n The following keys are "
359 "available in this mode:\n\n");
360#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000361 else
362 /* Default to the main help list. */
363 htx = N_(" nano help text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000364 "The nano editor is designed to emulate the functionality and "
365 "ease-of-use of the UW Pico text editor. There are four main "
366 "sections of the editor: The top line shows the program "
367 "version, the current filename being edited, and whether "
368 "or not the file has been modified. Next is the main editor "
369 "window showing the file being edited. The status line is "
370 "the third line from the bottom and shows important messages. "
371 "The bottom two lines show the most commonly used shortcuts "
372 "in the editor.\n\n "
373 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000374 "sequences are notated with a caret (^) symbol and can be "
375 "entered either by using the Control (Ctrl) key or pressing the "
376 "Esc key twice. Escape-key sequences are notated with the Meta "
377 "(M) symbol and can be entered using either the Esc, Alt or "
378 "Meta key depending on your keyboard setup. Also, pressing Esc "
379 "twice and then typing a three-digit number from 000 to 255 "
380 "will enter the character with the corresponding ASCII code. "
381 "The following keystrokes are available in the main editor "
382 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000383
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000384 htx = _(htx);
385
386 allocsize += strlen(htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000387
388 /* The space needed for the shortcut lists, at most COLS characters,
389 * plus '\n'. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000390 allocsize += (COLS < 21 ? 21 : COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000391
392#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000393 /* If we're on the main list, we also count the toggle help text.
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000394 * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
395 * plus translated text, plus '\n'. */
Chris Allegretta3a784062003-02-10 02:32:58 +0000396 if (currshortcut == main_list) {
397 size_t endislen = strlen(_("enable/disable"));
398
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000399 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000400 allocsize += 8 + strlen(t->desc) + endislen;
401 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000402#endif /* !NANO_SMALL */
403
404 /* help_text has been freed and set to NULL unless the user resized
405 * while in the help screen. */
406 free(help_text);
407
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000408 /* Allocate space for the help text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000409 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000410
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000411 /* Now add the text we want. */
412 strcpy(help_text, htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000413 ptr = help_text + strlen(help_text);
414
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000415 /* Now add our shortcut info. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000416 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000417 bool meta_shortcut = FALSE;
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000418 /* TRUE if the character in s->metaval is shown in the
419 * first column. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000420
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000421 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000422#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000423 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000424 ptr += sprintf(ptr, "%.7s", _("Up"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000425 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000426#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000427 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000428 ptr += sprintf(ptr, "^%.6s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000429 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000430 ptr += sprintf(ptr, "^?");
431 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000432 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000433 }
434#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000435 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000436 meta_shortcut = TRUE;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000437 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000438 ptr += sprintf(ptr, "M-%.5s", _("Space"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000439 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000440 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000441 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000442#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000443
444 *(ptr++) = '\t';
445
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000446 if (s->funcval != NANO_NO_KEY)
447 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000448
449 *(ptr++) = '\t';
450
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000451 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
452 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000453 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
454 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000455
456 *(ptr++) = '\t';
457
458 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000459 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000460 }
461
462#ifndef NANO_SMALL
463 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000464 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000465 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000466 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000467 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000468 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000469 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000470 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000471#endif /* !NANO_SMALL */
472
473 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000474 * help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000475 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000476}
477#endif
478
479/* Create a new filestruct node. Note that we specifically do not set
480 * prevnode->next equal to the new line. */
481filestruct *make_new_node(filestruct *prevnode)
482{
483 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
484
485 newnode->data = NULL;
486 newnode->prev = prevnode;
487 newnode->next = NULL;
488 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
489
490 return newnode;
491}
492
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000493/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000494filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000495{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000496 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000497
Chris Allegretta6df90f52002-07-19 01:08:59 +0000498 assert(src != NULL);
499
Chris Allegretta88b09152001-05-17 11:35:43 +0000500 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000501 dst->next = src->next;
502 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000503 strcpy(dst->data, src->data);
504 dst->lineno = src->lineno;
505
506 return dst;
507}
508
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000509/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000510void splice_node(filestruct *begin, filestruct *newnode, filestruct
511 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000512{
513 if (newnode != NULL) {
514 newnode->next = end;
515 newnode->prev = begin;
516 }
517 if (begin != NULL)
518 begin->next = newnode;
519 if (end != NULL)
520 end->prev = newnode;
521}
522
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000523/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000524void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000525{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000526 assert(fileptr != NULL);
527
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000528 if (fileptr->prev != NULL)
529 fileptr->prev->next = fileptr->next;
530
531 if (fileptr->next != NULL)
532 fileptr->next->prev = fileptr->prev;
533}
534
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000535/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000536void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000537{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000538 if (fileptr != NULL) {
539 if (fileptr->data != NULL)
540 free(fileptr->data);
541 free(fileptr);
542 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543}
544
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000545/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 filestruct *head; /* copy of src, top of the copied list */
549 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000550
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000552
Chris Allegretta6df90f52002-07-19 01:08:59 +0000553 prev = copy_node(src);
554 prev->prev = NULL;
555 head = prev;
556 src = src->next;
557 while (src != NULL) {
558 prev->next = copy_node(src);
559 prev->next->prev = prev;
560 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000561
Chris Allegretta6df90f52002-07-19 01:08:59 +0000562 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000563 }
564
Chris Allegretta6df90f52002-07-19 01:08:59 +0000565 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000566 return head;
567}
568
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000569/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000570void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000572 if (src != NULL) {
573 while (src->next != NULL) {
574 src = src->next;
575 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000576#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000577 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578#endif
579 }
580 delete_node(src);
581#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000582 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583#endif
584 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000585}
586
Chris Allegretta6df90f52002-07-19 01:08:59 +0000587void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000588{
589 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000590 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000591
Chris Allegretta6df90f52002-07-19 01:08:59 +0000592 assert(fileage == NULL || fileage != fileage->next);
593 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000595}
596
Chris Allegretta6df90f52002-07-19 01:08:59 +0000597void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000598{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000599 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000600 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000601 else {
602 int lineno = fileptr->prev->lineno;
603
604 assert(fileptr != fileptr->next);
605 for (; fileptr != NULL; fileptr = fileptr->next)
606 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000607 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000608}
609
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000610/* Print one usage string to the screen. This cuts down on duplicate
611 * strings to translate and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000612 * translatable (the flag names). */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000613void print1opt(const char *shortflag, const char *longflag, const char
614 *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000615{
616 printf(" %s\t", shortflag);
617 if (strlen(shortflag) < 8)
618 printf("\t");
619
620#ifdef HAVE_GETOPT_LONG
621 printf("%s\t", longflag);
622 if (strlen(longflag) < 8)
623 printf("\t\t");
624 else if (strlen(longflag) < 16)
625 printf("\t");
626#endif
627
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000628 printf("%s\n", _(desc));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000629}
630
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000631void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000632{
633#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000634 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
635 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000636#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000637 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
638 printf(_("Option\t\tMeaning\n"));
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +0000639#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000640
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000641 print1opt("-h, -?", "--help", N_("Show this message"));
642 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000643#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000644 print1opt("-A", "--smarthome", N_("Enable smart home key"));
645 print1opt("-B", "--backup", N_("Backup existing files on save"));
646 print1opt("-D", "--dos", N_("Write file in DOS format"));
647 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000648#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000649#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000650 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000651#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000652#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000653#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000654 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000655#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000656 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000657#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000658#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000659 print1opt("-M", "--mac", N_("Write file in Mac format"));
660 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000661#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000662#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000663 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000664#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000665#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000666 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000667#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000668#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000669 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000670#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000671 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
672 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000673#ifdef ENABLE_COLOR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000674 print1opt(_("-Y [str]"), _("--syntax [str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000675#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000676 print1opt("-Z", "--restricted", N_("Restricted mode"));
677 print1opt("-c", "--const", N_("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000678#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000679 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
680 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
681 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000682#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000683 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000684#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000685 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000686#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000687#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000688 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000689#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000690 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000691#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000692 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000693#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000694#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000695 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000696#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000697 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
698 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000699#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000700 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000701#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000702 print1opt("-x", "--nohelp", N_("Don't show help window"));
703 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000704
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000705 /* This is a special case. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000706 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000707
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000708 exit(0);
709}
710
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000711void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000712{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000713 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000714 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000715 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000716 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000717 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000718
Chris Allegrettae6600372003-01-17 03:39:41 +0000719#ifndef ENABLE_NLS
720 printf(" --disable-nls");
721#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000722#ifdef DEBUG
723 printf(" --enable-debug");
724#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000725#ifdef NANO_EXTRA
726 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000727#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000728#ifdef NANO_SMALL
729 printf(" --enable-tiny");
730#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000731#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000732 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000733#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000734#ifdef DISABLE_HELP
735 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000736#endif
737#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000738 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000739#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000740#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000741 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000742#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000743#ifdef DISABLE_OPERATINGDIR
744 printf(" --disable-operatingdir");
745#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000746#ifdef DISABLE_SPELLER
747 printf(" --disable-speller");
748#endif
749#ifdef DISABLE_TABCOMP
750 printf(" --disable-tabcomp");
751#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000752#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000753#ifdef DISABLE_WRAPPING
754 printf(" --disable-wrapping");
755#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000756#ifdef DISABLE_ROOTWRAP
757 printf(" --disable-wrapping-as-root");
758#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000759#ifdef ENABLE_COLOR
760 printf(" --enable-color");
761#endif
762#ifdef ENABLE_MULTIBUFFER
763 printf(" --enable-multibuffer");
764#endif
765#ifdef ENABLE_NANORC
766 printf(" --enable-nanorc");
767#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000768#ifdef USE_SLANG
769 printf(" --with-slang");
770#endif
771 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000772}
773
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000774int no_help(void)
775{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000776 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000777}
778
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000779void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000780{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000781 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000782}
783
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000784#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000785RETSIGTYPE cancel_fork(int signal)
786{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000787 if (kill(pid, SIGKILL) == -1)
788 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000789}
790
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000791/* Return TRUE on success. */
792bool open_pipe(const char *command)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000793{
794 int fd[2];
795 FILE *f;
796 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000797 /* Original and temporary handlers for
798 * SIGINT. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000799 bool sig_failed = FALSE;
800 /* sig_failed means that sigaction() failed without changing the
801 * signal handlers.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000802 *
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000803 * We use this variable since it is important to put things back
804 * when we finish, even if we get errors. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000805
806 /* Make our pipes. */
807
808 if (pipe(fd) == -1) {
809 statusbar(_("Could not pipe"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000810 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000811 }
812
813 /* Fork a child. */
814
815 if ((pid = fork()) == 0) {
816 close(fd[0]);
817 dup2(fd[1], fileno(stdout));
818 dup2(fd[1], fileno(stderr));
819 /* If execl() returns at all, there was an error. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000820
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000821 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000822 exit(0);
823 }
824
825 /* Else continue as parent. */
826
827 close(fd[1]);
828
829 if (pid == -1) {
830 close(fd[0]);
831 statusbar(_("Could not fork"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000832 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000833 }
834
835 /* Before we start reading the forked command's output, we set
836 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000837
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000838 /* Enable interpretation of the special control keys so that we get
839 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000840 enable_signals();
841
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000842 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000843 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000844 nperror("sigaction");
845 } else {
846 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000847 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000848 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000849 nperror("sigaction");
850 }
851 }
852 /* Note that now oldaction is the previous SIGINT signal handler,
853 * to be restored later. */
854
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000855 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000856 if (f == NULL)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000857 nperror("fdopen");
David Lawrence Ramsey00d77982004-08-07 21:27:37 +0000858
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000859 read_file(f, "stdin", FALSE);
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000860 /* If multibuffer mode is on, we could be here in view mode. If so,
861 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000862 if (!ISSET(VIEW_MODE))
863 set_modified();
864
865 if (wait(NULL) == -1)
866 nperror("wait");
867
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000868 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000869 nperror("sigaction");
870
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000871 /* Disable interpretation of the special control keys so that we can
872 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000873 disable_signals();
874
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000875 return TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000876}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000877#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000878
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000879/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000880void do_char(char ch)
881{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000882 size_t current_len = strlen(current->data);
883#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000884 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000885 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +0000886 * update_line()? */
887#endif
888
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000889 if (ch == '\0') /* Null to newline, if needed. */
890 ch = '\n';
891 else if (ch == '\n') { /* Newline to Enter, if needed. */
892 do_enter();
893 return;
894 }
895
896 assert(current != NULL && current->data != NULL);
897
898 /* When a character is inserted on the current magicline, it means
899 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000900 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000901 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000902
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000903 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000904 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000905 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000906 charmove(&current->data[current_x + 1], &current->data[current_x],
907 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000908 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000909 totsize++;
910 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000911
Chris Allegretta6df90f52002-07-19 01:08:59 +0000912#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000913 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000914 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000915 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000916#endif
917
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000918 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000919
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000920#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000921 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +0000922 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000923 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000924#endif
925
Chris Allegretta6df90f52002-07-19 01:08:59 +0000926#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000927 /* If color syntaxes are turned on, we need to call
928 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000929 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000930 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000931#endif
932
933#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000934 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000935 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000936 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000937#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000938 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000939}
940
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000941void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000942{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000943 int *v_kbinput = NULL; /* Used to hold verbatim input. */
944 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000945 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000946
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000947 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000948
949 v_kbinput = get_verbatim_kbinput(edit, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000950
951 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
952 * off afterwards, so that if constant cursor position display is
953 * on, it will be updated properly. */
954 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000955 for (i = 0; i < v_len; i++)
956 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000957 UNSET(DISABLE_CURPOS);
958
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000959 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000960}
961
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000962void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000963{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000964 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000965 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000966 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000967 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000968}
969
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000970void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000971{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000972 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000973 /* Do we have to call edit_refresh(), or can we get away with
974 * update_line()? */
975
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000976 assert(current != NULL && current->data != NULL && current_x <=
977 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000978
979 placewewant = xplustabs();
980
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000981 if (current->data[current_x] != '\0') {
982 size_t linelen = strlen(current->data + current_x);
983
984 assert(current_x < strlen(current->data));
985
986 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +0000987 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000988 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000989
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000990 null_at(&current->data, linelen + current_x - 1);
991#ifndef NANO_SMALL
992 if (current_x < mark_beginx && mark_beginbuf == current)
993 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000994#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000995 } else if (current != filebot && (current->next != filebot ||
996 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000997 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +0000998 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +0000999 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001000
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001001 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001002
1003 /* If we're deleting at the end of a line, we need to call
1004 * edit_refresh(). */
1005 if (current->data[current_x] == '\0')
1006 do_refresh = TRUE;
1007
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001008 current->data = charealloc(current->data, current_x +
1009 strlen(foo->data) + 1);
1010 strcpy(current->data + current_x, foo->data);
1011#ifndef NANO_SMALL
1012 if (mark_beginbuf == current->next) {
1013 mark_beginx += current_x;
1014 mark_beginbuf = current;
1015 }
1016#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001017 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001018 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001019
1020 unlink_node(foo);
1021 delete_node(foo);
1022 renumber(current);
1023 totlines--;
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001024#ifndef DISABLE_WRAPPING
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001025 wrap_reset();
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001026#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001027 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001028 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029
1030 totsize--;
1031 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001032
1033#ifdef ENABLE_COLOR
1034 /* If color syntaxes are turned on, we need to call
1035 * edit_refresh(). */
1036 if (ISSET(COLOR_SYNTAX))
1037 do_refresh = TRUE;
1038#endif
1039
1040 if (do_refresh)
1041 edit_refresh();
1042 else
1043 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001044}
1045
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001046void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001047{
1048 do_char('\t');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001049}
1050
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001051/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001052void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001053{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001054 filestruct *newnode = make_new_node(current);
1055 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001056
Chris Allegretta6df90f52002-07-19 01:08:59 +00001057 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001058
Chris Allegrettaff989832001-09-17 13:48:00 +00001059#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001060 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001061 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001062 /* If we are breaking the line in the indentation, the new
1063 * indentation should have only current_x characters, and
1064 * current_x should not change. */
1065 extra = indent_length(current->data);
1066 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001067 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001068 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001069 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001070#endif
1071 newnode->data = charalloc(strlen(current->data + current_x) +
1072 extra + 1);
1073 strcpy(&newnode->data[extra], current->data + current_x);
1074#ifndef NANO_SMALL
1075 if (ISSET(AUTOINDENT))
1076 strncpy(newnode->data, current->data, extra);
1077#endif
1078 null_at(&current->data, current_x);
1079#ifndef NANO_SMALL
1080 if (current == mark_beginbuf && current_x < mark_beginx) {
1081 mark_beginbuf = newnode;
1082 mark_beginx += extra - current_x;
1083 }
1084#endif
1085 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001086
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001087 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001088 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001089 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001090
1091 totsize++;
1092 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001093 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001094
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001095 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001096
1097 totlines++;
1098 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001099 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001100}
1101
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001102#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001103void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001104{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001105 size_t old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001106 const filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001107 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001108
Chris Allegretta6df90f52002-07-19 01:08:59 +00001109 /* Skip letters in this word first. */
1110 while (current->data[current_x] != '\0' &&
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001111 isalnum((int)current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001112 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001113
Chris Allegretta6df90f52002-07-19 01:08:59 +00001114 for (; current != NULL; current = current->next) {
1115 while (current->data[current_x] != '\0' &&
1116 !isalnum((int)current->data[current_x]))
1117 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001118
Chris Allegretta6df90f52002-07-19 01:08:59 +00001119 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001120 break;
1121
Chris Allegretta6df90f52002-07-19 01:08:59 +00001122 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001123 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001124 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001125 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001126
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001127 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001128
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001129 /* Refresh the screen. If current has run off the bottom, this
1130 * call puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001131 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001132}
1133
Chris Allegretta6df90f52002-07-19 01:08:59 +00001134/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001135void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001136{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001137 size_t old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001138 const filestruct *current_save = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001139 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001140
Chris Allegretta6df90f52002-07-19 01:08:59 +00001141 /* Skip letters in this word first. */
1142 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1143 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001144
Chris Allegretta6df90f52002-07-19 01:08:59 +00001145 for (; current != NULL; current = current->prev) {
1146 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1147 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001148
Chris Allegretta6df90f52002-07-19 01:08:59 +00001149 if (current_x >= 0)
1150 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001151
Chris Allegretta6df90f52002-07-19 01:08:59 +00001152 if (current->prev != NULL)
1153 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001154 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001155
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001156 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001157 current = fileage;
1158 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001159 } else {
1160 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1161 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001162 }
1163
Chris Allegretta76e291b2001-10-14 19:05:10 +00001164 placewewant = xplustabs();
1165
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001166 /* Refresh the screen. If current has run off the top, this call
1167 * puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001168 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001169}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001170
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001171void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001172{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001173 TOGGLE(MARK_ISSET);
1174 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001175 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001176 mark_beginbuf = current;
1177 mark_beginx = current_x;
1178 } else {
1179 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001180 edit_refresh();
1181 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001182}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001183#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001184
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001185#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001186void wrap_reset(void)
1187{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001188 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001189}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001190#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001191
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001192#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001193/* We wrap the given line. Precondition: we assume the cursor has been
1194 * moved forward since the last typed character. Return value: whether
1195 * we wrapped. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001196bool do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001197{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001198 size_t len = strlen(inptr->data);
1199 /* Length of the line we wrap. */
1200 size_t i = 0;
1201 /* Generic loop variable. */
1202 int wrap_loc = -1;
1203 /* Index of inptr->data where we wrap. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001204 int word_back = -1;
1205#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001206 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001207 /* Indentation to prepend to the new line. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001208 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001209#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001210 const char *after_break; /* Text after the wrap point. */
1211 size_t after_break_len; /* strlen(after_break) */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001212 bool wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001213 const char *wrap_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001214 /* The next line, minus indentation. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001215 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1216 char *newline = NULL; /* The line we create. */
1217 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001218
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001219/* There are three steps. First, we decide where to wrap. Then, we
1220 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001221
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001222/* Step 1, finding where to wrap. We are going to add a new line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001223 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001224 * location of this replacement.
1225 *
1226 * Where should we break the line? We need the last "legal wrap point"
1227 * such that the last word before it ended at or before fill. If there
1228 * is no such point, we settle for the first legal wrap point.
1229 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001230 * A "legal wrap point" is a whitespace character that is not followed
1231 * by whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001232 *
1233 * If there is no legal wrap point or we found the last character of the
1234 * line, we should return without wrapping.
1235 *
1236 * Note that the initial indentation does not count as a legal wrap
1237 * point if we are going to auto-indent!
1238 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001239 * Note that the code below could be optimized, by not calling
1240 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001241
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001242#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001243 if (ISSET(AUTOINDENT))
1244 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001245#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001246 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001247 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001248 /* Record where the last word ended. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001249 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001250 word_back = i;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001251 /* If we have found a "legal wrap point" and the current word
1252 * extends too far, then we stop. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001253 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001254 break;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001255 /* We record the latest "legal wrap point". */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001256 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001257 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001258 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001259 if (i == len)
1260 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001261
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001262 /* Step 2, making the new wrap line. It will consist of indentation
1263 * + after_break + " " + wrap_line (although indentation and
1264 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001265
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001266 /* after_break is the text that will be moved to the next line. */
1267 after_break = inptr->data + wrap_loc + 1;
1268 after_break_len = len - wrap_loc - 1;
1269 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001270
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001271 /* new_line_len will later be increased by the lengths of indentation
1272 * and wrap_line. */
1273 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001274
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001275 /* We prepend the wrapped text to the next line, if the flag is set,
1276 * and there is a next line, and prepending would not make the line
1277 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001278 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001279 wrap_line = inptr->next->data;
1280 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001281
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001282 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001283 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001284 wrapping = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001285 new_line_len += (1 + wrap_line_len);
1286 }
1287 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001288
Chris Allegrettaff989832001-09-17 13:48:00 +00001289#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001290 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001291 /* Indentation comes from the next line if wrapping, else from
1292 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001293 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001294 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001295 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001296 /* The wrap_line text should not duplicate indentation.
1297 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001298 wrap_line += indent_len;
1299 else
1300 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001301 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001302#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001303
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001304 /* Now we allocate the new line and copy into it. */
1305 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001306 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001307 *newline = '\0';
1308
1309#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001310 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001311 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001312 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001313 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001314 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001315#endif
1316 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001317 new_line_len += after_break_len;
1318 /* We end the old line after wrap_loc. Note that this does not eat
1319 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001320 null_at(&inptr->data, wrap_loc + 1);
1321 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001322 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001323 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001324 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001325 * in a tab or a space, we don't add a space and decrement
1326 * totsize to account for that. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001327 if (!isblank(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001328 strcat(newline, " ");
1329 else
1330 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001331 strcat(newline, wrap_line);
1332 free(inptr->next->data);
1333 inptr->next->data = newline;
1334 } else {
1335 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001336
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001337 /* In this case, the file size changes by +1 for the new line,
1338 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001339#ifndef NANO_SMALL
1340 totsize += indent_len;
1341#endif
1342 totlines++;
1343 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001344 temp->prev = inptr;
1345 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001346 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001347 /* If temp->next is NULL, then temp is the last line of the
1348 * file, so we must set filebot. */
1349 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001350 temp->next->prev = temp;
1351 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001352 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001353 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001354
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001355 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1356 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001357
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001358 /* Later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001359 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001360
1361 /* Each line knows its line number. We recalculate these if we
1362 * inserted a new line. */
1363 if (!wrapping)
1364 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001365
Chris Allegretta6df90f52002-07-19 01:08:59 +00001366 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001367 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001368 current = current->next;
1369 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001370#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001371 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001372#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001373 wrap_loc + 1;
1374 wrap_reset();
1375 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001376 }
1377
Chris Allegretta6df90f52002-07-19 01:08:59 +00001378#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001379 /* If the mark was on this line after the wrap point, we move it
1380 * down. If it was on the next line and we wrapped, we move it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001381 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001382 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1383 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001384 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001385 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001386 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001387#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001388
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001389 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001390}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001391#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001392
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001393#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001394/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001395 * return FALSE if the user cancels. */
1396bool do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001397{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001398 char *save_search;
1399 char *save_replace;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001400 size_t current_x_save = current_x;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001401 filestruct *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001402 filestruct *edittop_save = edittop;
1403 /* Save where we are. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001404 bool accepted = TRUE;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001405 /* The return value. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001406 bool reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001407#ifndef NANO_SMALL
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001408 bool case_sens_set = ISSET(CASE_SENSITIVE);
1409 bool mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001410
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001411 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001412 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001413 UNSET(MARK_ISSET);
1414#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001415 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001416 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001417
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001418 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001419 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001420 save_search = last_search;
1421 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001422
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001423 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001424 last_search = mallocstrcpy(NULL, word);
1425 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001426
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001427 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001428 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001429 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001430
1431 search_last_line = FALSE;
1432
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001433 /* Find the first whole-word occurrence of word. */
1434 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001435 if (is_whole_word(current_x, current->data, word)) {
1436 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001437
Chris Allegretta6df90f52002-07-19 01:08:59 +00001438 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001439
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001440 /* Allow the replace word to be corrected. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001441 accepted = -1 != statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001442#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001443 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001444#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001445 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001446
Chris Allegretta6df90f52002-07-19 01:08:59 +00001447 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001448
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001449 if (accepted && strcmp(word, answer) != 0) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001450 search_last_line = FALSE;
1451 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001452 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001453 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001454
1455 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001456 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001457
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001458 /* Restore the search/replace strings. */
1459 free(last_search);
1460 last_search = save_search;
1461 free(last_replace);
1462 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001463
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001464 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001465 current = current_save;
1466 current_x = current_x_save;
1467 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001468
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001469 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001470 if (reverse_search_set)
1471 SET(REVERSE_SEARCH);
1472
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001473#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001474 if (!case_sens_set)
1475 UNSET(CASE_SENSITIVE);
1476
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001477 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001478 if (mark_set)
1479 SET(MARK_ISSET);
1480#endif
1481
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001482 return accepted;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001483}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001484
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001485/* Integrated spell checking using 'spell' program. Return value: NULL
1486 * for normal termination, otherwise the error string. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001487const char *do_int_speller(const char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001488{
Chris Allegretta271e9722000-11-10 18:15:43 +00001489 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001490 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001491 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001492 pid_t pid_spell, pid_sort, pid_uniq;
1493 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001494
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001495 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001496 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1497 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001498
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001499 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001500
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001501 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001502 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001503
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001504 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001505
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001506 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001507
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001508 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001509 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1510 goto close_pipes_and_exit;
1511
1512 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1513 goto close_pipes_and_exit;
1514
Chris Allegretta271e9722000-11-10 18:15:43 +00001515 close(tempfile_fd);
1516
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001517 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001518 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1519 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001520
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001521 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001522
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001523 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001524 execlp("spell", "spell", NULL);
1525
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001526 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001527 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001528 }
1529
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001530 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001531 close(spell_fd[1]);
1532
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001533 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001534 if ((pid_sort = fork()) == 0) {
1535
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001536 /* Child continues (i.e, future spell process). Replace the
1537 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001538 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1539 goto close_pipes_and_exit;
1540
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001541 close(spell_fd[0]);
1542
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001543 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001544 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1545 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001546
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001547 close(sort_fd[1]);
1548
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001549 /* Start sort program. Use -f to remove mixed case without
1550 * having to have ANOTHER pipe for tr. If this isn't portable,
1551 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001552 execlp("sort", "sort", "-f", NULL);
1553
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001554 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001555 exit(1);
1556 }
1557
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001558 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001559 close(sort_fd[1]);
1560
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001561 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001562 if ((pid_uniq = fork()) == 0) {
1563
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001564 /* Child continues (i.e, future uniq process). Replace the
1565 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001566 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1567 goto close_pipes_and_exit;
1568
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001569 close(sort_fd[0]);
1570
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001571 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001572 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1573 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001574
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001575 close(uniq_fd[1]);
1576
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001577 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001578 execlp("uniq", "uniq", NULL);
1579
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001580 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001581 exit(1);
1582 }
1583
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001584 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001585 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001586
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001587 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001588 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1589 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001590 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001591 }
1592
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001593 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001594 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1595 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001596 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001597 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001598
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001599 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001600 read_buff_read = 0;
1601 read_buff_size = pipe_buff_size + 1;
1602 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001603
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001604 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001605 read_buff_read += bytesread;
1606 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001607 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001608 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001609
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001610 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001611
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001612 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001613 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001614
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001615 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001616 read_buff_word = read_buff_ptr = read_buff;
1617
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001618 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001619
1620 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001621 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001622 if (read_buff_word != read_buff_ptr) {
1623 if (!do_int_spell_fix(read_buff_word)) {
1624 read_buff_word = read_buff_ptr;
1625 break;
1626 }
1627 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001628 read_buff_word = read_buff_ptr + 1;
1629 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001630 read_buff_ptr++;
1631 }
1632
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001633 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001634 if (read_buff_word != read_buff_ptr)
1635 do_int_spell_fix(read_buff_word);
1636
Chris Allegretta271e9722000-11-10 18:15:43 +00001637 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001638 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001639 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001640
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001641 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001642 waitpid(pid_spell, &spell_status, 0);
1643 waitpid(pid_sort, &sort_status, 0);
1644 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001645
Chris Allegretta334a9402002-12-16 04:25:53 +00001646 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1647 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001648
Chris Allegretta334a9402002-12-16 04:25:53 +00001649 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1650 return _("Error invoking \"sort -f\"");
1651
1652 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1653 return _("Error invoking \"uniq\"");
1654
1655 /* Otherwise... */
1656 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001657
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001658 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001659
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001660 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001661 close(tempfile_fd);
1662 close(spell_fd[0]);
1663 close(spell_fd[1]);
1664 close(sort_fd[0]);
1665 close(sort_fd[1]);
1666 close(uniq_fd[0]);
1667 close(uniq_fd[1]);
1668 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001669}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001670
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001671/* External spell checking. Return value: NULL for normal termination,
1672 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001673const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001674{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001675 int alt_spell_status, lineno_cur = current->lineno;
David Lawrence Ramsey360093a2004-07-28 20:53:55 +00001676 int x_cur = current_x, y_cur = current_y;
1677 size_t pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001678 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001679 char *ptr;
1680 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001681 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001682#ifndef NANO_SMALL
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001683 bool mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001684 int mbb_lineno_cur = 0;
1685 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001686 * the alternate spell command. The line that mark_beginbuf
1687 * points to will be freed, so we save the line number and
1688 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001689
1690 if (mark_set) {
1691 mbb_lineno_cur = mark_beginbuf->lineno;
1692 UNSET(MARK_ISSET);
1693 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001694#endif
1695
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001696 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001697
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001698 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001699 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001700 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001701
Chris Allegrettae434b452001-01-27 19:25:00 +00001702 spellargs[0] = strtok(alt_speller, " ");
1703 while ((ptr = strtok(NULL, " ")) != NULL) {
1704 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001705 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001706 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001707 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001708 spellargs[arglen - 1] = NULL;
1709 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001710 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001711
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001712 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001713 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001714 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001715 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001716
1717 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001718 exit(1);
1719 }
1720
1721 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001722 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001723 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001724
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001725 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001726 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001727
Chris Allegretta334a9402002-12-16 04:25:53 +00001728 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1729 char *altspell_error = NULL;
1730 char *invoke_error = _("Could not invoke \"%s\"");
1731 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1732
1733 altspell_error = charalloc(msglen);
1734 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1735 return altspell_error;
1736 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001737
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001738 refresh();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001739
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001740#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001741 if (mark_set) {
1742 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1743 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001744 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001745 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001746 SET(MARK_ISSET);
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001747 } else {
1748#endif
1749 /* Only reload the temp file if it isn't a marked selection. */
1750 free_filestruct(fileage);
1751 terminal_init();
1752 global_init(TRUE);
1753 open_file(tempfile_name, FALSE, TRUE);
1754#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001755 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001756#endif
1757
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001758 /* Go back to the old position, mark the file as modified, and make
1759 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001760 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001761 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001762 clearok(topwin, FALSE);
1763 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001764
Chris Allegretta334a9402002-12-16 04:25:53 +00001765 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001766}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001767
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001768void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001769{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001770 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001771 char *temp = safe_tempnam(0, "nano.");
1772 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001773
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001774 if (temp == NULL) {
1775 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001776 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00001777 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001778
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001779#ifndef NANO_SMALL
1780 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001781 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001782 else
1783#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001784 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001785
1786 if (i == -1) {
David Lawrence Ramsey95e39e52004-08-12 02:52:14 +00001787 statusbar(_("Error writing temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001788 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001789 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001790 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001791
Chris Allegrettae1f14522001-09-19 03:19:43 +00001792#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001793 /* Update the current open_files entry before spell-checking, in
1794 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001795 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001796#endif
1797
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001798 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1799 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001800 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001801 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001802
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001803 if (spell_msg != NULL)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001804 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1805 strerror(errno));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001806 else
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001807 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00001808}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001809#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001810
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001811#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001812/* The "indentation" of a line is the whitespace between the quote part
1813 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001814size_t indent_length(const char *line)
1815{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001816 size_t len = 0;
1817
1818 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001819 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001820 line++;
1821 len++;
1822 }
1823 return len;
1824}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001825#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001826
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001827#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001828/* justify_format() replaces Tab by Space and multiple spaces by 1
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00001829 * (except it maintains 2 after a character in punct followed by a
1830 * character in brackets). Note that the terminating \0 counts as a
1831 * space.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001832 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001833 * justify_format() might make line->data shorter, and change the actual
1834 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001835 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001836 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001837 * skip should be at most strlen(line->data). The character at
1838 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001839void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001840{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001841 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001842
Chris Allegretta6df90f52002-07-19 01:08:59 +00001843 /* These four asserts are assumptions about the input data. */
1844 assert(line != NULL);
1845 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001846 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001847 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001848
Chris Allegretta6df90f52002-07-19 01:08:59 +00001849 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001850 for (front = back; ; front++) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001851 bool remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001852 /* Do we want to remove this space? */
1853
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001854 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001855 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001856
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001857 /* These tests are safe since line->data + skip is not a
1858 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001859 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001860 const char *bob = front - 2;
1861
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001862 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001863 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001864 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001865 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001866 break;
1867 }
1868 if (strchr(brackets, *bob) == NULL)
1869 break;
1870 }
1871 }
1872
1873 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001874 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001875 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001876#ifndef NANO_SMALL
1877 if (mark_beginbuf == line && back - line->data < mark_beginx)
1878 mark_beginx--;
1879#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001880 if (*front == '\0')
1881 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001882 } else {
1883 *back = *front;
1884 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001885 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001886 if (*front == '\0')
1887 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001888 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001889
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001890 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001891 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001892
Chris Allegretta6df90f52002-07-19 01:08:59 +00001893 /* Now back is the new end of line->data. */
1894 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001895 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001896 null_at(&line->data, back - line->data);
1897#ifndef NANO_SMALL
1898 if (mark_beginbuf == line && back - line->data < mark_beginx)
1899 mark_beginx = back - line->data;
1900#endif
1901 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001902}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001903
1904/* The "quote part" of a line is the largest initial substring matching
1905 * the quote string. This function returns the length of the quote part
1906 * of the given line.
1907 *
1908 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1909 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001910size_t quote_length(const char *line)
1911{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001912#ifdef HAVE_REGEX_H
1913 regmatch_t matches;
1914 int rc = regexec(&quotereg, line, 1, &matches, 0);
1915
1916 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1917 return 0;
1918 /* matches.rm_so should be 0, since the quote string should start
1919 * with the caret ^. */
1920 return matches.rm_eo;
1921#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001922 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001923
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001924 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001925 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001926 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001927 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001928#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001929}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001930
Chris Allegretta6df90f52002-07-19 01:08:59 +00001931/* a_line and b_line are lines of text. The quotation part of a_line is
1932 * the first a_quote characters. Check that the quotation part of
1933 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001934bool quotes_match(const char *a_line, size_t a_quote, const char
1935 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001936{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001937 /* Here is the assumption about a_quote: */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001938 assert(a_quote == quote_length(a_line));
1939 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001940 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001941}
1942
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001943/* We assume a_line and b_line have no quote part. Then, we return
1944 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001945bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00001946 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001947{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001948 assert(a_indent == indent_length(a_line));
1949 assert(b_indent == indent_length(b_line));
1950
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001951 return b_indent <= a_indent &&
1952 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001953}
1954
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001955/* Is foo the beginning of a paragraph?
1956 *
1957 * A line of text consists of a "quote part", followed by an
1958 * "indentation part", followed by text. The functions quote_length()
1959 * and indent_length() calculate these parts.
1960 *
1961 * A line is "part of a paragraph" if it has a part not in the quote
1962 * part or the indentation.
1963 *
1964 * A line is "the beginning of a paragraph" if it is part of a
1965 * paragraph and
1966 * 1) it is the top line of the file, or
1967 * 2) the line above it is not part of a paragraph, or
1968 * 3) the line above it does not have precisely the same quote
1969 * part, or
1970 * 4) the indentation of this line is not an initial substring of
1971 * the indentation of the previous line, or
1972 * 5) this line has no quote part and some indentation, and
1973 * AUTOINDENT is not set.
1974 * The reason for number 5) is that if AUTOINDENT is not set, then an
1975 * indented line is expected to start a paragraph, like in books.
1976 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
1977 * turned on. */
1978bool begpar(const filestruct *const foo)
1979{
1980 size_t quote_len;
1981 size_t indent_len;
1982 size_t temp_id_len;
1983
1984 /* Case 1). */
1985 if (foo->prev == NULL)
1986 return TRUE;
1987
1988 quote_len = quote_length(foo->data);
1989 indent_len = indent_length(foo->data + quote_len);
1990
1991 /* Not part of a paragraph. */
1992 if (foo->data[quote_len + indent_len] == '\0')
1993 return FALSE;
1994
1995 /* Case 3). */
1996 if (!quotes_match(foo->data, quote_len, foo->prev->data))
1997 return TRUE;
1998
1999 temp_id_len = indent_length(foo->prev->data + quote_len);
2000
2001 /* Case 2) or 5) or 4). */
2002 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2003 (quote_len == 0 && indent_len > 0
2004#ifndef NANO_SMALL
2005 && !ISSET(AUTOINDENT)
2006#endif
2007 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2008 foo->data + quote_len, indent_len))
2009 return TRUE;
2010
2011 return FALSE;
2012}
2013
2014/* We find the last beginning-of-paragraph line before the current
2015 * line. */
2016void do_para_begin(void)
2017{
2018 const filestruct *old_current = current;
2019 const size_t old_pww = placewewant;
2020
2021 current_x = 0;
2022 placewewant = 0;
2023
2024 if (current->prev != NULL) {
2025 do {
2026 current = current->prev;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002027 current_y--;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002028 } while (!begpar(current));
2029 }
2030
2031 edit_redraw(old_current, old_pww);
2032}
2033
2034bool inpar(const char *str)
2035{
2036 size_t quote_len = quote_length(str);
2037
2038 return str[quote_len + indent_length(str + quote_len)] != '\0';
2039}
2040
2041/* A line is the last line of a paragraph if it is in a paragraph, and
2042 * the next line isn't, or is the beginning of a paragraph. We move
2043 * down to the end of a paragraph, then one line farther. */
2044void do_para_end(void)
2045{
2046 const filestruct *const old_current = current;
2047 const size_t old_pww = placewewant;
2048
2049 current_x = 0;
2050 placewewant = 0;
2051
2052 while (current->next != NULL && !inpar(current->data))
2053 current = current->next;
2054
2055 while (current->next != NULL && inpar(current->next->data) &&
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002056 !begpar(current->next)) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002057 current = current->next;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002058 current_y++;
2059 }
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002060
2061 if (current->next != NULL)
2062 current = current->next;
2063
2064 edit_redraw(old_current, old_pww);
2065}
2066
Chris Allegretta6df90f52002-07-19 01:08:59 +00002067/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002068 * buffer, not allowing them to be concatenated. We assume there are
2069 * enough lines after first_line. We leave copies of the lines in
2070 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002071filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2072 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002073{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002074 /* We put the original lines, not copies, into the cutbuffer, just
2075 * out of a misguided sense of consistency, so if you uncut, you get
2076 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002077 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002078
2079 set_modified();
2080 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002081 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002082 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002083
Chris Allegretta908f7702003-01-15 11:18:58 +00002084 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002085 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002086 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002087 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002088 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002089 edittop = bob;
2090#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002091 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002092 mark_beginbuf = bob;
2093#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002094
Chris Allegretta908f7702003-01-15 11:18:58 +00002095 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002096 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002097 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002098 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002099 }
2100 return first_line;
2101}
2102
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002103/* Is it possible to break line at or before goal? */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002104bool breakable(const char *line, int goal)
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002105{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002106 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002107 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002108 return TRUE;
2109
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002110 if (is_cntrl_char(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002111 goal -= 2;
2112 else
2113 goal -= 1;
2114 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002115 /* If goal is not negative, the whole line (one word) was short
2116 * enough. */
2117 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002118}
2119
Chris Allegretta6df90f52002-07-19 01:08:59 +00002120/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002121 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002122 * such space, and force is TRUE, then we find the first space. Anyway,
2123 * we then take the last space in that group of spaces. The terminating
2124 * '\0' counts as a space. */
2125int break_line(const char *line, int goal, bool force)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002126{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002127 /* Note that we use int instead of size_t, since goal is at most
2128 * COLS, the screen width, which will always be reasonably small. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002129 int space_loc = -1;
2130 /* Current tentative return value. Index of the last space we
2131 * found with short enough display width. */
2132 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002133 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002134
2135 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002136 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002137 if (*line == ' ')
2138 space_loc = cur_loc;
2139 assert(*line != '\t');
2140
Chris Allegrettacf287c82002-07-20 13:57:41 +00002141 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002142 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002143 else
2144 goal--;
2145 }
2146 if (goal >= 0)
2147 /* In fact, the whole line displays shorter than goal. */
2148 return cur_loc;
2149 if (space_loc == -1) {
2150 /* No space found short enough. */
2151 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002152 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002153 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002154 return cur_loc;
2155 return -1;
2156 }
2157 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002158 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002159 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2160 *(line - cur_loc + space_loc + 1) == '\0')
2161 space_loc++;
2162 return space_loc;
2163}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002164
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002165/* Find the beginning of the current paragraph if we're in one, or the
2166 * beginning of the next paragraph if we're not. Afterwards, save the
2167 * quote length and paragraph length in *quote and *par. Return FALSE
2168 * if we found a paragraph, or TRUE if there was an error or we didn't
2169 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002170 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002171 * See the comment at begpar() for more about when a line is the
2172 * beginning of a paragraph. */
2173bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002174{
2175 size_t quote_len;
2176 /* Length of the initial quotation of the paragraph we
2177 * search. */
2178 size_t par_len;
2179 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002180 size_t indent_len;
2181 /* Generic indentation length. */
2182 filestruct *line;
2183 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002184
2185#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002186 if (quoterc != 0) {
2187 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2188 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002189 }
2190#endif
2191
2192 /* Here is an assumption that is always true anyway. */
2193 assert(current != NULL);
2194
2195 current_x = 0;
2196
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002197 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002198 indent_len = indent_length(current->data + quote_len);
2199
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002200 /* Here we find the first line of the paragraph to search. If the
2201 * current line is in a paragraph, then we move back to the first
2202 * line of the paragraph. Otherwise, we move to the first line that
2203 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002204 if (current->data[quote_len + indent_len] != '\0') {
2205 /* This line is part of a paragraph. So we must search back to
2206 * the first line of this paragraph. First we check items 1)
2207 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002208 while (current->prev != NULL && quotes_match(current->data,
2209 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002210 size_t temp_id_len =
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00002211 indent_length(current->prev->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002212 /* The indentation length of the previous line. */
2213
2214 /* Is this line the beginning of a paragraph, according to
2215 * items 2), 5), or 4) above? If so, stop. */
2216 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002217 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002218#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002219 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002220#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002221 ) || !indents_match(current->prev->data + quote_len,
2222 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002223 break;
2224 indent_len = temp_id_len;
2225 current = current->prev;
2226 current_y--;
2227 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002228 } else {
2229 /* This line is not part of a paragraph. Move down until we get
2230 * to a non "blank" line. */
2231 do {
2232 /* There is no next paragraph, so nothing to move to. */
2233 if (current->next == NULL) {
2234 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002235 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002236 }
2237 current = current->next;
2238 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002239 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002240 indent_len = indent_length(current->data + quote_len);
2241 } while (current->data[quote_len + indent_len] == '\0');
2242 }
2243
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002244 /* Now current is the first line of the paragraph, and quote_len is
2245 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002246
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002247 /* Next step, compute par_len, the number of lines in this
2248 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002249 line = current;
2250 par_len = 1;
2251 indent_len = indent_length(line->data + quote_len);
2252
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002253 while (line->next != NULL &&
2254 quotes_match(current->data, quote_len, line->next->data)) {
2255 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002256
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002257 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002258 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002259 line->next->data[quote_len + temp_id_len] == '\0' ||
2260 (quote_len == 0 && temp_id_len > 0
2261#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002262 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002263#endif
2264 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002265 break;
2266 indent_len = temp_id_len;
2267 line = line->next;
2268 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002269 }
2270
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002271 /* Now par_len is the number of lines in this paragraph. We should
2272 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002273
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002274 /* Save the values of quote_len and par_len. */
2275 assert(quote != NULL && par != NULL);
2276 *quote = quote_len;
2277 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002278
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002279 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002280}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002281
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002282/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2283 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002284void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002285{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002286 filestruct *first_par_line = NULL;
2287 /* Will be the first line of the resulting justified paragraph.
2288 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002289 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002290 /* Will be the last line of the result, also for uncut. */
2291 filestruct *cutbuffer_save = cutbuffer;
2292 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002293 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002294 * original to restore it later. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002295 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002296 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002297 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002298 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002299
2300 /* We save these global variables to be restored if the user
2301 * unjustifies. Note we don't need to save totlines. */
2302 int current_x_save = current_x;
2303 int current_y_save = current_y;
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002304 long flags_save = flags;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002305 long totsize_save = totsize;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002306 filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002307 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002308#ifndef NANO_SMALL
2309 filestruct *mark_beginbuf_save = mark_beginbuf;
2310 int mark_beginx_save = mark_beginx;
2311#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002312 int kbinput;
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002313 bool meta_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002314
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002315 /* If we're justifying the entire file, start at the beginning. */
2316 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002317 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002318
2319 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002320
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002321 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002322 size_t quote_len;
2323 /* Length of the initial quotation of the paragraph we
2324 * justify. */
2325 size_t par_len;
2326 /* Number of lines in that paragraph. */
2327
2328 /* Find the first line of the paragraph to be justified. That
2329 * is the start of this paragraph if we're in one, or the start
2330 * of the next otherwise. Save the quote length and paragraph
2331 * length (number of lines). Don't refresh the screen yet
2332 * (since we'll do that after we justify). If the search failed
2333 * and we're justifying the whole file, move the last line of
2334 * the text we're justifying to just before the magicline, which
2335 * is where it'll be anyway if we've searched the entire file,
2336 * and break out of the loop; otherwise, refresh the screen and
2337 * get out. */
2338 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002339 if (full_justify) {
2340 /* This should be safe in the event of filebot->prev's
2341 * being NULL, since only last_par_line->next is used if
2342 * we eventually unjustify. */
2343 last_par_line = filebot->prev;
2344 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002345 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002346 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002347 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002348 }
2349 }
2350
2351 /* Next step, we loop through the lines of this paragraph,
2352 * justifying each one individually. */
2353 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002354 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002355 size_t line_len;
2356 size_t display_len;
2357 /* The width of current in screen columns. */
2358 int break_pos;
2359 /* Where we will break the line. */
2360
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002361 /* We'll be moving to the next line after justifying the
2362 * current line in almost all cases, so allow changing the
2363 * spacing at the ends of justified lines by default. */
2364 allow_respacing = TRUE;
2365
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002366 indent_len = quote_len + indent_length(current->data +
2367 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002368
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002369 /* If we haven't already done it, copy the original
2370 * paragraph to the cutbuffer for unjustification. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002371 if (first_par_line == NULL)
2372 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002373 filebot->lineno - current->lineno : par_len, quote_len);
2374
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002375 /* Now we call justify_format() on the current line of the
2376 * paragraph, which will remove excess spaces from it and
2377 * change tabs to spaces. */
2378 justify_format(current, quote_len +
2379 indent_length(current->data + quote_len));
2380
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002381 line_len = strlen(current->data);
2382 display_len = strlenpt(current->data);
2383
2384 if (display_len > fill) {
2385 /* The line is too long. Try to wrap it to the next. */
2386 break_pos = break_line(current->data + indent_len,
2387 fill - strnlenpt(current->data, indent_len), TRUE);
2388 if (break_pos == -1 || break_pos + indent_len == line_len)
2389 /* We can't break the line, or don't need to, so
2390 * just go on to the next. */
2391 goto continue_loc;
2392 break_pos += indent_len;
2393 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002394 if (par_len == 1) {
2395 /* There is no next line in this paragraph. We make
2396 * a new line and copy text after break_pos into
2397 * it. */
2398 splice_node(current, make_new_node(current), current->next);
2399 /* In a non-quoted paragraph, we copy the indent
2400 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002401 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002402#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002403 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002404#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002405 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002406 indent_len = 0;
2407 current->next->data = charalloc(indent_len + line_len -
2408 break_pos);
2409 strncpy(current->next->data, current->data, indent_len);
2410 strcpy(current->next->data + indent_len,
2411 current->data + break_pos + 1);
2412 assert(strlen(current->next->data) ==
2413 indent_len + line_len - break_pos - 1);
2414 totlines++;
2415 totsize += indent_len;
2416 par_len++;
2417 } else {
2418 size_t next_line_len = strlen(current->next->data);
2419
2420 indent_len = quote_len +
2421 indent_length(current->next->data + quote_len);
2422 current->next->data = charealloc(current->next->data,
2423 next_line_len + line_len - break_pos + 1);
2424
2425 charmove(current->next->data + indent_len + line_len -
2426 break_pos, current->next->data + indent_len,
2427 next_line_len - indent_len + 1);
2428 strcpy(current->next->data + indent_len,
2429 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002430 current->next->data[indent_len + line_len -
2431 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002432#ifndef NANO_SMALL
2433 if (mark_beginbuf == current->next) {
2434 if (mark_beginx < indent_len)
2435 mark_beginx = indent_len;
2436 mark_beginx += line_len - break_pos;
2437 }
2438#endif
2439 }
2440#ifndef NANO_SMALL
2441 if (mark_beginbuf == current && mark_beginx > break_pos) {
2442 mark_beginbuf = current->next;
2443 mark_beginx -= break_pos + 1 - indent_len;
2444 }
2445#endif
2446 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002447
2448 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002449 current = current->next;
2450 } else if (display_len < fill && par_len > 1) {
2451 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002452
2453 indent_len = quote_len +
2454 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002455 /* If we can't pull a word from the next line up to this
2456 * one, just go on. */
2457 if (!breakable(current->next->data + indent_len,
2458 fill - display_len - 1))
2459 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002460
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002461 break_pos = break_line(current->next->data + indent_len,
2462 fill - display_len - 1, FALSE);
2463 assert(break_pos != -1);
2464
2465 current->data = charealloc(current->data,
2466 line_len + break_pos + 2);
2467 current->data[line_len] = ' ';
2468 strncpy(current->data + line_len + 1,
2469 current->next->data + indent_len, break_pos);
2470 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002471#ifndef NANO_SMALL
2472 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002473 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002474 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002475 if (mark_beginx <= indent_len)
2476 mark_beginx = line_len + 1;
2477 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002478 mark_beginx = line_len + 1 + mark_beginx -
2479 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002480 } else
2481 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002482 }
2483#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002484 next_line_len = strlen(current->next->data);
2485 if (indent_len + break_pos == next_line_len) {
2486 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002487
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002488 /* Don't destroy edittop! */
2489 if (line == edittop)
2490 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002491
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002492 unlink_node(line);
2493 delete_node(line);
2494 totlines--;
2495 totsize -= indent_len;
2496 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002497
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002498 /* Don't go to the next line. Accordingly, don't
2499 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002500 * previous justified line, so that we don't end up
2501 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002502 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002503 } else {
2504 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002505 current->next->data + indent_len + break_pos + 1,
2506 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002507 null_at(&current->next->data, next_line_len - break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002508
2509 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002510 current = current->next;
2511 }
2512 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002513 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002514 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002515 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002516
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002517 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002518 * current line. If the justified line was not the last
2519 * line of the paragraph, add a space to the end of it to
2520 * replace the one removed or left out by justify_format().
2521 * If it was the last line of the paragraph, and
2522 * justify_format() left a space on the end of it, remove
2523 * the space. */
2524 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002525 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002526
2527 if (par_len > 1) {
2528 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002529 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002530 current->prev->data[prev_line_len] = ' ';
2531 current->prev->data[prev_line_len + 1] = '\0';
2532 totsize++;
2533 } else if (par_len == 1 &&
2534 current->prev->data[prev_line_len - 1] == ' ') {
2535 current->prev->data = charealloc(current->prev->data,
2536 prev_line_len);
2537 current->prev->data[prev_line_len - 1] = '\0';
2538 totsize--;
2539 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002540 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002541 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002542
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002543 /* We've just justified a paragraph. If we're not justifying the
2544 * entire file, break out of the loop. Otherwise, continue the
2545 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002546 if (!full_justify)
2547 break;
2548
2549 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002550
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002551 /* We are now done justifying the paragraph or the file, so clean
2552 * up. totlines, totsize, and current_y have been maintained above.
2553 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002554 * fileage, and renumber() since edit_refresh() needs the line
2555 * numbers to be right (but only do the last two if we actually
2556 * justified something). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002557 last_par_line = current->prev;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002558 if (first_par_line != NULL) {
2559 if (first_par_line->prev == NULL)
2560 fileage = first_par_line;
2561 renumber(first_par_line);
2562 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002563
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002564 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002565
Chris Allegretta9149e612000-11-27 00:23:41 +00002566 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002567 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002568 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002569 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002570
Chris Allegretta6df90f52002-07-19 01:08:59 +00002571 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002572 * keystroke and return. */
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002573 kbinput = get_edit_input(&meta_key, FALSE);
Chris Allegretta5f071802001-05-06 02:34:31 +00002574
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002575 if (!meta_key && kbinput == NANO_UNJUSTIFY_KEY) {
2576 /* Restore the justify we just did (ungrateful user!). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002577 filestruct *cutbottom = get_cutbottom();
2578
Chris Allegretta6df90f52002-07-19 01:08:59 +00002579 current = current_save;
2580 current_x = current_x_save;
2581 current_y = current_y_save;
2582 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002583
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002584 /* Splice the cutbuffer back into the file, but only if we
2585 * actually justified something. */
2586 if (first_par_line != NULL) {
2587 cutbottom->next = last_par_line->next;
2588 cutbottom->next->prev = cutbottom;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002589 /* The line numbers after the end of the paragraph have been
2590 * changed, so we change them back. */
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002591 renumber(cutbottom->next);
2592 if (first_par_line->prev != NULL) {
2593 cutbuffer->prev = first_par_line->prev;
2594 cutbuffer->prev->next = cutbuffer;
2595 } else
2596 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002597
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002598 last_par_line->next = NULL;
2599 free_filestruct(first_par_line);
2600 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002601
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002602 /* Restore global variables from before the justify. */
2603 totsize = totsize_save;
2604 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002605#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002606 mark_beginbuf = mark_beginbuf_save;
2607 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002608#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002609 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002610 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002611 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612 edit_refresh();
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002613 } else {
2614 placewewant = 0;
David Lawrence Ramseydfca1c42004-08-25 16:37:06 +00002615 unget_kbinput(kbinput, meta_key);
Chris Allegretta9149e612000-11-27 00:23:41 +00002616 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002617
Chris Allegretta6df90f52002-07-19 01:08:59 +00002618 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002619 /* Note that now cutbottom is invalid, but that's okay. */
2620 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002621 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002622 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002623 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002624}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002625
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002626void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002627{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002628 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002629}
2630
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002631void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002632{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002633 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002634}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002635#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002636
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002637void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002638{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002639 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002640
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002641 if (!ISSET(MODIFIED))
2642 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002643 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002644 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002645 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002646 i = do_yesno(FALSE,
2647 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2648
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002649#ifdef DEBUG
2650 dump_buffer(fileage);
2651#endif
2652
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002653 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002654#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002655 /* Exit only if there are no more open buffers. */
2656 if (close_open_file() != 0)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002657#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002658 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002659 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002660 statusbar(_("Cancelled"));
2661
2662 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002663}
2664
2665void signal_init(void)
2666{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002667 /* Trap SIGINT and SIGQUIT because we want them to do useful
2668 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002669 memset(&act, 0, sizeof(struct sigaction));
2670 act.sa_handler = SIG_IGN;
2671 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002672 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002673
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002674 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002675 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002676 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002677 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002678
2679#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002680 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002681 act.sa_handler = handle_sigwinch;
2682 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002683 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002684#endif
2685
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002686 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002687 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002688 act.sa_handler = SIG_IGN;
2689 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002690 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002691 /* Block all other signals in the suspend and continue handlers.
2692 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002693 sigfillset(&act.sa_mask);
2694
2695 act.sa_handler = do_suspend;
2696 sigaction(SIGTSTP, &act, NULL);
2697
2698 act.sa_handler = do_cont;
2699 sigaction(SIGCONT, &act, NULL);
2700 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002701}
2702
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002703/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002704RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002705{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002706 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002707}
2708
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002709/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002710RETSIGTYPE do_suspend(int signal)
2711{
2712 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002713 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002714 fflush(stdout);
2715
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002716 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002717 tcsetattr(0, TCSANOW, &oldterm);
2718
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002719 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002720 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002721 act.sa_handler = handle_hupterm;
2722 sigaction(SIGHUP, &act, NULL);
2723 sigaction(SIGTERM, &act, NULL);
2724
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002725 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002726 kill(0, SIGSTOP);
2727}
2728
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002729/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002730RETSIGTYPE do_cont(int signal)
2731{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002732#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002733 /* Perhaps the user resized the window while we slept. Handle it
2734 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002735 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002736#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002737 /* Just update the screen. */
2738 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002739#endif
2740}
2741
2742#ifndef NANO_SMALL
2743void handle_sigwinch(int s)
2744{
2745 const char *tty = ttyname(0);
2746 int fd;
2747 int result = 0;
2748 struct winsize win;
2749
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002750 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002751 return;
2752 fd = open(tty, O_RDWR);
2753 if (fd == -1)
2754 return;
2755 result = ioctl(fd, TIOCGWINSZ, &win);
2756 close(fd);
2757 if (result == -1)
2758 return;
2759
2760 /* Could check whether the COLS or LINES changed, and return
2761 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2762 * variables, and in some cases ncurses has already updated them.
2763 * But not in all cases, argh. */
2764 COLS = win.ws_col;
2765 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002766 editwinrows = LINES - 5 + no_help();
2767 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002768 die_too_small();
2769
2770#ifndef DISABLE_WRAPJUSTIFY
2771 fill = wrap_at;
2772 if (fill <= 0)
2773 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002774 if (fill < 0)
2775 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002776#endif
2777
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002778 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002779 memset(hblank, ' ', COLS);
2780 hblank[COLS] = '\0';
2781
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002782#ifdef USE_SLANG
2783 /* Slang curses emulation brain damage, part 1: If we just do what
2784 * curses does here, it'll only work properly if the resize made the
2785 * window smaller. Do what mutt does: Leave and immediately reenter
2786 * Slang screen management mode. */
2787 SLsmg_reset_smg();
2788 SLsmg_init_smg();
2789#else
2790 /* Do the equivalent of what Minimum Profit does: Leave and
2791 * immediately reenter curses mode. */
2792 endwin();
2793 refresh();
2794#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002796 /* Restore the terminal to its previous state. */
2797 terminal_init();
2798
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002799 /* Do the equivalent of what both mutt and Minimum Profit do:
2800 * Reinitialize all the windows based on the new screen
2801 * dimensions. */
2802 window_init();
2803
2804 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002805 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002806 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002807 total_refresh();
2808
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002809 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002810 curs_set(1);
2811
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002812 /* Reset all the input routines that rely on character sequences. */
2813 reset_kbinput();
2814
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002815 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002816 siglongjmp(jmpbuf, 1);
2817}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002818
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002819void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002820{
2821 sigset_t winch;
2822 sigemptyset(&winch);
2823 sigaddset(&winch, SIGWINCH);
2824 if (allow)
2825 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2826 else
2827 sigprocmask(SIG_BLOCK, &winch, NULL);
2828}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002829#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002830
Chris Allegrettadab017e2002-04-23 10:56:06 +00002831#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002832void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002833{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002834 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002835
Chris Allegretta658399a2001-06-14 02:54:22 +00002836 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002837 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002838
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002839 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002840 case TOGGLE_SUSPEND_KEY:
2841 signal_init();
2842 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002843#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002844 case TOGGLE_MOUSE_KEY:
2845 mouse_init();
2846 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002847#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002848 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002849 blank_statusbar();
2850 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002851 wrefresh(bottomwin);
2852 window_init();
2853 edit_refresh();
2854 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002855 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002856 case TOGGLE_DOS_KEY:
2857 UNSET(MAC_FILE);
2858 break;
2859 case TOGGLE_MAC_KEY:
2860 UNSET(DOS_FILE);
2861 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002862#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002863 case TOGGLE_SYNTAX_KEY:
2864 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002865 break;
2866#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002867#ifdef ENABLE_NANORC
2868 case TOGGLE_WHITESPACE_KEY:
2869 edit_refresh();
2870 break;
2871#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002872 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002873
Chris Allegretta6df90f52002-07-19 01:08:59 +00002874 /* We are assuming here that shortcut_init() above didn't free and
2875 * reallocate the toggles. */
2876 enabled = ISSET(which->flag);
2877 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2878 enabled = !enabled;
2879 statusbar("%s %s", which->desc,
2880 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002881}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002882#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002883
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002884void disable_signals(void)
2885{
2886 struct termios term;
2887
2888 tcgetattr(0, &term);
2889 term.c_lflag &= ~ISIG;
2890 tcsetattr(0, TCSANOW, &term);
2891}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002892
2893#ifndef NANO_SMALL
2894void enable_signals(void)
2895{
2896 struct termios term;
2897
2898 tcgetattr(0, &term);
2899 term.c_lflag |= ISIG;
2900 tcsetattr(0, TCSANOW, &term);
2901}
2902#endif
2903
2904void disable_flow_control(void)
2905{
2906 struct termios term;
2907
2908 tcgetattr(0, &term);
2909 term.c_iflag &= ~(IXON|IXOFF);
2910 tcsetattr(0, TCSANOW, &term);
2911}
2912
2913void enable_flow_control(void)
2914{
2915 struct termios term;
2916
2917 tcgetattr(0, &term);
2918 term.c_iflag |= (IXON|IXOFF);
2919 tcsetattr(0, TCSANOW, &term);
2920}
2921
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002922/* Set up the terminal state. Put the terminal in cbreak mode (read one
2923 * character at a time and interpret the special control keys), disable
2924 * translation of carriage return (^M) into newline (^J) so that we can
2925 * tell the difference between the Enter key and Ctrl-J, and disable
2926 * echoing of characters as they're typed. Finally, disable
2927 * interpretation of the special control keys, and if we're not in
2928 * preserve mode, disable interpretation of the flow control characters
2929 * too. */
2930void terminal_init(void)
2931{
2932 cbreak();
2933 nonl();
2934 noecho();
2935 disable_signals();
2936 if (!ISSET(PRESERVE))
2937 disable_flow_control();
2938}
2939
David Lawrence Ramseya27bd652004-08-17 05:23:38 +00002940int main(int argc, char **argv)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002941{
2942 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002943 int startline = 0; /* Line to try and start at */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00002944#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002945 bool fill_flag_used = FALSE; /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00002946#endif
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00002947 int kbinput; /* Input from keyboard */
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002948 bool meta_key;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002949#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002950 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002951 {"help", 0, 0, 'h'},
2952#ifdef ENABLE_MULTIBUFFER
2953 {"multibuffer", 0, 0, 'F'},
2954#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002955#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00002956#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00002957 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00002958#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002959 {"ignorercfiles", 0, 0, 'I'},
2960#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002961#ifndef DISABLE_JUSTIFY
2962 {"quotestr", 1, 0, 'Q'},
2963#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00002964#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00002965 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00002966#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002967 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002968 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002969#ifdef ENABLE_COLOR
2970 {"syntax", 1, 0, 'Y'},
2971#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002972 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00002973 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002974 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002975#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002976 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002977#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00002978#ifndef DISABLE_OPERATINGDIR
2979 {"operatingdir", 1, 0, 'o'},
2980#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002981 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002982#ifndef DISABLE_WRAPJUSTIFY
2983 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002984#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002985#ifndef DISABLE_SPELLER
2986 {"speller", 1, 0, 's'},
2987#endif
2988 {"tempfile", 0, 0, 't'},
2989 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002990#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002991 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002992#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002993 {"nohelp", 0, 0, 'x'},
2994 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00002995#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00002996 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00002997 {"backup", 0, 0, 'B'},
2998 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00002999 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003000 {"mac", 0, 0, 'M'},
3001 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003002 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003003 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003004 {"autoindent", 0, 0, 'i'},
3005 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003006#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003007 {0, 0, 0, 0}
3008 };
3009#endif
3010
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003011 setlocale(LC_ALL, "");
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003012#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003013 bindtextdomain(PACKAGE, LOCALEDIR);
3014 textdomain(PACKAGE);
3015#endif
3016
Chris Allegretta7662c862003-01-13 01:35:15 +00003017#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003018 /* if we don't have rcfile support, we're root, and
3019 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003020 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003021 SET(NO_WRAP);
3022#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003023
Chris Allegretta6df90f52002-07-19 01:08:59 +00003024 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003025#ifdef HAVE_GETOPT_LONG
3026 getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
3027#else
3028 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003029#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003030 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003031
3032 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003033 case 'a':
3034 case 'b':
3035 case 'e':
3036 case 'f':
3037 case 'g':
3038 case 'j':
3039 /* Pico compatibility flags. */
3040 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003041#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003042 case 'A':
3043 SET(SMART_HOME);
3044 break;
3045 case 'B':
3046 SET(BACKUP_FILE);
3047 break;
3048 case 'D':
3049 SET(DOS_FILE);
3050 break;
3051 case 'E':
3052 backup_dir = mallocstrcpy(backup_dir, optarg);
3053 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003054#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003055#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003056 case 'F':
3057 SET(MULTIBUFFER);
3058 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003059#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003060#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003061#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003062 case 'H':
3063 SET(HISTORYLOG);
3064 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003065#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003066 case 'I':
3067 SET(NO_RCFILE);
3068 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003069#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003070#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003071 case 'M':
3072 SET(MAC_FILE);
3073 break;
3074 case 'N':
3075 SET(NO_CONVERT);
3076 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003077#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003078#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003079 case 'Q':
3080 quotestr = mallocstrcpy(quotestr, optarg);
3081 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003082#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003083#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003084 case 'R':
3085 SET(USE_REGEXP);
3086 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003087#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003088#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003089 case 'S':
3090 SET(SMOOTHSCROLL);
3091 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003092#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003093 case 'T':
3094 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003095 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
3096 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003097 exit(1);
3098 }
3099 break;
3100 case 'V':
3101 version();
3102 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003103#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003104 case 'Y':
3105 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3106 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00003107#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003108 case 'Z':
3109 SET(RESTRICTED);
3110 break;
3111 case 'c':
3112 SET(CONSTUPDATE);
3113 break;
3114 case 'd':
3115 SET(REBIND_DELETE);
3116 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003117#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003118 case 'i':
3119 SET(AUTOINDENT);
3120 break;
3121 case 'k':
3122 SET(CUT_TO_END);
3123 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003124#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003125 case 'l':
3126 SET(NOFOLLOW_SYMLINKS);
3127 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003128#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003129 case 'm':
3130 SET(USE_MOUSE);
3131 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003132#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003133#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003134 case 'o':
3135 operating_dir = mallocstrcpy(operating_dir, optarg);
3136 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003137#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003138 case 'p':
3139 SET(PRESERVE);
3140 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003141#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003142 case 'r':
3143 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003144 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
3145 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003146 exit(1);
3147 }
3148 fill_flag_used = TRUE;
3149 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003150#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003151#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003152 case 's':
3153 alt_speller = mallocstrcpy(alt_speller, optarg);
3154 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003155#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003156 case 't':
3157 SET(TEMP_FILE);
3158 break;
3159 case 'v':
3160 SET(VIEW_MODE);
3161 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003162#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003163 case 'w':
3164 SET(NO_WRAP);
3165 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003166#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003167 case 'x':
3168 SET(NO_HELP);
3169 break;
3170 case 'z':
3171 SET(SUSPEND);
3172 break;
3173 default:
3174 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003175 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003176 }
3177
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003178 /* If the executable filename starts with 'r', we use restricted
3179 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003180 if (*(tail(argv[0])) == 'r')
3181 SET(RESTRICTED);
3182
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003183 /* If we're using restricted mode, disable suspending, backups, and
3184 * reading rcfiles, since they all would allow reading from or
3185 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003186 if (ISSET(RESTRICTED)) {
3187 UNSET(SUSPEND);
3188 UNSET(BACKUP_FILE);
3189 SET(NO_RCFILE);
3190 }
3191
Chris Allegretta7662c862003-01-13 01:35:15 +00003192/* We've read through the command line options. Now back up the flags
3193 and values that are set, and read the rcfile(s). If the values
3194 haven't changed afterward, restore the backed-up values. */
3195#ifdef ENABLE_NANORC
3196 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003197#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003198 char *operating_dir_cpy = operating_dir;
3199#endif
David Lawrence Ramsey7e8dd192004-08-12 20:06:20 +00003200#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003201 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003202#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003203#ifndef NANO_SMALL
3204 char *backup_dir_cpy = backup_dir;
3205#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003206#ifndef DISABLE_JUSTIFY
3207 char *quotestr_cpy = quotestr;
3208#endif
3209#ifndef DISABLE_SPELLER
3210 char *alt_speller_cpy = alt_speller;
3211#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003212 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003213 long flags_cpy = flags;
3214
Chris Allegretta5ec68622003-02-05 02:39:34 +00003215#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003216 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003217#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003218#ifndef NANO_SMALL
3219 backup_dir = NULL;
3220#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003221#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003222 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003223#endif
3224#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003225 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003226#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003227
3228 do_rcfile();
3229
3230#ifndef DISABLE_OPERATINGDIR
3231 if (operating_dir_cpy != NULL) {
3232 free(operating_dir);
3233 operating_dir = operating_dir_cpy;
3234 }
3235#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003236#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003237 if (fill_flag_used)
3238 wrap_at = wrap_at_cpy;
3239#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003240#ifndef NANO_SMALL
3241 if (backup_dir_cpy != NULL) {
3242 free(backup_dir);
3243 backup_dir = backup_dir_cpy;
3244 }
3245#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003246#ifndef DISABLE_JUSTIFY
3247 if (quotestr_cpy != NULL) {
3248 free(quotestr);
3249 quotestr = quotestr_cpy;
3250 }
3251#endif
3252#ifndef DISABLE_SPELLER
3253 if (alt_speller_cpy != NULL) {
3254 free(alt_speller);
3255 alt_speller = alt_speller_cpy;
3256 }
3257#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00003258 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00003259 tabsize = tabsize_cpy;
3260 flags |= flags_cpy;
3261 }
3262#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003263 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003264 SET(NO_WRAP);
3265#endif
3266#endif /* ENABLE_NANORC */
3267
Chris Allegrettad8451932003-03-11 03:50:40 +00003268#ifndef NANO_SMALL
3269 history_init();
3270#ifdef ENABLE_NANORC
3271 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3272 load_history();
3273#endif
3274#endif
3275
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003276#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003277 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003278 * in which case backups are disabled, since they would allow
3279 * reading from or writing to files not specified on the command
3280 * line). This entails making sure it exists and is a directory, so
3281 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003282 if (!ISSET(RESTRICTED))
3283 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003284#endif
3285
Chris Allegretta7662c862003-01-13 01:35:15 +00003286#ifndef DISABLE_OPERATINGDIR
3287 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003288 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003289 init_operating_dir();
3290#endif
3291
Chris Allegretta7662c862003-01-13 01:35:15 +00003292#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003293 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003294 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003295
3296 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003297 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003298
Chris Allegretta7662c862003-01-13 01:35:15 +00003299 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003300 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003301#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003302 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003303#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003304 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003305#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003306 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003307#ifdef HAVE_REGEX_H
3308 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
3309
3310 if (quoterc == 0) {
3311 /* We no longer need quotestr, just quotereg. */
3312 free(quotestr);
3313 quotestr = NULL;
3314 } else {
3315 size_t size = regerror(quoterc, &quotereg, NULL, 0);
3316
3317 quoteerr = charalloc(size);
3318 regerror(quoterc, &quotereg, quoteerr, size);
3319 }
3320#else
3321 quotelen = strlen(quotestr);
3322#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00003323#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003324
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003325#ifndef DISABLE_SPELLER
3326 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003327 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003328 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003329 * checking is disabled, since it would allow reading from or
3330 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003331 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003332 char *spellenv = getenv("SPELL");
3333 if (spellenv != NULL)
3334 alt_speller = mallocstrcpy(NULL, spellenv);
3335 }
3336#endif
3337
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003338#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
3339 if (whitespace == NULL)
3340 whitespace = mallocstrcpy(NULL, " ");
3341#endif
3342
Chris Allegretta7662c862003-01-13 01:35:15 +00003343 if (tabsize == -1)
3344 tabsize = 8;
3345
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003346 /* Clear the filename we'll be using */
3347 filename = charalloc(1);
3348 filename[0] = '\0';
3349
Chris Allegretta7662c862003-01-13 01:35:15 +00003350 /* If there's a +LINE flag, it is the first non-option argument. */
3351 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3352 startline = atoi(&argv[optind][1]);
3353 optind++;
3354 }
3355 if (0 < optind && optind < argc)
3356 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003357
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003358 /* See if there's a non-option in argv (first non-option is the
3359 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003360 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003361 /* Look for the +line flag... */
3362 if (argv[optind][0] == '+') {
3363 startline = atoi(&argv[optind][1]);
3364 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003365 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003366 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003367 } else
3368 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003369 }
3370
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003371 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003372 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003373
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003374 /* Curses initialization stuff: Start curses and set up the
3375 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003376 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003377 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003378
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003379 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003380 global_init(FALSE);
3381 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003382
3383 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003384 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003385
3386#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003387 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003388#endif
3389
Chris Allegretta2a42af12000-09-12 23:02:49 +00003390 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003391#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003392 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003393#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003394
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003395#ifdef DEBUG
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003396 fprintf(stderr, "Main: top and bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003397#endif
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003398 titlebar(NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003399 display_main_list();
3400
3401#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003402 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003403#endif
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003404 open_file(filename, FALSE, FALSE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003405#ifdef ENABLE_MULTIBUFFER
3406 /* If we're using multibuffers and more than one file is specified
3407 on the command line, load them all and switch to the first one
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003408 afterward. */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003409 if (optind + 1 < argc) {
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003410 bool old_multibuffer = ISSET(MULTIBUFFER), list = FALSE;
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003411 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003412 for (optind++; optind < argc; optind++) {
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003413 add_open_file(TRUE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003414 new_file();
3415 filename = mallocstrcpy(filename, argv[optind]);
David Lawrence Ramsey6b248562004-08-07 22:33:14 +00003416 titlebar(NULL);
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003417 open_file(filename, FALSE, FALSE);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003418 load_file(FALSE);
David Lawrence Ramsey69a28122004-08-12 04:34:00 +00003419 /* Display the main list with "Close" if we haven't
3420 * already. */
3421 if (!list) {
3422 shortcut_init(FALSE);
3423 list = TRUE;
3424 display_main_list();
3425 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003426 }
3427 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003428 if (!old_multibuffer)
3429 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003430 }
3431#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003432
3433 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003434 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003435
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003436#ifndef NANO_SMALL
3437 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003438 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003439#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003440
Robert Siemborski6967eec2000-07-08 14:23:32 +00003441 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00003442
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003443 while (TRUE) {
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00003444 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003445 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003446 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003447
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003448#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003449 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003450#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003451
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003452 kbinput = get_edit_input(&meta_key, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003453
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003454 /* Last gasp, stuff that's not in the main lists. */
3455 if (kbinput != ERR && !is_cntrl_char(kbinput)) {
3456 /* Don't stop unhandled sequences, so that people with odd
3457 * character sets can type. */
3458 if (ISSET(VIEW_MODE))
3459 print_view_warning();
3460 else
3461 do_char(kbinput);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003462 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003463 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003464 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003465}