blob: 5e006b7db04c42aa7ef7045600dced42a48eb834 [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>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000031#include <sys/ioctl.h>
32#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000033#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000034#include <errno.h>
35#include <ctype.h>
36#include <locale.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000037#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000038#include "proto.h"
39#include "nano.h"
40
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000041#ifdef HAVE_TERMIOS_H
42#include <termios.h>
43#endif
44
45#ifdef HAVE_TERMIO_H
46#include <termio.h>
47#endif
48
49#ifdef HAVE_GETOPT_H
50#include <getopt.h>
51#endif
52
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000053#ifndef NANO_SMALL
54#include <setjmp.h>
55#endif
56
Chris Allegretta6fe61492001-05-21 12:56:25 +000057#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000058static ssize_t fill = 0; /* Fill - where to wrap lines,
59 basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000060#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000061#ifndef DISABLE_WRAPPING
David Lawrence Ramseyce62e822004-08-05 22:10:22 +000062static bool same_line_wrap = FALSE; /* Whether wrapped text should
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000063 be prepended to the next
64 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000065#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000066
Chris Allegretta6df90f52002-07-19 01:08:59 +000067static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000068static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000069
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000070#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000071static sigjmp_buf jmpbuf; /* Used to return to mainloop after
72 SIGWINCH */
David Lawrence Ramsey22fac782004-08-05 15:16:19 +000073static int pid; /* The PID of the newly forked process
74 * in open_pipe(). It must be global
75 * because the signal handler needs
76 * it. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000077#endif
Chris Allegretta08020882001-01-29 23:37:54 +000078
David Lawrence Ramseyda141062004-05-25 19:41:11 +000079/* What we do when we're all set to exit. */
80void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000081{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000082 if (!ISSET(NO_HELP))
83 blank_bottombars();
84 else
85 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000086
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000087 wrefresh(bottomwin);
88 endwin();
89
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000090 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000091 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000092
Chris Allegrettad8451932003-03-11 03:50:40 +000093#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
94 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
95 save_history();
96#endif
97
Chris Allegretta6232d662002-05-12 19:52:15 +000098#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000099 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000100#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000101
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000102 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000103}
104
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000105/* Die (gracefully?). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000106void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000107{
108 va_list ap;
109
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000110 endwin();
111 curses_ended = TRUE;
112
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000113 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000114 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000115
Chris Allegretta6df90f52002-07-19 01:08:59 +0000116 va_start(ap, msg);
117 vfprintf(stderr, msg, ap);
118 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000119
Chris Allegretta32da4562002-01-02 15:12:21 +0000120 /* save the currently loaded file if it's been modified */
121 if (ISSET(MODIFIED))
122 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000123
Chris Allegretta355fbe52001-07-14 19:32:47 +0000124#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000125 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000126 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000127 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000128
129 tmp = open_files;
130
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000131 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000132 open_files = open_files->prev;
133
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000134 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000135
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000136 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000137 currently loaded file), don't save it again */
138 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000139 /* make sure open_files->fileage and fileage, and
140 open_files->filebot and filebot, are in sync; they
141 might not be if lines have been cut from the top or
142 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000143 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000144 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000145 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000146 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000147 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000148 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149 open_files = open_files->next;
150 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000151 }
152#endif
153
Chris Allegretta6df90f52002-07-19 01:08:59 +0000154 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000155}
156
Chris Allegretta6df90f52002-07-19 01:08:59 +0000157void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000158{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000159 char *ret;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000160 bool failed = TRUE;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000161
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000162 /* If we're using restricted mode, don't write any emergency backup
163 * files, since that would allow reading from or writing to files
164 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000165 if (ISSET(RESTRICTED))
166 return;
167
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168 /* If we can't save, we have REAL bad problems, but we might as well
169 TRY. */
170 if (die_filename[0] == '\0')
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000171 die_filename = "nano";
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000173 ret = get_next_filename(die_filename);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174 if (ret[0] != '\0')
David Lawrence Ramsey951d7142004-10-04 15:23:47 +0000175 failed = (write_file(ret, TRUE, FALSE, TRUE) == -1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000176
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000177 if (!failed)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000179 else
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000180 fprintf(stderr, _("\nBuffer not written to %s (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000181
182 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000183}
184
Chris Allegrettae61e8302001-01-14 05:18:27 +0000185/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000186 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000187void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000188{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000189 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000190}
191
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192void print_view_warning(void)
193{
194 statusbar(_("Key illegal in VIEW mode"));
195}
196
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000197/* Initialize global variables -- no better way for now. If
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000198 * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
199void global_init(bool save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000200{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000201 current_x = 0;
202 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000203
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000204 editwinrows = LINES - 5 + no_help();
205 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000206 die_too_small();
207
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000209 if (!save_cutbuffer)
210 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000211 current = NULL;
212 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000214 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000216
Chris Allegretta6fe61492001-05-21 12:56:25 +0000217#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000218 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000219 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000220 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000221 if (fill < 0)
222 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000223#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000224
Chris Allegretta88b09152001-05-17 11:35:43 +0000225 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000226 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000227 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000228}
229
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000230void window_init(void)
231{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000232 editwinrows = LINES - 5 + no_help();
233 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000234 die_too_small();
235
Chris Allegretta1a128af2003-01-26 04:15:56 +0000236 if (topwin != NULL)
237 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000238 if (edit != NULL)
239 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000240 if (bottomwin != NULL)
241 delwin(bottomwin);
242
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000243 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000244 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000245 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
247
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000248 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249 keypad(edit, TRUE);
250 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251}
252
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000253#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000254void mouse_init(void)
255{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257 mousemask(BUTTON1_RELEASED, NULL);
258 mouseinterval(50);
259 } else
260 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000261}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000262#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000263
264#ifndef DISABLE_HELP
265/* This function allocates help_text, and stores the help string in it.
266 * help_text should be NULL initially. */
267void help_init(void)
268{
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000269 size_t allocsize = 1; /* Space needed for help_text. */
270 const char *htx; /* Untranslated help message. */
271 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000272 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000273#ifndef NANO_SMALL
274 const toggle *t;
275#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000276
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000277 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000278 if (currshortcut == whereis_list || currshortcut == replace_list
279 || currshortcut == replace_list_2)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000280 htx = N_("Search Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000281 "Enter the words or characters you would like to search "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000282 "for, then hit Enter. If there is a match for the text you "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000283 "entered, the screen will be updated to the location of the "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000284 "nearest match for the search string.\n\n The previous "
285 "search string will be shown in brackets after the search "
286 "prompt. Hitting Enter without entering any text will "
287 "perform the previous search. If you have selected text "
288 "with the mark and then search to replace, only matches in "
289 "the selected text will be replaced.\n\n The following "
290 "function keys are available in Search mode:\n\n");
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000291 else if (currshortcut == gotoline_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 "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000316 "selected text with the mark, you will be prompted to "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000317 "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, "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000338 "you can use the Tab key to (attempt to) automatically "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000339 "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 "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000350 "current file, or, if you have selected text with the "
351 "mark, in the selected text.\n\n The following other "
352 "functions are available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000353#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000354#ifndef NANO_SMALL
355 else if (currshortcut == extcmd_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000356 htx = N_("External Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000357 "This menu allows you to insert the output of a command "
358 "run by the shell into the current buffer (or a new "
359 "buffer in multibuffer mode).\n\n The following keys are "
360 "available in this mode:\n\n");
361#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000362 else
363 /* Default to the main help list. */
364 htx = N_(" nano help text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000365 "The nano editor is designed to emulate the functionality and "
366 "ease-of-use of the UW Pico text editor. There are four main "
367 "sections of the editor: The top line shows the program "
368 "version, the current filename being edited, and whether "
369 "or not the file has been modified. Next is the main editor "
370 "window showing the file being edited. The status line is "
371 "the third line from the bottom and shows important messages. "
372 "The bottom two lines show the most commonly used shortcuts "
373 "in the editor.\n\n "
374 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000375 "sequences are notated with a caret (^) symbol and can be "
376 "entered either by using the Control (Ctrl) key or pressing the "
377 "Esc key twice. Escape-key sequences are notated with the Meta "
378 "(M) symbol and can be entered using either the Esc, Alt or "
379 "Meta key depending on your keyboard setup. Also, pressing Esc "
380 "twice and then typing a three-digit number from 000 to 255 "
381 "will enter the character with the corresponding ASCII code. "
382 "The following keystrokes are available in the main editor "
383 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000384
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000385 htx = _(htx);
386
387 allocsize += strlen(htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000388
389 /* The space needed for the shortcut lists, at most COLS characters,
390 * plus '\n'. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000391 allocsize += (COLS < 21 ? 21 : COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000392
393#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000394 /* If we're on the main list, we also count the toggle help text.
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000395 * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
396 * plus translated text, plus '\n'. */
Chris Allegretta3a784062003-02-10 02:32:58 +0000397 if (currshortcut == main_list) {
398 size_t endislen = strlen(_("enable/disable"));
399
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000400 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000401 allocsize += 8 + strlen(t->desc) + endislen;
402 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000403#endif /* !NANO_SMALL */
404
405 /* help_text has been freed and set to NULL unless the user resized
406 * while in the help screen. */
407 free(help_text);
408
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000409 /* Allocate space for the help text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000410 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000411
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000412 /* Now add the text we want. */
413 strcpy(help_text, htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000414 ptr = help_text + strlen(help_text);
415
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000416 /* Now add our shortcut info. Assume that each shortcut has, at the
417 * very least, an equivalent control key, an equivalent primary meta
418 * key sequence, or both. Also assume that the meta key values are
419 * not control characters. We can display a maximum of 3 shortcut
420 * entries. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000421 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000422 int entries = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000423
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000424 /* Control key. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000425 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000426 entries++;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000427#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000428 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000429 ptr += sprintf(ptr, "%.7s", _("Up"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000430 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000431#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000432 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000433 ptr += sprintf(ptr, "^%.6s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000434 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000435 ptr += sprintf(ptr, "^?");
436 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000437 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000438 *(ptr++) = '\t';
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000439 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000440
441 /* Function key. */
442 if (s->funcval != NANO_NO_KEY) {
443 entries++;
David Lawrence Ramsey2e83a502004-11-01 22:35:26 +0000444 /* If this is the first entry, put it in the middle. */
445 if (entries == 1) {
446 entries++;
447 *(ptr++) = '\t';
448 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000449 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
450 *(ptr++) = '\t';
451 }
452
453 /* Primary meta key sequence. */
454 if (s->metaval != NANO_NO_KEY) {
455 entries++;
456 /* If this is the last entry, put it at the end. */
457 if (entries == 2 && s->miscval == NANO_NO_KEY) {
458 entries++;
459 *(ptr++) = '\t';
460 }
461 /* If the primary meta key sequence is the first entry,
462 * don't put parentheses around it. */
463 if (entries == 1 && s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000464 ptr += sprintf(ptr, "M-%.5s", _("Space"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000465 else
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000466 ptr += sprintf(ptr, entries == 1 ? "M-%c" : "(M-%c)",
467 toupper(s->metaval));
468 *(ptr++) = '\t';
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000469 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000470
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000471 /* Miscellaneous meta key sequence. */
472 if (entries < 3 && s->miscval != NANO_NO_KEY) {
473 entries++;
474 /* If this is the last entry, put it at the end. */
475 if (entries == 2) {
476 entries++;
477 *(ptr++) = '\t';
478 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000479 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000480 *(ptr++) = '\t';
481 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000482
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000483 /* Make sure all the help text starts at the same place. */
484 while (entries < 3) {
485 entries++;
486 *(ptr++) = '\t';
487 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000488
489 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000490 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000491 }
492
493#ifndef NANO_SMALL
494 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000495 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000496 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000497 assert(t->desc != NULL);
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +0000498 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
499 t->desc, _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000500 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000501 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000502#endif /* !NANO_SMALL */
503
504 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000505 * help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000506 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000507}
508#endif
509
510/* Create a new filestruct node. Note that we specifically do not set
511 * prevnode->next equal to the new line. */
512filestruct *make_new_node(filestruct *prevnode)
513{
514 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
515
516 newnode->data = NULL;
517 newnode->prev = prevnode;
518 newnode->next = NULL;
519 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
520
521 return newnode;
522}
523
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000524/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000525filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000526{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000527 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000528
Chris Allegretta6df90f52002-07-19 01:08:59 +0000529 assert(src != NULL);
530
Chris Allegretta88b09152001-05-17 11:35:43 +0000531 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000532 dst->next = src->next;
533 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000534 strcpy(dst->data, src->data);
535 dst->lineno = src->lineno;
536
537 return dst;
538}
539
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000540/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000541void splice_node(filestruct *begin, filestruct *newnode, filestruct
542 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000543{
544 if (newnode != NULL) {
545 newnode->next = end;
546 newnode->prev = begin;
547 }
548 if (begin != NULL)
549 begin->next = newnode;
550 if (end != NULL)
551 end->prev = newnode;
552}
553
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000554/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000555void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000556{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000557 assert(fileptr != NULL);
558
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000559 if (fileptr->prev != NULL)
560 fileptr->prev->next = fileptr->next;
561
562 if (fileptr->next != NULL)
563 fileptr->next->prev = fileptr->prev;
564}
565
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000566/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000567void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000568{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000569 if (fileptr != NULL) {
570 if (fileptr->data != NULL)
571 free(fileptr->data);
572 free(fileptr);
573 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574}
575
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000576/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000577filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000578{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000579 filestruct *head; /* copy of src, top of the copied list */
580 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581
Chris Allegretta6df90f52002-07-19 01:08:59 +0000582 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583
Chris Allegretta6df90f52002-07-19 01:08:59 +0000584 prev = copy_node(src);
585 prev->prev = NULL;
586 head = prev;
587 src = src->next;
588 while (src != NULL) {
589 prev->next = copy_node(src);
590 prev->next->prev = prev;
591 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000592
Chris Allegretta6df90f52002-07-19 01:08:59 +0000593 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594 }
595
Chris Allegretta6df90f52002-07-19 01:08:59 +0000596 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000597 return head;
598}
599
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000600/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000601void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000602{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000603 if (src != NULL) {
604 while (src->next != NULL) {
605 src = src->next;
606 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000607#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000608 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000609#endif
610 }
611 delete_node(src);
612#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000613 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000614#endif
615 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000616}
617
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000618/* Partition a filestruct so it begins at (top, top_x) and ends at (bot,
619 * bot_x). */
620partition *partition_filestruct(filestruct *top, size_t top_x,
621 filestruct *bot, size_t bot_x)
622{
623 partition *p;
624 assert(top != NULL && bot != NULL);
625
626 /* Initialize the partition. */
627 p = (partition *)nmalloc(sizeof(partition));
628
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000629 /* If the top and bottom of the partition are different from the top
630 * and bottom of the filestruct, save the latter and then set them
631 * to top and bot. */
632 if (top != fileage) {
633 p->fileage = fileage;
634 fileage = top;
635 } else
636 p->fileage = NULL;
637 if (bot != filebot) {
638 p->filebot = filebot;
639 filebot = bot;
640 } else
641 p->filebot = NULL;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000642
643 /* Save the line above the top of the partition, detach the top of
644 * the partition from it, and save the text before top_x in
645 * top_data. */
646 p->top_prev = top->prev;
647 top->prev = NULL;
648 p->top_data = mallocstrncpy(NULL, top->data, top_x + 1);
649 p->top_data[top_x] = '\0';
650
651 /* Save the line below the bottom of the partition, detach the
652 * bottom of the partition from it, and save the text after bot_x in
653 * bot_data. */
654 p->bot_next = bot->next;
655 bot->next = NULL;
656 p->bot_data = mallocstrcpy(NULL, bot->data + bot_x);
657
658 /* Remove all text after bot_x at the bottom of the partition. */
659 null_at(&bot->data, bot_x);
660
661 /* Remove all text before top_x at the top of the partition. */
662 charmove(top->data, top->data + top_x, strlen(top->data) -
663 top_x + 1);
664 align(&top->data);
665
666 /* Return the partition. */
667 return p;
668}
669
670/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
671 * (filebot, strlen(filebot)) again. */
672void unpartition_filestruct(partition *p)
673{
674 char *tmp;
675 assert(p != NULL);
676
677 /* Reattach the line above the top of the partition, and restore the
678 * text before top_x from top_data. Free top_data when we're done
679 * with it. */
680 tmp = mallocstrcpy(NULL, fileage->data);
681 fileage->prev = p->top_prev;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000682 if (fileage->prev != NULL)
683 fileage->prev->next = fileage;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000684 fileage->data = charealloc(fileage->data, strlen(p->top_data) +
685 strlen(fileage->data) + 1);
686 strcpy(fileage->data, p->top_data);
687 free(p->top_data);
688 strcat(fileage->data, tmp);
689 free(tmp);
690
691 /* Reattach the line below the bottom of the partition, and restore
692 * the text after bot_x from bot_data. Free bot_data when we're
693 * done with it. */
694 filebot->next = p->bot_next;
David Lawrence Ramsey8cbd4cb2004-11-04 15:31:43 +0000695 if (filebot->next != NULL)
696 filebot->next->prev = filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000697 filebot->data = charealloc(filebot->data, strlen(filebot->data) +
698 strlen(p->bot_data) + 1);
699 strcat(filebot->data, p->bot_data);
700 free(p->bot_data);
701
David Lawrence Ramseyf978f042004-11-04 16:45:48 +0000702 /* Restore the top and bottom of the filestruct, if they were
703 * different from the top and bottom of the partition. */
704 if (p->fileage != NULL)
705 fileage = p->fileage;
706 if (p->filebot != NULL)
707 filebot = p->filebot;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000708
709 /* Uninitialize the partition. */
710 free(p);
711 p = NULL;
712}
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +0000713
Chris Allegretta6df90f52002-07-19 01:08:59 +0000714void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000715{
716 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000717 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000718
Chris Allegretta6df90f52002-07-19 01:08:59 +0000719 assert(fileage == NULL || fileage != fileage->next);
720 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000721 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000722}
723
Chris Allegretta6df90f52002-07-19 01:08:59 +0000724void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000725{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000726 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000727 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000728 else {
729 int lineno = fileptr->prev->lineno;
730
731 assert(fileptr != fileptr->next);
732 for (; fileptr != NULL; fileptr = fileptr->next)
733 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000734 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000735}
736
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000737/* Print one usage string to the screen. This cuts down on duplicate
738 * strings to translate and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000739 * translatable (the flag names). */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000740void print1opt(const char *shortflag, const char *longflag, const char
741 *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000742{
743 printf(" %s\t", shortflag);
744 if (strlen(shortflag) < 8)
745 printf("\t");
746
747#ifdef HAVE_GETOPT_LONG
748 printf("%s\t", longflag);
749 if (strlen(longflag) < 8)
750 printf("\t\t");
751 else if (strlen(longflag) < 16)
752 printf("\t");
753#endif
754
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000755 printf("%s\n", _(desc));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000756}
757
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000758void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000759{
760#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000761 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
762 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000763#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000764 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
765 printf(_("Option\t\tMeaning\n"));
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +0000766#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000767
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000768 print1opt("-h, -?", "--help", N_("Show this message"));
769 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000770#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000771 print1opt("-A", "--smarthome", N_("Enable smart home key"));
772 print1opt("-B", "--backup", N_("Backup existing files on save"));
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000773 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000774#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000775#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000776 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000777#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000778#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000779#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000780 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000781#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000782 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000783#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000784#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000785 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000786#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000787#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000788 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000789#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000790#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000791 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000792#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000793#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000794 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000795#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000796 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
797 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000798#ifdef ENABLE_COLOR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000799 print1opt(_("-Y [str]"), _("--syntax [str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000800#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000801 print1opt("-Z", "--restricted", N_("Restricted mode"));
802 print1opt("-c", "--const", N_("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000803#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000804 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
805 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
806 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000807#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000808 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000809#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000810 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000811#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000812#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000813 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000814#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000815 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000816#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000817 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000818#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000819#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000820 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000821#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000822 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
823 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000824#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000825 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000826#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000827 print1opt("-x", "--nohelp", N_("Don't show help window"));
828 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000829
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000830 /* This is a special case. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000831 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000832
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000833 exit(0);
834}
835
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000836void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000837{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000838 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000839 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000840 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000841 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000842 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000843
Chris Allegrettae6600372003-01-17 03:39:41 +0000844#ifndef ENABLE_NLS
845 printf(" --disable-nls");
846#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000847#ifdef DEBUG
848 printf(" --enable-debug");
849#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000850#ifdef NANO_EXTRA
851 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000852#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000853#ifdef NANO_SMALL
854 printf(" --enable-tiny");
855#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000856#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000857 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000858#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000859#ifdef DISABLE_HELP
860 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000861#endif
862#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000863 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000864#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000865#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000866 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000867#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000868#ifdef DISABLE_OPERATINGDIR
869 printf(" --disable-operatingdir");
870#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000871#ifdef DISABLE_SPELLER
872 printf(" --disable-speller");
873#endif
874#ifdef DISABLE_TABCOMP
875 printf(" --disable-tabcomp");
876#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000877#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000878#ifdef DISABLE_WRAPPING
879 printf(" --disable-wrapping");
880#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000881#ifdef DISABLE_ROOTWRAP
882 printf(" --disable-wrapping-as-root");
883#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000884#ifdef ENABLE_COLOR
885 printf(" --enable-color");
886#endif
887#ifdef ENABLE_MULTIBUFFER
888 printf(" --enable-multibuffer");
889#endif
890#ifdef ENABLE_NANORC
891 printf(" --enable-nanorc");
892#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000893#ifdef USE_SLANG
894 printf(" --with-slang");
895#endif
896 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000897}
898
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000899int no_help(void)
900{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000901 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000902}
903
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000904void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000905{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000906 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000907}
908
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000909#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000910RETSIGTYPE cancel_fork(int signal)
911{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000912 if (kill(pid, SIGKILL) == -1)
913 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000914}
915
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000916/* Return TRUE on success. */
917bool open_pipe(const char *command)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000918{
919 int fd[2];
920 FILE *f;
921 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000922 /* Original and temporary handlers for
923 * SIGINT. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000924 bool sig_failed = FALSE;
925 /* sig_failed means that sigaction() failed without changing the
926 * signal handlers.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000927 *
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000928 * We use this variable since it is important to put things back
929 * when we finish, even if we get errors. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000930
931 /* Make our pipes. */
932
933 if (pipe(fd) == -1) {
934 statusbar(_("Could not pipe"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000935 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000936 }
937
938 /* Fork a child. */
939
940 if ((pid = fork()) == 0) {
941 close(fd[0]);
942 dup2(fd[1], fileno(stdout));
943 dup2(fd[1], fileno(stderr));
944 /* If execl() returns at all, there was an error. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000945
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000946 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000947 exit(0);
948 }
949
950 /* Else continue as parent. */
951
952 close(fd[1]);
953
954 if (pid == -1) {
955 close(fd[0]);
956 statusbar(_("Could not fork"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000957 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000958 }
959
960 /* Before we start reading the forked command's output, we set
961 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000962
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000963 /* Enable interpretation of the special control keys so that we get
964 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000965 enable_signals();
966
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000967 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000968 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000969 nperror("sigaction");
970 } else {
971 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000972 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000973 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000974 nperror("sigaction");
975 }
976 }
977 /* Note that now oldaction is the previous SIGINT signal handler,
978 * to be restored later. */
979
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000980 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000981 if (f == NULL)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000982 nperror("fdopen");
David Lawrence Ramsey00d77982004-08-07 21:27:37 +0000983
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000984 read_file(f, "stdin");
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000985 /* If multibuffer mode is on, we could be here in view mode. If so,
986 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000987 if (!ISSET(VIEW_MODE))
988 set_modified();
989
990 if (wait(NULL) == -1)
991 nperror("wait");
992
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000993 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000994 nperror("sigaction");
995
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000996 /* Disable interpretation of the special control keys so that we can
997 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000998 disable_signals();
999
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001000 return TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001001}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +00001002#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001003
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001004/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001005void do_char(char ch)
1006{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001007 size_t current_len = strlen(current->data);
1008#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001009 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001010 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +00001011 * update_line()? */
1012#endif
1013
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001014 if (ch == '\0') /* Null to newline, if needed. */
1015 ch = '\n';
1016 else if (ch == '\n') { /* Newline to Enter, if needed. */
1017 do_enter();
1018 return;
1019 }
1020
1021 assert(current != NULL && current->data != NULL);
1022
1023 /* When a character is inserted on the current magicline, it means
1024 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001025 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +00001026 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +00001027
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001028 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001029 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001030 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001031 charmove(&current->data[current_x + 1], &current->data[current_x],
1032 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001033 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001034 totsize++;
1035 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001036
Chris Allegretta6df90f52002-07-19 01:08:59 +00001037#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001038 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001039 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001040 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001041#endif
1042
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001043 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001044
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001045#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001046 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +00001047 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001048 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001049#endif
1050
Chris Allegretta6df90f52002-07-19 01:08:59 +00001051#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001052 /* If color syntaxes are turned on, we need to call
1053 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +00001054 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001055 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001056#endif
1057
1058#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001059 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001060 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001061 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00001062#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001063 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001064}
1065
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001066void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001067{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001068 int *v_kbinput = NULL; /* Used to hold verbatim input. */
1069 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +00001070 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001071
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001072 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001073
David Lawrence Ramsey6da969e2004-08-28 15:51:07 +00001074 v_kbinput = get_verbatim_kbinput(edit, ERR, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001075
1076 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1077 * off afterwards, so that if constant cursor position display is
1078 * on, it will be updated properly. */
1079 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001080 for (i = 0; i < v_len; i++)
1081 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001082 UNSET(DISABLE_CURPOS);
1083
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001084 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001085}
1086
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001087void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001088{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001089 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001090 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001091 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001092 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001093}
1094
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001095void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001096{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001097 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001098 /* Do we have to call edit_refresh(), or can we get away with
1099 * update_line()? */
1100
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001101 assert(current != NULL && current->data != NULL && current_x <=
1102 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001103
1104 placewewant = xplustabs();
1105
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001106 if (current->data[current_x] != '\0') {
1107 size_t linelen = strlen(current->data + current_x);
1108
1109 assert(current_x < strlen(current->data));
1110
1111 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001112 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001113 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001114
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001115 null_at(&current->data, linelen + current_x - 1);
1116#ifndef NANO_SMALL
1117 if (current_x < mark_beginx && mark_beginbuf == current)
1118 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001119#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001120 } else if (current != filebot && (current->next != filebot ||
1121 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001122 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001123 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001124 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001125
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001126 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001127
1128 /* If we're deleting at the end of a line, we need to call
1129 * edit_refresh(). */
1130 if (current->data[current_x] == '\0')
1131 do_refresh = TRUE;
1132
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001133 current->data = charealloc(current->data, current_x +
1134 strlen(foo->data) + 1);
1135 strcpy(current->data + current_x, foo->data);
1136#ifndef NANO_SMALL
1137 if (mark_beginbuf == current->next) {
1138 mark_beginx += current_x;
1139 mark_beginbuf = current;
1140 }
1141#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001142 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001143 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001144
1145 unlink_node(foo);
1146 delete_node(foo);
1147 renumber(current);
1148 totlines--;
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001149#ifndef DISABLE_WRAPPING
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001150 wrap_reset();
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001151#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001152 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001153 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001154
1155 totsize--;
1156 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001157
1158#ifdef ENABLE_COLOR
1159 /* If color syntaxes are turned on, we need to call
1160 * edit_refresh(). */
1161 if (ISSET(COLOR_SYNTAX))
1162 do_refresh = TRUE;
1163#endif
1164
1165 if (do_refresh)
1166 edit_refresh();
1167 else
1168 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001169}
1170
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001171void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001172{
1173 do_char('\t');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001174}
1175
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001176/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001177void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001179 filestruct *newnode = make_new_node(current);
1180 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181
Chris Allegretta6df90f52002-07-19 01:08:59 +00001182 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183
Chris Allegrettaff989832001-09-17 13:48:00 +00001184#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001185 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001186 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001187 /* If we are breaking the line in the indentation, the new
1188 * indentation should have only current_x characters, and
1189 * current_x should not change. */
1190 extra = indent_length(current->data);
1191 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001192 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001193 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001194 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001195#endif
1196 newnode->data = charalloc(strlen(current->data + current_x) +
1197 extra + 1);
1198 strcpy(&newnode->data[extra], current->data + current_x);
1199#ifndef NANO_SMALL
1200 if (ISSET(AUTOINDENT))
1201 strncpy(newnode->data, current->data, extra);
1202#endif
1203 null_at(&current->data, current_x);
1204#ifndef NANO_SMALL
1205 if (current == mark_beginbuf && current_x < mark_beginx) {
1206 mark_beginbuf = newnode;
1207 mark_beginx += extra - current_x;
1208 }
1209#endif
1210 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001211
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001212 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001213 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001214 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001215
1216 totsize++;
1217 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001218 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001219
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001220 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001221
1222 totlines++;
1223 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001224 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001225}
1226
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001227#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001228void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001229{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001230 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001231 const filestruct *old_current = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001232 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001233
Chris Allegretta6df90f52002-07-19 01:08:59 +00001234 /* Skip letters in this word first. */
1235 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001236 isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001237 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001238
Chris Allegretta6df90f52002-07-19 01:08:59 +00001239 for (; current != NULL; current = current->next) {
1240 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001241 !isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001242 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001243
Chris Allegretta6df90f52002-07-19 01:08:59 +00001244 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001245 break;
1246
Chris Allegretta6df90f52002-07-19 01:08:59 +00001247 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001248 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001249 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001250 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001251
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001252 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001253
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001254 /* Update the screen. */
1255 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001256}
1257
Chris Allegretta6df90f52002-07-19 01:08:59 +00001258/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001259void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001260{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001261 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001262 const filestruct *old_current = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001263 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001264
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001265 current_x++;
1266
Chris Allegretta6df90f52002-07-19 01:08:59 +00001267 /* Skip letters in this word first. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001268 while (current_x > 0 && isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001269 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001270
Chris Allegretta6df90f52002-07-19 01:08:59 +00001271 for (; current != NULL; current = current->prev) {
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001272 while (current_x > 0 && !isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001273 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001274
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001275 if (current_x > 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001276 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001277
Chris Allegretta6df90f52002-07-19 01:08:59 +00001278 if (current->prev != NULL)
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001279 current_x = strlen(current->prev->data) + 1;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001280 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001281
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001282 current_x--;
1283
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001284 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001285 current = fileage;
1286 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001287 } else {
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001288 while (current_x > 0 && isalnum(current->data[current_x - 1]))
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001289 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001290 }
1291
Chris Allegretta76e291b2001-10-14 19:05:10 +00001292 placewewant = xplustabs();
1293
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001294 /* Update the screen. */
1295 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001296}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001297
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001298void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001299{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001300 TOGGLE(MARK_ISSET);
1301 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001302 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001303 mark_beginbuf = current;
1304 mark_beginx = current_x;
1305 } else {
1306 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001307 edit_refresh();
1308 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001309}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001310#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001311
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001312#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001313void wrap_reset(void)
1314{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001315 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001316}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001317#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001318
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001319#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001320/* We wrap the given line. Precondition: we assume the cursor has been
1321 * moved forward since the last typed character. Return value: whether
1322 * we wrapped. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001323bool do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001324{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001325 size_t len = strlen(inptr->data);
1326 /* Length of the line we wrap. */
1327 size_t i = 0;
1328 /* Generic loop variable. */
1329 int wrap_loc = -1;
1330 /* Index of inptr->data where we wrap. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001331 int word_back = -1;
1332#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001333 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001334 /* Indentation to prepend to the new line. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001335 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001336#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001337 const char *after_break; /* Text after the wrap point. */
1338 size_t after_break_len; /* strlen(after_break) */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001339 bool wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001340 const char *wrap_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001341 /* The next line, minus indentation. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001342 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1343 char *newline = NULL; /* The line we create. */
1344 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001345
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001346/* There are three steps. First, we decide where to wrap. Then, we
1347 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001348
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001349/* Step 1, finding where to wrap. We are going to add a new line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001350 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001351 * location of this replacement.
1352 *
1353 * Where should we break the line? We need the last "legal wrap point"
1354 * such that the last word before it ended at or before fill. If there
1355 * is no such point, we settle for the first legal wrap point.
1356 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001357 * A "legal wrap point" is a whitespace character that is not followed
1358 * by whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001359 *
1360 * If there is no legal wrap point or we found the last character of the
1361 * line, we should return without wrapping.
1362 *
1363 * Note that the initial indentation does not count as a legal wrap
1364 * point if we are going to auto-indent!
1365 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001366 * Note that the code below could be optimized, by not calling
1367 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001368
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001369#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001370 if (ISSET(AUTOINDENT))
1371 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001372#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001373 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001374 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001375 /* Record where the last word ended. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001376 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001377 word_back = i;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001378 /* If we have found a "legal wrap point" and the current word
1379 * extends too far, then we stop. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001380 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001381 break;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001382 /* We record the latest "legal wrap point". */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001383 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001384 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001385 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001386 if (i == len)
1387 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001388
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001389 /* Step 2, making the new wrap line. It will consist of indentation
1390 * + after_break + " " + wrap_line (although indentation and
1391 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001392
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001393 /* after_break is the text that will be moved to the next line. */
1394 after_break = inptr->data + wrap_loc + 1;
1395 after_break_len = len - wrap_loc - 1;
1396 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001397
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001398 /* new_line_len will later be increased by the lengths of indentation
1399 * and wrap_line. */
1400 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001401
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001402 /* We prepend the wrapped text to the next line, if the flag is set,
1403 * and there is a next line, and prepending would not make the line
1404 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001405 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001406 wrap_line = inptr->next->data;
1407 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001408
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001409 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001410 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001411 wrapping = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001412 new_line_len += (1 + wrap_line_len);
1413 }
1414 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001415
Chris Allegrettaff989832001-09-17 13:48:00 +00001416#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001417 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001418 /* Indentation comes from the next line if wrapping, else from
1419 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001421 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001422 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001423 /* The wrap_line text should not duplicate indentation.
1424 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001425 wrap_line += indent_len;
1426 else
1427 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001428 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001429#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001430
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001431 /* Now we allocate the new line and copy into it. */
1432 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001433 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001434 *newline = '\0';
1435
1436#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001437 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001438 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001439 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001440 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001441 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001442#endif
1443 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001444 new_line_len += after_break_len;
1445 /* We end the old line after wrap_loc. Note that this does not eat
1446 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001447 null_at(&inptr->data, wrap_loc + 1);
1448 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001449 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001450 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001451 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001452 * in a tab or a space, we don't add a space and decrement
1453 * totsize to account for that. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001454 if (!isblank(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001455 strcat(newline, " ");
1456 else
1457 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001458 strcat(newline, wrap_line);
1459 free(inptr->next->data);
1460 inptr->next->data = newline;
1461 } else {
1462 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001463
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001464 /* In this case, the file size changes by +1 for the new line,
1465 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001466#ifndef NANO_SMALL
1467 totsize += indent_len;
1468#endif
1469 totlines++;
1470 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001471 temp->prev = inptr;
1472 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001473 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001474 /* If temp->next is NULL, then temp is the last line of the
1475 * file, so we must set filebot. */
1476 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001477 temp->next->prev = temp;
1478 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001479 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001480 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001481
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001482 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1483 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001484
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001485 /* Later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001486 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001487
1488 /* Each line knows its line number. We recalculate these if we
1489 * inserted a new line. */
1490 if (!wrapping)
1491 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001492
Chris Allegretta6df90f52002-07-19 01:08:59 +00001493 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001494 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001495 current = current->next;
1496 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001497#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001498 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001499#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001500 wrap_loc + 1;
1501 wrap_reset();
1502 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001503 }
1504
Chris Allegretta6df90f52002-07-19 01:08:59 +00001505#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001506 /* If the mark was on this line after the wrap point, we move it
1507 * down. If it was on the next line and we wrapped, we move it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001508 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001509 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1510 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001511 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001512 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001513 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001514#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001515
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001516 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001517}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001518#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001519
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001520#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001521/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001522 * return FALSE if the user cancels. */
1523bool do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001524{
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001525 char *save_search, *save_replace;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001526 size_t current_x_save = current_x, pww_save = placewewant;
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001527 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001528 /* Save where we are. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001529 bool canceled = FALSE;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001530 /* The return value. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001531 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001532#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001533 bool reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001534#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001535#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001536 bool regexp_set = ISSET(USE_REGEXP);
1537#endif
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001538#ifndef NANO_SMALL
1539 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001540 bool right_side_up = FALSE;
1541 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
1542 * FALSE if (current, current_x) is. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001543 filestruct *top, *bot;
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001544 size_t top_x, bot_x;
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001545#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001546
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001547 /* Make sure spell-check is case sensitive. */
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001548 SET(CASE_SENSITIVE);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001549
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001550#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001551 /* Make sure spell-check goes forward only. */
1552 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001553#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001554#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001555 /* Make sure spell-check doesn't use regular expressions. */
1556 UNSET(USE_REGEXP);
1557#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001558
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001559 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001560 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001561 save_search = last_search;
1562 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001563
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001564 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001565 last_search = mallocstrcpy(NULL, word);
1566 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001567
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001568#ifndef NANO_SMALL
1569 if (old_mark_set) {
David Lawrence Ramseyf978f042004-11-04 16:45:48 +00001570 /* If the mark is on, partition the filestruct so that it
David Lawrence Ramseyf643fc22004-11-04 17:42:41 +00001571 * contains only the marked text, and turn the mark off. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001572 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001573 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001574 filepart = partition_filestruct(top, top_x, bot, bot_x);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001575 UNSET(MARK_ISSET);
1576 }
1577#endif
1578
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001579 /* Start from the top of the file. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001580 edittop = fileage;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001581 current = fileage;
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001582 current_x = (size_t)-1;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001583 placewewant = 0;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001584
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001585 /* Find the first whole-word occurrence of word. */
David Lawrence Ramseye5e88fd2004-10-31 13:20:30 +00001586 findnextstr_wrap_reset();
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +00001587 while (findnextstr(TRUE, TRUE, FALSE, fileage, 0, word, NULL)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001588 if (is_whole_word(current_x, current->data, word)) {
1589 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001590
Chris Allegretta6df90f52002-07-19 01:08:59 +00001591 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001592
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +00001593 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001594 canceled = (statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001595#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001596 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001597#endif
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001598 _("Edit a replacement")) == -1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001599
Chris Allegretta6df90f52002-07-19 01:08:59 +00001600 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001601
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001602 if (!canceled && strcmp(word, answer) != 0) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001603 bool added_magicline = (filebot->data[0] != '\0');
1604 /* Whether we added a magicline after
1605 * filebot. */
1606
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001607 current_x--;
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001608 do_replace_loop(word, current, &current_x, TRUE,
1609 &canceled);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001610
1611 /* If we added a magicline, remove it now. */
1612 if (added_magicline)
1613 remove_magicline();
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001614 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001615
1616 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001617 }
David Lawrence Ramsey53752e82004-10-18 22:19:22 +00001618 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001619
David Lawrence Ramsey46c604a2004-11-05 23:55:58 +00001620#ifndef NANO_SMALL
1621 if (old_mark_set) {
1622 size_t bot_data_len = strlen(filebot->data);
1623
1624 /* If the mark ended in the middle of a word and that word was
1625 * spell-checked, put either current_x_save or mark_beginx,
1626 * depending on the value of right_side_up, at the end of the
1627 * spell-checked word. */
1628 if (right_side_up)
1629 current_x_save = bot_data_len;
1630 else
1631 mark_beginx = bot_data_len;
1632 }
1633#endif
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001634
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001635 /* Restore the search/replace strings. */
1636 free(last_search);
1637 last_search = save_search;
1638 free(last_replace);
1639 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001640
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001641#ifndef NANO_SMALL
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001642 if (old_mark_set) {
David Lawrence Ramseyf978f042004-11-04 16:45:48 +00001643 /* If the mark was on, unpartition the filestruct so that it
1644 * contains all the text again, and turn the mark back on. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001645 unpartition_filestruct(filepart);
1646 SET(MARK_ISSET);
1647 }
1648#endif
1649
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001650 /* Restore where we were. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001651 edittop = edittop_save;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001652 current = current_save;
1653 current_x = current_x_save;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001654 placewewant = pww_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001655
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001656 /* Restore case sensitivity setting. */
1657 if (!case_sens_set)
1658 UNSET(CASE_SENSITIVE);
1659
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001660#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001661 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001662 if (reverse_search_set)
1663 SET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001664#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001665#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001666 /* Restore regular expression usage setting. */
1667 if (regexp_set)
1668 SET(USE_REGEXP);
1669#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001670
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001671 return !canceled;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001672}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001673
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001674/* Integrated spell checking using 'spell' program. Return value: NULL
1675 * for normal termination, otherwise the error string. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001676const char *do_int_speller(const char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001677{
Chris Allegretta271e9722000-11-10 18:15:43 +00001678 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001679 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001680 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001681 pid_t pid_spell, pid_sort, pid_uniq;
1682 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001683
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001684 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001685 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1686 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001687
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001688 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001689
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001690 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001691 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001692
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001693 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001694
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001695 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001696
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001697 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001698 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1699 goto close_pipes_and_exit;
1700
1701 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1702 goto close_pipes_and_exit;
1703
Chris Allegretta271e9722000-11-10 18:15:43 +00001704 close(tempfile_fd);
1705
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001706 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001707 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1708 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001709
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001710 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001711
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001712 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001713 execlp("spell", "spell", NULL);
1714
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001715 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001716 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001717 }
1718
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001719 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001720 close(spell_fd[1]);
1721
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001722 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001723 if ((pid_sort = fork()) == 0) {
1724
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001725 /* Child continues (i.e, future spell process). Replace the
1726 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001727 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1728 goto close_pipes_and_exit;
1729
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001730 close(spell_fd[0]);
1731
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001732 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001733 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1734 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001735
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001736 close(sort_fd[1]);
1737
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001738 /* Start sort program. Use -f to remove mixed case without
1739 * having to have ANOTHER pipe for tr. If this isn't portable,
1740 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001741 execlp("sort", "sort", "-f", NULL);
1742
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001743 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001744 exit(1);
1745 }
1746
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001747 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001748 close(sort_fd[1]);
1749
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001750 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001751 if ((pid_uniq = fork()) == 0) {
1752
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001753 /* Child continues (i.e, future uniq process). Replace the
1754 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001755 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1756 goto close_pipes_and_exit;
1757
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001758 close(sort_fd[0]);
1759
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001760 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001761 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1762 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001763
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001764 close(uniq_fd[1]);
1765
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001766 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001767 execlp("uniq", "uniq", NULL);
1768
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001769 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001770 exit(1);
1771 }
1772
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001773 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001774 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001775
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001776 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001777 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1778 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001779 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001780 }
1781
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001782 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001783 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1784 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001785 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001786 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001787
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001788 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001789 read_buff_read = 0;
1790 read_buff_size = pipe_buff_size + 1;
1791 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001792
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001793 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001794 read_buff_read += bytesread;
1795 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001796 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001797 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001798
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001799 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001800
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001801 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001802 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001803
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001804 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001805 read_buff_word = read_buff_ptr = read_buff;
1806
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001807 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001808
1809 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001810 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001811 if (read_buff_word != read_buff_ptr) {
1812 if (!do_int_spell_fix(read_buff_word)) {
1813 read_buff_word = read_buff_ptr;
1814 break;
1815 }
1816 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001817 read_buff_word = read_buff_ptr + 1;
1818 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001819 read_buff_ptr++;
1820 }
1821
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001822 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001823 if (read_buff_word != read_buff_ptr)
1824 do_int_spell_fix(read_buff_word);
1825
Chris Allegretta271e9722000-11-10 18:15:43 +00001826 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001827 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001828 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001829
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001830 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001831 waitpid(pid_spell, &spell_status, 0);
1832 waitpid(pid_sort, &sort_status, 0);
1833 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001834
Chris Allegretta334a9402002-12-16 04:25:53 +00001835 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1836 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001837
Chris Allegretta334a9402002-12-16 04:25:53 +00001838 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1839 return _("Error invoking \"sort -f\"");
1840
1841 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1842 return _("Error invoking \"uniq\"");
1843
1844 /* Otherwise... */
1845 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001846
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001847 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001848
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001849 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001850 close(tempfile_fd);
1851 close(spell_fd[0]);
1852 close(spell_fd[1]);
1853 close(sort_fd[0]);
1854 close(sort_fd[1]);
1855 close(uniq_fd[0]);
1856 close(uniq_fd[1]);
1857 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001858}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001859
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001860/* External spell checking. Return value: NULL for normal termination,
1861 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001862const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001863{
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001864 int alt_spell_status, lineno_save = current->lineno;
1865 size_t current_x_save = current_x, pww_save = placewewant;
1866 int current_y_save = current_y;
Chris Allegretta271e9722000-11-10 18:15:43 +00001867 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001868 char *ptr;
1869 static int arglen = 3;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001870 static char **spellargs = NULL;
1871 FILE *f;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001872#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001873 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001874 bool added_magicline = FALSE;
1875 /* Whether we added a magicline after filebot. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001876 bool right_side_up = FALSE;
1877 /* TRUE if (mark_beginbuf, mark_beginx) is the top of the mark,
1878 * FALSE if (current, current_x) is. */
1879 int mbb_lineno_save = 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001880 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001881 * the alternate spell command. The line that mark_beginbuf
1882 * points to will be freed, so we save the line number and
1883 * restore afterwards. */
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001884 int old_totlines = totlines;
1885 /* Our saved value of totlines, used when we spell-check a
1886 * marked selection. */
1887 long old_totsize = totsize;
1888 /* Our saved value of totsize, used when we spell-check a marked
1889 * selection. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001890
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001891 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001892 /* If the mark is on, save the number of the line it starts on,
1893 * and then turn the mark off. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001894 mbb_lineno_save = mark_beginbuf->lineno;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001895 UNSET(MARK_ISSET);
1896 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001897#endif
1898
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001899 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001900
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001901 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001902 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001903 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001904
Chris Allegrettae434b452001-01-27 19:25:00 +00001905 spellargs[0] = strtok(alt_speller, " ");
1906 while ((ptr = strtok(NULL, " ")) != NULL) {
1907 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001908 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001909 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001910 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001911 spellargs[arglen - 1] = NULL;
1912 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001913 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001914
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001915 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001916 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001917 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001918 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001919
1920 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001921 exit(1);
1922 }
1923
1924 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001925 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001926 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001927
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001928 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001929 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001930
Chris Allegretta334a9402002-12-16 04:25:53 +00001931 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1932 char *altspell_error = NULL;
1933 char *invoke_error = _("Could not invoke \"%s\"");
1934 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1935
1936 altspell_error = charalloc(msglen);
1937 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1938 return altspell_error;
1939 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001940
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001941 refresh();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001942
David Lawrence Ramsey439fbe32004-10-16 04:56:34 +00001943 /* Restore the terminal to its previous state. */
1944 terminal_init();
1945
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001946#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001947 if (old_mark_set) {
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001948 filestruct *top, *bot;
1949 size_t top_x, bot_x;
1950 int part_totlines;
1951 long part_totsize;
1952
1953 /* If the mark was on, partition the filestruct so that it
1954 * contains only the marked text, and keep track of whether the
1955 * temp file (which should contain the spell-checked marked
1956 * text) will have a magicline added when it's reloaded. */
1957 mark_order((const filestruct **)&top, &top_x,
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001958 (const filestruct **)&bot, &bot_x, &right_side_up);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001959 filepart = partition_filestruct(top, top_x, bot, bot_x);
1960 added_magicline = (filebot->data[0] != '\0');
1961
1962 /* Get the number of lines and the number of characters in the
1963 * marked text, and subtract them from the saved values of
1964 * totlines and totsize. */
1965 get_totals(top, bot, &part_totlines, &part_totsize);
1966 old_totlines -= part_totlines;
1967 old_totsize -= part_totsize;
1968 }
1969#endif
1970
1971 /* Reinitialize the filestruct. */
1972 free_filestruct(fileage);
1973 global_init(TRUE);
1974
1975 /* Reload the temp file. Do what load_buffer() would do, except for
1976 * making a new buffer for the temp file if multibuffer support is
1977 * available. */
1978 open_file(tempfile_name, FALSE, &f);
1979 read_file(f, tempfile_name);
1980 current = fileage;
1981
1982#ifndef NANO_SMALL
1983 if (old_mark_set) {
David Lawrence Ramsey15398372004-11-05 15:03:12 +00001984 filestruct *top_save = fileage;
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001985 size_t bot_data_len;
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00001986
1987 /* If we added a magicline, remove it now. */
1988 if (added_magicline)
1989 remove_magicline();
1990
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00001991 /* If the mark ended in the middle of a word and that word was
1992 * spell-checked, put either current_x_save or mark_beginx,
1993 * depending on the value of right_side_up, at the end of the
1994 * spell-checked word. */
1995 bot_data_len = strlen(filebot->data);
1996 if (right_side_up)
1997 current_x_save = bot_data_len;
1998 else
1999 mark_beginx = bot_data_len;
2000
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002001 /* If the mark was on, unpartition the filestruct so that it
2002 * contains all the text again. Note that we've replaced the
2003 * marked text originally in the partition with the
2004 * spell-checked marked text in the temp file. */
2005 unpartition_filestruct(filepart);
2006
2007 /* Renumber starting with the beginning line of the old
2008 * partition. Also add the number of lines and characters in
2009 * the spell-checked marked text to the saved values of totlines
2010 * and totsize, and then make those saved values the actual
2011 * values. */
David Lawrence Ramsey15398372004-11-05 15:03:12 +00002012 renumber(top_save);
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002013 old_totlines += totlines;
2014 old_totsize += totsize;
2015 totlines = old_totlines;
2016 totsize = old_totsize;
2017
2018 /* Assign mark_beginbuf to the line where the mark began
2019 * before. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002020 do_gotopos(mbb_lineno_save, mark_beginx, current_y_save, 0);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002021 mark_beginbuf = current;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002022
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00002023 /* Assign mark_beginx to the location in mark_beginbuf where the
2024 * mark began before, adjusted for any shortening of the
2025 * line. */
2026 mark_beginx = current_x;
2027
2028 /* Turn the mark back on. */
2029 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002030 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002031#endif
2032
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002033 /* Go back to the old position, mark the file as modified, and make
2034 * sure that the titlebar is refreshed. */
David Lawrence Ramsey90e59c12004-11-05 23:03:03 +00002035 do_gotopos(lineno_save, current_x_save, current_y_save, pww_save);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002036 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00002037 clearok(topwin, FALSE);
2038 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002039
Chris Allegretta334a9402002-12-16 04:25:53 +00002040 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002041}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002042
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002043void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002044{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002045 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002046 char *temp = safe_tempnam(0, "nano.");
2047 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002048
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002049 if (temp == NULL) {
2050 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002051 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00002052 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002053
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002054#ifndef NANO_SMALL
2055 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002056 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002057 else
2058#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00002059 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002060
2061 if (i == -1) {
David Lawrence Ramsey95e39e52004-08-12 02:52:14 +00002062 statusbar(_("Error writing temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00002063 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002064 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00002065 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002066
Chris Allegrettae1f14522001-09-19 03:19:43 +00002067#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002068 /* Update the current open_files entry before spell-checking, in
2069 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002070 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00002071#endif
2072
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002073 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
2074 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00002075 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00002076 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002077
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002078 if (spell_msg != NULL)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002079 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
2080 strerror(errno));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002081 else
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002082 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00002083}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002084#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002085
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002086#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00002087/* The "indentation" of a line is the whitespace between the quote part
2088 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002089size_t indent_length(const char *line)
2090{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002091 size_t len = 0;
2092
2093 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002094 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002095 line++;
2096 len++;
2097 }
2098 return len;
2099}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002100#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002101
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002102#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00002103/* justify_format() replaces Tab by Space and multiple spaces by 1
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002104 * (except it maintains 2 after a non-repeated character in punct
2105 * followed by a character in brackets). Note that the terminating \0
2106 * counts as a space.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002107 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002108 * justify_format() might make line->data shorter, and change the actual
2109 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00002110 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002111 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00002112 * skip should be at most strlen(line->data). The character at
2113 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002114void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002115{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002116 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002117
Chris Allegretta6df90f52002-07-19 01:08:59 +00002118 /* These four asserts are assumptions about the input data. */
2119 assert(line != NULL);
2120 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00002121 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002122 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002123
Chris Allegretta6df90f52002-07-19 01:08:59 +00002124 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002125 for (front = back; ; front++) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002126 bool remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002127 /* Do we want to remove this space? */
2128
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002129 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002130 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002131
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00002132 /* These tests are safe since line->data + skip is not a
2133 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002134 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002135 const char *bob = back - 2;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002136
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002137 remove_space = TRUE;
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002138 for (; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002139 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00002140 /* If this character is in punct, don't remove the
2141 * space unless this character and the character
2142 * before it are the same. */
2143 remove_space = (bob > line->data + skip &&
2144 *bob == *(bob - 1));
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002145 break;
2146 }
2147 if (strchr(brackets, *bob) == NULL)
2148 break;
2149 }
2150 }
2151
2152 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002153 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002154 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002155#ifndef NANO_SMALL
2156 if (mark_beginbuf == line && back - line->data < mark_beginx)
2157 mark_beginx--;
2158#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002159 if (*front == '\0')
2160 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002161 } else {
2162 *back = *front;
2163 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002164 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002165 if (*front == '\0')
2166 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002167 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002168
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002169 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00002170 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00002171
Chris Allegretta6df90f52002-07-19 01:08:59 +00002172 /* Now back is the new end of line->data. */
2173 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00002174 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002175 null_at(&line->data, back - line->data);
2176#ifndef NANO_SMALL
2177 if (mark_beginbuf == line && back - line->data < mark_beginx)
2178 mark_beginx = back - line->data;
2179#endif
2180 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002181}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002182
2183/* The "quote part" of a line is the largest initial substring matching
2184 * the quote string. This function returns the length of the quote part
2185 * of the given line.
2186 *
2187 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2188 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002189size_t quote_length(const char *line)
2190{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002191#ifdef HAVE_REGEX_H
2192 regmatch_t matches;
2193 int rc = regexec(&quotereg, line, 1, &matches, 0);
2194
2195 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
2196 return 0;
2197 /* matches.rm_so should be 0, since the quote string should start
2198 * with the caret ^. */
2199 return matches.rm_eo;
2200#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002201 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002202
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00002203 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002204 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002205 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002206 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002207#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002208}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002209
Chris Allegretta6df90f52002-07-19 01:08:59 +00002210/* a_line and b_line are lines of text. The quotation part of a_line is
2211 * the first a_quote characters. Check that the quotation part of
2212 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002213bool quotes_match(const char *a_line, size_t a_quote, const char
2214 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002215{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002216 /* Here is the assumption about a_quote: */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002217 assert(a_quote == quote_length(a_line));
2218 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002219 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002220}
2221
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002222/* We assume a_line and b_line have no quote part. Then, we return
2223 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002224bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002225 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002226{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002227 assert(a_indent == indent_length(a_line));
2228 assert(b_indent == indent_length(b_line));
2229
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002230 return b_indent <= a_indent &&
2231 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002232}
2233
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002234/* Is foo the beginning of a paragraph?
2235 *
2236 * A line of text consists of a "quote part", followed by an
2237 * "indentation part", followed by text. The functions quote_length()
2238 * and indent_length() calculate these parts.
2239 *
2240 * A line is "part of a paragraph" if it has a part not in the quote
2241 * part or the indentation.
2242 *
2243 * A line is "the beginning of a paragraph" if it is part of a
2244 * paragraph and
2245 * 1) it is the top line of the file, or
2246 * 2) the line above it is not part of a paragraph, or
2247 * 3) the line above it does not have precisely the same quote
2248 * part, or
2249 * 4) the indentation of this line is not an initial substring of
2250 * the indentation of the previous line, or
2251 * 5) this line has no quote part and some indentation, and
2252 * AUTOINDENT is not set.
2253 * The reason for number 5) is that if AUTOINDENT is not set, then an
2254 * indented line is expected to start a paragraph, like in books.
2255 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2256 * turned on. */
2257bool begpar(const filestruct *const foo)
2258{
2259 size_t quote_len;
2260 size_t indent_len;
2261 size_t temp_id_len;
2262
2263 /* Case 1). */
2264 if (foo->prev == NULL)
2265 return TRUE;
2266
2267 quote_len = quote_length(foo->data);
2268 indent_len = indent_length(foo->data + quote_len);
2269
2270 /* Not part of a paragraph. */
2271 if (foo->data[quote_len + indent_len] == '\0')
2272 return FALSE;
2273
2274 /* Case 3). */
2275 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2276 return TRUE;
2277
2278 temp_id_len = indent_length(foo->prev->data + quote_len);
2279
2280 /* Case 2) or 5) or 4). */
2281 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2282 (quote_len == 0 && indent_len > 0
2283#ifndef NANO_SMALL
2284 && !ISSET(AUTOINDENT)
2285#endif
2286 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2287 foo->data + quote_len, indent_len))
2288 return TRUE;
2289
2290 return FALSE;
2291}
2292
2293/* We find the last beginning-of-paragraph line before the current
2294 * line. */
2295void do_para_begin(void)
2296{
2297 const filestruct *old_current = current;
2298 const size_t old_pww = placewewant;
2299
2300 current_x = 0;
2301 placewewant = 0;
2302
2303 if (current->prev != NULL) {
2304 do {
2305 current = current->prev;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002306 current_y--;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002307 } while (!begpar(current));
2308 }
2309
2310 edit_redraw(old_current, old_pww);
2311}
2312
2313bool inpar(const char *str)
2314{
2315 size_t quote_len = quote_length(str);
2316
2317 return str[quote_len + indent_length(str + quote_len)] != '\0';
2318}
2319
2320/* A line is the last line of a paragraph if it is in a paragraph, and
2321 * the next line isn't, or is the beginning of a paragraph. We move
2322 * down to the end of a paragraph, then one line farther. */
2323void do_para_end(void)
2324{
2325 const filestruct *const old_current = current;
2326 const size_t old_pww = placewewant;
2327
2328 current_x = 0;
2329 placewewant = 0;
2330
2331 while (current->next != NULL && !inpar(current->data))
2332 current = current->next;
2333
2334 while (current->next != NULL && inpar(current->next->data) &&
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002335 !begpar(current->next)) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002336 current = current->next;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002337 current_y++;
2338 }
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002339
2340 if (current->next != NULL)
2341 current = current->next;
2342
2343 edit_redraw(old_current, old_pww);
2344}
2345
Chris Allegretta6df90f52002-07-19 01:08:59 +00002346/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002347 * buffer, not allowing them to be concatenated. We assume there are
2348 * enough lines after first_line. We leave copies of the lines in
2349 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002350filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2351 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002352{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002353 /* We put the original lines, not copies, into the cutbuffer, just
2354 * out of a misguided sense of consistency, so if you uncut, you get
2355 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002356 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002357
2358 set_modified();
2359 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002360 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002361 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002362
Chris Allegretta908f7702003-01-15 11:18:58 +00002363 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002364 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002365 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002366 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002367 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002368 edittop = bob;
2369#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002370 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002371 mark_beginbuf = bob;
2372#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002373
Chris Allegretta908f7702003-01-15 11:18:58 +00002374 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002375 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002376 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002377 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002378 }
2379 return first_line;
2380}
2381
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002382/* Is it possible to break line at or before goal? */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002383bool breakable(const char *line, ssize_t goal)
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002384{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002385 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002386 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002387 return TRUE;
2388
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002389 if (is_cntrl_char(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002390 goal -= 2;
2391 else
2392 goal -= 1;
2393 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002394 /* If goal is not negative, the whole line (one word) was short
2395 * enough. */
2396 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002397}
2398
Chris Allegretta6df90f52002-07-19 01:08:59 +00002399/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002400 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002401 * such space, and force is TRUE, then we find the first space. Anyway,
2402 * we then take the last space in that group of spaces. The terminating
2403 * '\0' counts as a space. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002404int break_line(const char *line, ssize_t goal, bool force)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002405{
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002406 ssize_t space_loc = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002407 /* Current tentative return value. Index of the last space we
2408 * found with short enough display width. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002409 ssize_t cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002410 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002411
2412 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002413 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002414 if (*line == ' ')
2415 space_loc = cur_loc;
2416 assert(*line != '\t');
2417
Chris Allegrettacf287c82002-07-20 13:57:41 +00002418 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002419 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002420 else
2421 goal--;
2422 }
2423 if (goal >= 0)
2424 /* In fact, the whole line displays shorter than goal. */
2425 return cur_loc;
2426 if (space_loc == -1) {
2427 /* No space found short enough. */
2428 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002429 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002430 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002431 return cur_loc;
2432 return -1;
2433 }
2434 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002435 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002436 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2437 *(line - cur_loc + space_loc + 1) == '\0')
2438 space_loc++;
2439 return space_loc;
2440}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002441
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002442/* Find the beginning of the current paragraph if we're in one, or the
2443 * beginning of the next paragraph if we're not. Afterwards, save the
2444 * quote length and paragraph length in *quote and *par. Return FALSE
2445 * if we found a paragraph, or TRUE if there was an error or we didn't
2446 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002447 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002448 * See the comment at begpar() for more about when a line is the
2449 * beginning of a paragraph. */
2450bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002451{
2452 size_t quote_len;
2453 /* Length of the initial quotation of the paragraph we
2454 * search. */
2455 size_t par_len;
2456 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002457 size_t indent_len;
2458 /* Generic indentation length. */
2459 filestruct *line;
2460 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002461
2462#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002463 if (quoterc != 0) {
2464 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2465 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002466 }
2467#endif
2468
2469 /* Here is an assumption that is always true anyway. */
2470 assert(current != NULL);
2471
2472 current_x = 0;
2473
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002474 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002475 indent_len = indent_length(current->data + quote_len);
2476
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002477 /* Here we find the first line of the paragraph to search. If the
2478 * current line is in a paragraph, then we move back to the first
2479 * line of the paragraph. Otherwise, we move to the first line that
2480 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002481 if (current->data[quote_len + indent_len] != '\0') {
2482 /* This line is part of a paragraph. So we must search back to
2483 * the first line of this paragraph. First we check items 1)
2484 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002485 while (current->prev != NULL && quotes_match(current->data,
2486 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002487 size_t temp_id_len =
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00002488 indent_length(current->prev->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002489 /* The indentation length of the previous line. */
2490
2491 /* Is this line the beginning of a paragraph, according to
2492 * items 2), 5), or 4) above? If so, stop. */
2493 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002494 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002495#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002496 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002497#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002498 ) || !indents_match(current->prev->data + quote_len,
2499 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002500 break;
2501 indent_len = temp_id_len;
2502 current = current->prev;
2503 current_y--;
2504 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002505 } else {
2506 /* This line is not part of a paragraph. Move down until we get
2507 * to a non "blank" line. */
2508 do {
2509 /* There is no next paragraph, so nothing to move to. */
2510 if (current->next == NULL) {
2511 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002512 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002513 }
2514 current = current->next;
2515 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002516 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002517 indent_len = indent_length(current->data + quote_len);
2518 } while (current->data[quote_len + indent_len] == '\0');
2519 }
2520
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002521 /* Now current is the first line of the paragraph, and quote_len is
2522 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002523
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002524 /* Next step, compute par_len, the number of lines in this
2525 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002526 line = current;
2527 par_len = 1;
2528 indent_len = indent_length(line->data + quote_len);
2529
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002530 while (line->next != NULL &&
2531 quotes_match(current->data, quote_len, line->next->data)) {
2532 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002533
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002534 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002535 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002536 line->next->data[quote_len + temp_id_len] == '\0' ||
2537 (quote_len == 0 && temp_id_len > 0
2538#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002539 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002540#endif
2541 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002542 break;
2543 indent_len = temp_id_len;
2544 line = line->next;
2545 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002546 }
2547
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002548 /* Now par_len is the number of lines in this paragraph. We should
2549 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002550
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002551 /* Save the values of quote_len and par_len. */
2552 assert(quote != NULL && par != NULL);
2553 *quote = quote_len;
2554 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002555
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002556 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002557}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002558
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002559/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2560 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002561void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002562{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002563 filestruct *first_par_line = NULL;
2564 /* Will be the first line of the resulting justified paragraph.
2565 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002566 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002567 /* Will be the last line of the result, also for uncut. */
2568 filestruct *cutbuffer_save = cutbuffer;
2569 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002570 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002571 * original to restore it later. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002572 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002573 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002574 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002575 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002576
2577 /* We save these global variables to be restored if the user
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002578 * unjustifies. Note that we don't need to save totlines. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00002579 size_t current_x_save = current_x;
2580 int current_y_save = current_y;
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002581 long flags_save = flags, totsize_save = totsize;
2582 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002583#ifndef NANO_SMALL
2584 filestruct *mark_beginbuf_save = mark_beginbuf;
David Lawrence Ramsey687776b2004-10-30 01:16:08 +00002585 size_t mark_beginx_save = mark_beginx;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002586#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002587 int kbinput;
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00002588 bool meta_key, func_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002589
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002590 /* If we're justifying the entire file, start at the beginning. */
2591 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002592 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002593
2594 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002595
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002596 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002597 size_t quote_len;
2598 /* Length of the initial quotation of the paragraph we
2599 * justify. */
2600 size_t par_len;
2601 /* Number of lines in that paragraph. */
2602
2603 /* Find the first line of the paragraph to be justified. That
2604 * is the start of this paragraph if we're in one, or the start
2605 * of the next otherwise. Save the quote length and paragraph
2606 * length (number of lines). Don't refresh the screen yet
2607 * (since we'll do that after we justify). If the search failed
2608 * and we're justifying the whole file, move the last line of
2609 * the text we're justifying to just before the magicline, which
2610 * is where it'll be anyway if we've searched the entire file,
2611 * and break out of the loop; otherwise, refresh the screen and
2612 * get out. */
2613 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002614 if (full_justify) {
2615 /* This should be safe in the event of filebot->prev's
2616 * being NULL, since only last_par_line->next is used if
2617 * we eventually unjustify. */
2618 last_par_line = filebot->prev;
2619 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002620 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002621 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002622 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002623 }
2624 }
2625
2626 /* Next step, we loop through the lines of this paragraph,
2627 * justifying each one individually. */
2628 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002629 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002630 size_t line_len;
2631 size_t display_len;
2632 /* The width of current in screen columns. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002633 ssize_t break_pos;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002634 /* Where we will break the line. */
2635
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002636 /* We'll be moving to the next line after justifying the
2637 * current line in almost all cases, so allow changing the
2638 * spacing at the ends of justified lines by default. */
2639 allow_respacing = TRUE;
2640
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002641 indent_len = quote_len + indent_length(current->data +
2642 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002643
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002644 /* If we haven't already done it, copy the original
2645 * paragraph to the cutbuffer for unjustification. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002646 if (first_par_line == NULL)
2647 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002648 filebot->lineno - current->lineno : par_len, quote_len);
2649
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002650 /* Now we call justify_format() on the current line of the
2651 * paragraph, which will remove excess spaces from it and
2652 * change tabs to spaces. */
2653 justify_format(current, quote_len +
2654 indent_length(current->data + quote_len));
2655
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002656 line_len = strlen(current->data);
2657 display_len = strlenpt(current->data);
2658
2659 if (display_len > fill) {
2660 /* The line is too long. Try to wrap it to the next. */
2661 break_pos = break_line(current->data + indent_len,
2662 fill - strnlenpt(current->data, indent_len), TRUE);
2663 if (break_pos == -1 || break_pos + indent_len == line_len)
2664 /* We can't break the line, or don't need to, so
2665 * just go on to the next. */
2666 goto continue_loc;
2667 break_pos += indent_len;
2668 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002669 if (par_len == 1) {
2670 /* There is no next line in this paragraph. We make
2671 * a new line and copy text after break_pos into
2672 * it. */
2673 splice_node(current, make_new_node(current), current->next);
2674 /* In a non-quoted paragraph, we copy the indent
2675 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002676 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002677#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002678 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002679#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002680 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002681 indent_len = 0;
2682 current->next->data = charalloc(indent_len + line_len -
2683 break_pos);
2684 strncpy(current->next->data, current->data, indent_len);
2685 strcpy(current->next->data + indent_len,
2686 current->data + break_pos + 1);
2687 assert(strlen(current->next->data) ==
2688 indent_len + line_len - break_pos - 1);
2689 totlines++;
2690 totsize += indent_len;
2691 par_len++;
2692 } else {
2693 size_t next_line_len = strlen(current->next->data);
2694
2695 indent_len = quote_len +
2696 indent_length(current->next->data + quote_len);
2697 current->next->data = charealloc(current->next->data,
2698 next_line_len + line_len - break_pos + 1);
2699
2700 charmove(current->next->data + indent_len + line_len -
2701 break_pos, current->next->data + indent_len,
2702 next_line_len - indent_len + 1);
2703 strcpy(current->next->data + indent_len,
2704 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002705 current->next->data[indent_len + line_len -
2706 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002707#ifndef NANO_SMALL
2708 if (mark_beginbuf == current->next) {
2709 if (mark_beginx < indent_len)
2710 mark_beginx = indent_len;
2711 mark_beginx += line_len - break_pos;
2712 }
2713#endif
2714 }
2715#ifndef NANO_SMALL
2716 if (mark_beginbuf == current && mark_beginx > break_pos) {
2717 mark_beginbuf = current->next;
2718 mark_beginx -= break_pos + 1 - indent_len;
2719 }
2720#endif
2721 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002722
2723 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002724 current = current->next;
2725 } else if (display_len < fill && par_len > 1) {
2726 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002727
2728 indent_len = quote_len +
2729 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002730 /* If we can't pull a word from the next line up to this
2731 * one, just go on. */
2732 if (!breakable(current->next->data + indent_len,
2733 fill - display_len - 1))
2734 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002735
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002736 break_pos = break_line(current->next->data + indent_len,
2737 fill - display_len - 1, FALSE);
2738 assert(break_pos != -1);
2739
2740 current->data = charealloc(current->data,
2741 line_len + break_pos + 2);
2742 current->data[line_len] = ' ';
2743 strncpy(current->data + line_len + 1,
2744 current->next->data + indent_len, break_pos);
2745 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002746#ifndef NANO_SMALL
2747 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002748 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002749 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002750 if (mark_beginx <= indent_len)
2751 mark_beginx = line_len + 1;
2752 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002753 mark_beginx = line_len + 1 + mark_beginx -
2754 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002755 } else
2756 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002757 }
2758#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002759 next_line_len = strlen(current->next->data);
2760 if (indent_len + break_pos == next_line_len) {
2761 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002762
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002763 /* Don't destroy edittop! */
2764 if (line == edittop)
2765 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002766
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002767 unlink_node(line);
2768 delete_node(line);
2769 totlines--;
2770 totsize -= indent_len;
2771 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002772
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002773 /* Don't go to the next line. Accordingly, don't
2774 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002775 * previous justified line, so that we don't end up
2776 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002777 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002778 } else {
2779 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002780 current->next->data + indent_len + break_pos + 1,
2781 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002782 null_at(&current->next->data, next_line_len - break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002783
2784 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002785 current = current->next;
2786 }
2787 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002788 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002789 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002790 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002791
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002792 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002793 * current line. If the justified line was not the last
2794 * line of the paragraph, add a space to the end of it to
2795 * replace the one removed or left out by justify_format().
2796 * If it was the last line of the paragraph, and
2797 * justify_format() left a space on the end of it, remove
2798 * the space. */
2799 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002800 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002801
2802 if (par_len > 1) {
2803 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002804 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002805 current->prev->data[prev_line_len] = ' ';
2806 current->prev->data[prev_line_len + 1] = '\0';
2807 totsize++;
2808 } else if (par_len == 1 &&
2809 current->prev->data[prev_line_len - 1] == ' ') {
2810 current->prev->data = charealloc(current->prev->data,
2811 prev_line_len);
2812 current->prev->data[prev_line_len - 1] = '\0';
2813 totsize--;
2814 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002815 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002816 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002817
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002818 /* We've just justified a paragraph. If we're not justifying the
2819 * entire file, break out of the loop. Otherwise, continue the
2820 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002821 if (!full_justify)
2822 break;
2823
2824 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002825
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002826 /* We are now done justifying the paragraph or the file, so clean
2827 * up. totlines, totsize, and current_y have been maintained above.
2828 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002829 * fileage, and renumber() since edit_refresh() needs the line
2830 * numbers to be right (but only do the last two if we actually
2831 * justified something). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002832 last_par_line = current->prev;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002833 if (first_par_line != NULL) {
2834 if (first_par_line->prev == NULL)
2835 fileage = first_par_line;
2836 renumber(first_par_line);
2837 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002838
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002839 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002840
Chris Allegretta9149e612000-11-27 00:23:41 +00002841 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002842
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002843 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002844 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002845 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002846
Chris Allegretta6df90f52002-07-19 01:08:59 +00002847 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002848 * keystroke and return. */
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00002849 kbinput = get_edit_input(&meta_key, &func_key, FALSE);
Chris Allegretta5f071802001-05-06 02:34:31 +00002850
David Lawrence Ramsey45f971d2004-09-27 01:10:48 +00002851 if (!meta_key && !func_key && kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002852 /* Restore the justify we just did (ungrateful user!). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002853 filestruct *cutbottom = get_cutbottom();
2854
Chris Allegretta6df90f52002-07-19 01:08:59 +00002855 current = current_save;
2856 current_x = current_x_save;
2857 current_y = current_y_save;
2858 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002859
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002860 /* Splice the cutbuffer back into the file, but only if we
2861 * actually justified something. */
2862 if (first_par_line != NULL) {
2863 cutbottom->next = last_par_line->next;
2864 cutbottom->next->prev = cutbottom;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002865 /* The line numbers after the end of the paragraph have been
2866 * changed, so we change them back. */
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002867 renumber(cutbottom->next);
2868 if (first_par_line->prev != NULL) {
2869 cutbuffer->prev = first_par_line->prev;
2870 cutbuffer->prev->next = cutbuffer;
2871 } else
2872 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002873
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002874 last_par_line->next = NULL;
2875 free_filestruct(first_par_line);
2876 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002877
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002878 /* Restore global variables from before the justify. */
2879 totsize = totsize_save;
2880 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002881#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002882 mark_beginbuf = mark_beginbuf_save;
2883 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002884#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002885 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002886 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002887 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002888 edit_refresh();
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002889 } else {
2890 placewewant = 0;
David Lawrence Ramseyc59979f2004-10-23 02:47:39 +00002891 unget_kbinput(kbinput, meta_key, func_key);
Chris Allegretta9149e612000-11-27 00:23:41 +00002892 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002893
Chris Allegretta6df90f52002-07-19 01:08:59 +00002894 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002895 /* Note that now cutbottom is invalid, but that's okay. */
2896 blank_statusbar();
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002897
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002898 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002899 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002900 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002901}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002902
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002903void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002904{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002905 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002906}
2907
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002908void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002909{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002910 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002911}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002912#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002913
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002914void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002915{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002916 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002917
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002918 if (!ISSET(MODIFIED))
2919 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002920 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002921 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002922 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002923 i = do_yesno(FALSE,
2924 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2925
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002926#ifdef DEBUG
2927 dump_buffer(fileage);
2928#endif
2929
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002930 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002931#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002932 /* Exit only if there are no more open buffers. */
David Lawrence Ramsey3e189a82004-10-03 19:18:48 +00002933 if (!close_open_file())
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002934#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002935 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002936 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002937 statusbar(_("Cancelled"));
2938
2939 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002940}
2941
2942void signal_init(void)
2943{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002944 /* Trap SIGINT and SIGQUIT because we want them to do useful
2945 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002946 memset(&act, 0, sizeof(struct sigaction));
2947 act.sa_handler = SIG_IGN;
2948 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002949 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002950
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002951 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002952 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002953 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002954 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002955
2956#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002957 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002958 act.sa_handler = handle_sigwinch;
2959 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002960 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002961#endif
2962
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002963 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002964 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002965 act.sa_handler = SIG_IGN;
2966 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002967 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002968 /* Block all other signals in the suspend and continue handlers.
2969 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002970 sigfillset(&act.sa_mask);
2971
2972 act.sa_handler = do_suspend;
2973 sigaction(SIGTSTP, &act, NULL);
2974
2975 act.sa_handler = do_cont;
2976 sigaction(SIGCONT, &act, NULL);
2977 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002978}
2979
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002980/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002981RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002982{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002983 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002984}
2985
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002986/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002987RETSIGTYPE do_suspend(int signal)
2988{
2989 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002990 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002991 fflush(stdout);
2992
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002993 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002994 tcsetattr(0, TCSANOW, &oldterm);
2995
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002996 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002997 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002998 act.sa_handler = handle_hupterm;
2999 sigaction(SIGHUP, &act, NULL);
3000 sigaction(SIGTERM, &act, NULL);
3001
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003002 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003003 kill(0, SIGSTOP);
3004}
3005
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003006/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003007RETSIGTYPE do_cont(int signal)
3008{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003009#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003010 /* Perhaps the user resized the window while we slept. Handle it
3011 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003012 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00003013#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003014 /* Just update the screen. */
3015 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003016#endif
3017}
3018
3019#ifndef NANO_SMALL
3020void handle_sigwinch(int s)
3021{
3022 const char *tty = ttyname(0);
3023 int fd;
3024 int result = 0;
3025 struct winsize win;
3026
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003027 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003028 return;
3029 fd = open(tty, O_RDWR);
3030 if (fd == -1)
3031 return;
3032 result = ioctl(fd, TIOCGWINSZ, &win);
3033 close(fd);
3034 if (result == -1)
3035 return;
3036
3037 /* Could check whether the COLS or LINES changed, and return
3038 * otherwise. EXCEPT, that COLS and LINES are ncurses global
3039 * variables, and in some cases ncurses has already updated them.
3040 * But not in all cases, argh. */
3041 COLS = win.ws_col;
3042 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00003043 editwinrows = LINES - 5 + no_help();
3044 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003045 die_too_small();
3046
3047#ifndef DISABLE_WRAPJUSTIFY
3048 fill = wrap_at;
3049 if (fill <= 0)
3050 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00003051 if (fill < 0)
3052 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003053#endif
3054
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00003055 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003056 memset(hblank, ' ', COLS);
3057 hblank[COLS] = '\0';
3058
David Lawrence Ramsey40bdb682004-11-03 22:03:41 +00003059 /* If we've partitioned the filestruct, unpartition it now. */
3060 if (filepart != NULL)
3061 unpartition_filestruct(filepart);
3062
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003063#ifdef USE_SLANG
3064 /* Slang curses emulation brain damage, part 1: If we just do what
3065 * curses does here, it'll only work properly if the resize made the
3066 * window smaller. Do what mutt does: Leave and immediately reenter
3067 * Slang screen management mode. */
3068 SLsmg_reset_smg();
3069 SLsmg_init_smg();
3070#else
3071 /* Do the equivalent of what Minimum Profit does: Leave and
3072 * immediately reenter curses mode. */
3073 endwin();
3074 refresh();
3075#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003076
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003077 /* Restore the terminal to its previous state. */
3078 terminal_init();
3079
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003080 /* Do the equivalent of what both mutt and Minimum Profit do:
3081 * Reinitialize all the windows based on the new screen
3082 * dimensions. */
3083 window_init();
3084
3085 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003086 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003087 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003088 total_refresh();
3089
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003090 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003091 curs_set(1);
3092
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00003093 /* Reset all the input routines that rely on character sequences. */
3094 reset_kbinput();
3095
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00003096 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003097 siglongjmp(jmpbuf, 1);
3098}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003099
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003100void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003101{
3102 sigset_t winch;
3103 sigemptyset(&winch);
3104 sigaddset(&winch, SIGWINCH);
3105 if (allow)
3106 sigprocmask(SIG_UNBLOCK, &winch, NULL);
3107 else
3108 sigprocmask(SIG_BLOCK, &winch, NULL);
3109}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003110#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003111
Chris Allegrettadab017e2002-04-23 10:56:06 +00003112#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00003113void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00003114{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00003115 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00003116
Chris Allegretta658399a2001-06-14 02:54:22 +00003117 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003118 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00003119
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003120 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00003121 case TOGGLE_SUSPEND_KEY:
3122 signal_init();
3123 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003124#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003125 case TOGGLE_MOUSE_KEY:
3126 mouse_init();
3127 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003128#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003129 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003130 blank_statusbar();
3131 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00003132 wrefresh(bottomwin);
3133 window_init();
3134 edit_refresh();
3135 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00003136 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003137#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003138 case TOGGLE_SYNTAX_KEY:
3139 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003140 break;
3141#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003142#ifdef ENABLE_NANORC
3143 case TOGGLE_WHITESPACE_KEY:
3144 edit_refresh();
3145 break;
3146#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003147 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003148
Chris Allegretta6df90f52002-07-19 01:08:59 +00003149 /* We are assuming here that shortcut_init() above didn't free and
3150 * reallocate the toggles. */
3151 enabled = ISSET(which->flag);
3152 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3153 enabled = !enabled;
3154 statusbar("%s %s", which->desc,
3155 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003156}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003157#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003158
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003159void disable_extended_input(void)
3160{
3161 struct termios term;
3162
3163 tcgetattr(0, &term);
3164 term.c_lflag &= ~IEXTEN;
3165 tcsetattr(0, TCSANOW, &term);
3166}
3167
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003168void disable_signals(void)
3169{
3170 struct termios term;
3171
3172 tcgetattr(0, &term);
3173 term.c_lflag &= ~ISIG;
3174 tcsetattr(0, TCSANOW, &term);
3175}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003176
3177#ifndef NANO_SMALL
3178void enable_signals(void)
3179{
3180 struct termios term;
3181
3182 tcgetattr(0, &term);
3183 term.c_lflag |= ISIG;
3184 tcsetattr(0, TCSANOW, &term);
3185}
3186#endif
3187
3188void disable_flow_control(void)
3189{
3190 struct termios term;
3191
3192 tcgetattr(0, &term);
3193 term.c_iflag &= ~(IXON|IXOFF);
3194 tcsetattr(0, TCSANOW, &term);
3195}
3196
3197void enable_flow_control(void)
3198{
3199 struct termios term;
3200
3201 tcgetattr(0, &term);
3202 term.c_iflag |= (IXON|IXOFF);
3203 tcsetattr(0, TCSANOW, &term);
3204}
3205
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003206/* Set up the terminal state. Put the terminal in cbreak mode (read one
3207 * character at a time and interpret the special control keys), disable
3208 * translation of carriage return (^M) into newline (^J) so that we can
3209 * tell the difference between the Enter key and Ctrl-J, and disable
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003210 * echoing of characters as they're typed. Finally, disable extended
3211 * input processing, disable interpretation of the special control keys,
3212 * and if we're not in preserve mode, disable interpretation of the flow
3213 * control characters too. */
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003214void terminal_init(void)
3215{
3216 cbreak();
3217 nonl();
3218 noecho();
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00003219 disable_extended_input();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003220 disable_signals();
3221 if (!ISSET(PRESERVE))
3222 disable_flow_control();
3223}
3224
David Lawrence Ramseya27bd652004-08-17 05:23:38 +00003225int main(int argc, char **argv)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003226{
3227 int optchr;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003228 int startline = 0;
3229 /* Line to try and start at. */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003230#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003231 bool fill_flag_used = FALSE;
3232 /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003233#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003234#ifdef ENABLE_MULTIBUFFER
3235 bool old_multibuffer;
3236 /* The old value of the multibuffer option, restored after we
3237 * load all files on the command line. */
3238#endif
3239 int kbinput;
3240 /* Input from keyboard. */
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00003241 bool meta_key, func_key;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003242#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003243 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003244 {"help", 0, 0, 'h'},
3245#ifdef ENABLE_MULTIBUFFER
3246 {"multibuffer", 0, 0, 'F'},
3247#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003248#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003249#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003250 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003251#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003252 {"ignorercfiles", 0, 0, 'I'},
3253#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003254#ifndef DISABLE_JUSTIFY
3255 {"quotestr", 1, 0, 'Q'},
3256#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003257#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003258 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003259#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003260 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003261 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003262#ifdef ENABLE_COLOR
3263 {"syntax", 1, 0, 'Y'},
3264#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003265 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003266 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003267 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003268#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003269 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003270#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003271#ifndef DISABLE_OPERATINGDIR
3272 {"operatingdir", 1, 0, 'o'},
3273#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003274 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003275#ifndef DISABLE_WRAPJUSTIFY
3276 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003277#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003278#ifndef DISABLE_SPELLER
3279 {"speller", 1, 0, 's'},
3280#endif
3281 {"tempfile", 0, 0, 't'},
3282 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003283#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003284 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003285#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003286 {"nohelp", 0, 0, 'x'},
3287 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003288#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003289 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003290 {"backup", 0, 0, 'B'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003291 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003292 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003293 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003294 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003295 {"autoindent", 0, 0, 'i'},
3296 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003297#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003298 {0, 0, 0, 0}
3299 };
3300#endif
3301
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003302 setlocale(LC_ALL, "");
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003303#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003304 bindtextdomain(PACKAGE, LOCALEDIR);
3305 textdomain(PACKAGE);
3306#endif
3307
Chris Allegretta7662c862003-01-13 01:35:15 +00003308#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003309 /* If we don't have rcfile support, we're root, and
3310 * --disable-wrapping-as-root is used, turn wrapping off. */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003311 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003312 SET(NO_WRAP);
3313#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003314
Chris Allegretta6df90f52002-07-19 01:08:59 +00003315 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003316#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey28caf142004-10-07 20:54:52 +00003317 getopt_long(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003318#else
David Lawrence Ramsey28caf142004-10-07 20:54:52 +00003319 getopt(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003320#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003321 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003322
3323 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003324 case 'a':
3325 case 'b':
3326 case 'e':
3327 case 'f':
3328 case 'g':
3329 case 'j':
3330 /* Pico compatibility flags. */
3331 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003332#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003333 case 'A':
3334 SET(SMART_HOME);
3335 break;
3336 case 'B':
3337 SET(BACKUP_FILE);
3338 break;
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003339 case 'E':
3340 backup_dir = mallocstrcpy(backup_dir, optarg);
3341 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003342#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003343#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003344 case 'F':
3345 SET(MULTIBUFFER);
3346 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003347#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003348#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003349#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003350 case 'H':
3351 SET(HISTORYLOG);
3352 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003353#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003354 case 'I':
3355 SET(NO_RCFILE);
3356 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003357#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003358#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003359 case 'N':
3360 SET(NO_CONVERT);
3361 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003362#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003363#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003364 case 'Q':
3365 quotestr = mallocstrcpy(quotestr, optarg);
3366 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003367#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003368#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003369 case 'R':
3370 SET(USE_REGEXP);
3371 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003372#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003373#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003374 case 'S':
3375 SET(SMOOTHSCROLL);
3376 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003377#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003378 case 'T':
3379 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003380 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
3381 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003382 exit(1);
3383 }
3384 break;
3385 case 'V':
3386 version();
3387 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003388#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003389 case 'Y':
3390 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3391 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00003392#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003393 case 'Z':
3394 SET(RESTRICTED);
3395 break;
3396 case 'c':
3397 SET(CONSTUPDATE);
3398 break;
3399 case 'd':
3400 SET(REBIND_DELETE);
3401 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003402#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003403 case 'i':
3404 SET(AUTOINDENT);
3405 break;
3406 case 'k':
3407 SET(CUT_TO_END);
3408 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003409#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003410 case 'l':
3411 SET(NOFOLLOW_SYMLINKS);
3412 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003413#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003414 case 'm':
3415 SET(USE_MOUSE);
3416 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003417#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003418#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003419 case 'o':
3420 operating_dir = mallocstrcpy(operating_dir, optarg);
3421 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003422#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003423 case 'p':
3424 SET(PRESERVE);
3425 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003426#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003427 case 'r':
3428 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003429 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
3430 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003431 exit(1);
3432 }
3433 fill_flag_used = TRUE;
3434 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003435#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003436#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003437 case 's':
3438 alt_speller = mallocstrcpy(alt_speller, optarg);
3439 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003440#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003441 case 't':
3442 SET(TEMP_FILE);
3443 break;
3444 case 'v':
3445 SET(VIEW_MODE);
3446 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003447#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003448 case 'w':
3449 SET(NO_WRAP);
3450 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003451#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003452 case 'x':
3453 SET(NO_HELP);
3454 break;
3455 case 'z':
3456 SET(SUSPEND);
3457 break;
3458 default:
3459 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003460 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003461 }
3462
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003463 /* If the executable filename starts with 'r', we use restricted
3464 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003465 if (*(tail(argv[0])) == 'r')
3466 SET(RESTRICTED);
3467
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003468 /* If we're using restricted mode, disable suspending, backups, and
3469 * reading rcfiles, since they all would allow reading from or
3470 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003471 if (ISSET(RESTRICTED)) {
3472 UNSET(SUSPEND);
3473 UNSET(BACKUP_FILE);
3474 SET(NO_RCFILE);
3475 }
3476
Chris Allegretta7662c862003-01-13 01:35:15 +00003477/* We've read through the command line options. Now back up the flags
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003478 * and values that are set, and read the rcfile(s). If the values
3479 * haven't changed afterward, restore the backed-up values. */
Chris Allegretta7662c862003-01-13 01:35:15 +00003480#ifdef ENABLE_NANORC
3481 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003482#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003483 char *operating_dir_cpy = operating_dir;
3484#endif
David Lawrence Ramsey7e8dd192004-08-12 20:06:20 +00003485#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003486 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003487#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003488#ifndef NANO_SMALL
3489 char *backup_dir_cpy = backup_dir;
3490#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003491#ifndef DISABLE_JUSTIFY
3492 char *quotestr_cpy = quotestr;
3493#endif
3494#ifndef DISABLE_SPELLER
3495 char *alt_speller_cpy = alt_speller;
3496#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003497 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003498 long flags_cpy = flags;
3499
Chris Allegretta5ec68622003-02-05 02:39:34 +00003500#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003501 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003502#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003503#ifndef NANO_SMALL
3504 backup_dir = NULL;
3505#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003506#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003507 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003508#endif
3509#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003510 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003511#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003512
3513 do_rcfile();
3514
3515#ifndef DISABLE_OPERATINGDIR
3516 if (operating_dir_cpy != NULL) {
3517 free(operating_dir);
3518 operating_dir = operating_dir_cpy;
3519 }
3520#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003521#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003522 if (fill_flag_used)
3523 wrap_at = wrap_at_cpy;
3524#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003525#ifndef NANO_SMALL
3526 if (backup_dir_cpy != NULL) {
3527 free(backup_dir);
3528 backup_dir = backup_dir_cpy;
3529 }
3530#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003531#ifndef DISABLE_JUSTIFY
3532 if (quotestr_cpy != NULL) {
3533 free(quotestr);
3534 quotestr = quotestr_cpy;
3535 }
3536#endif
3537#ifndef DISABLE_SPELLER
3538 if (alt_speller_cpy != NULL) {
3539 free(alt_speller);
3540 alt_speller = alt_speller_cpy;
3541 }
3542#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00003543 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00003544 tabsize = tabsize_cpy;
3545 flags |= flags_cpy;
3546 }
3547#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003548 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003549 SET(NO_WRAP);
3550#endif
3551#endif /* ENABLE_NANORC */
3552
Chris Allegrettad8451932003-03-11 03:50:40 +00003553#ifndef NANO_SMALL
3554 history_init();
3555#ifdef ENABLE_NANORC
3556 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3557 load_history();
3558#endif
3559#endif
3560
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003561#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003562 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003563 * in which case backups are disabled, since they would allow
3564 * reading from or writing to files not specified on the command
3565 * line). This entails making sure it exists and is a directory, so
3566 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003567 if (!ISSET(RESTRICTED))
3568 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003569#endif
3570
Chris Allegretta7662c862003-01-13 01:35:15 +00003571#ifndef DISABLE_OPERATINGDIR
3572 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003573 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003574 init_operating_dir();
3575#endif
3576
Chris Allegretta7662c862003-01-13 01:35:15 +00003577#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003578 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003579 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003580
3581 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003582 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003583
Chris Allegretta7662c862003-01-13 01:35:15 +00003584 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003585 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003586#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003587 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003588#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003589 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003590#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003591 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003592#ifdef HAVE_REGEX_H
3593 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
3594
3595 if (quoterc == 0) {
3596 /* We no longer need quotestr, just quotereg. */
3597 free(quotestr);
3598 quotestr = NULL;
3599 } else {
3600 size_t size = regerror(quoterc, &quotereg, NULL, 0);
3601
3602 quoteerr = charalloc(size);
3603 regerror(quoterc, &quotereg, quoteerr, size);
3604 }
3605#else
3606 quotelen = strlen(quotestr);
3607#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00003608#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003609
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003610#ifndef DISABLE_SPELLER
3611 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003612 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003613 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003614 * checking is disabled, since it would allow reading from or
3615 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003616 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003617 char *spellenv = getenv("SPELL");
3618 if (spellenv != NULL)
3619 alt_speller = mallocstrcpy(NULL, spellenv);
3620 }
3621#endif
3622
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003623#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003624 /* If whitespace wasn't specified, set its default value. */
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003625 if (whitespace == NULL)
3626 whitespace = mallocstrcpy(NULL, " ");
3627#endif
3628
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003629 /* If tabsize wasn't specified, set its default value. */
Chris Allegretta7662c862003-01-13 01:35:15 +00003630 if (tabsize == -1)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003631 tabsize = WIDTH_OF_TAB;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003632
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003633 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003634 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003635
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003636 /* Curses initialization stuff: Start curses and set up the
3637 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003638 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003639 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003640
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003641 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003642 global_init(FALSE);
3643 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003644
3645 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003646 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003647
3648#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003649 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003650#endif
3651
Chris Allegretta2a42af12000-09-12 23:02:49 +00003652 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003653#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003654 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003655#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003656
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003657#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003658 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003659#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003660
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00003661 /* If there's a +LINE flag here, it is the first non-option
3662 * argument, and it is followed by at least one other argument, the
3663 * filename it applies to. */
3664 if (0 < optind && optind < argc - 1 && argv[optind][0] == '+') {
3665 startline = atoi(&argv[optind][1]);
3666 optind++;
3667 }
3668
Chris Allegretta7662c862003-01-13 01:35:15 +00003669#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003670 old_multibuffer = ISSET(MULTIBUFFER);
3671 SET(MULTIBUFFER);
3672
3673 /* Read all the files after the first one on the command line into
3674 * new buffers. */
3675 {
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00003676 int i = optind + 1, iline = 0;
3677 for (; i < argc; i++) {
3678 /* If there's a +LINE flag here, it is followed by at least
3679 * one other argument, the filename it applies to. */
3680 if (i < argc - 1 && argv[i][0] == '+' && iline == 0) {
3681 iline = atoi(&argv[i][1]);
3682 } else {
3683 load_buffer(argv[i]);
3684 if (iline > 0) {
3685 do_gotoline(iline, FALSE);
3686 iline = 0;
3687 }
3688 }
3689 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003690 }
3691#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003692
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003693 /* Read the first file on the command line into either the current
3694 * buffer or a new buffer, depending on whether multibuffer mode is
3695 * enabled. */
3696 if (optind < argc)
3697 load_buffer(argv[optind]);
3698
3699 /* We didn't open any files if all the command line arguments were
3700 * invalid files like directories or if there were no command line
3701 * arguments given. In this case, we have to load a blank buffer.
3702 * Also, we unset view mode to allow editing. */
3703 if (filename == NULL) {
3704 filename = mallocstrcpy(NULL, "");
3705 new_file();
3706 UNSET(VIEW_MODE);
3707
3708 /* Add this new entry to the open_files structure if we have
3709 * multibuffer support, or to the main filestruct if we don't. */
3710 load_file();
3711 }
3712
3713#ifdef ENABLE_MULTIBUFFER
3714 if (!old_multibuffer)
3715 UNSET(MULTIBUFFER);
3716#endif
3717
3718#ifdef DEBUG
3719 fprintf(stderr, "Main: top and bottom win\n");
3720#endif
3721
3722 titlebar(NULL);
3723 display_main_list();
3724
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003725 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003726 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003727
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003728#ifndef NANO_SMALL
3729 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003730 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003731#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003732
Robert Siemborski6967eec2000-07-08 14:23:32 +00003733 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00003734
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003735 while (TRUE) {
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00003736 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003737 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003738 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003739
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003740#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003741 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003742#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003743
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00003744 kbinput = get_edit_input(&meta_key, &func_key, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003745
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003746 /* Last gasp, stuff that's not in the main lists. */
David Lawrence Ramseye6ef8b92004-09-12 22:01:38 +00003747 if (kbinput != ERR && !is_cntrl_char(kbinput)) {
David Lawrence Ramsey807657b2004-09-12 21:40:04 +00003748 /* Don't stop unhandled printable sequences, so that people
3749 * with odd character sets can type. */
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003750 if (ISSET(VIEW_MODE))
3751 print_view_warning();
3752 else
3753 do_char(kbinput);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003754 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003755 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003756 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003757}