blob: d6ee2865856566fbc464fbd1d4d65f2d93782e72 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/stat.h>
32#include <sys/ioctl.h>
33#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000034#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000035#include <errno.h>
36#include <ctype.h>
37#include <locale.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000038#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000039#include "proto.h"
40#include "nano.h"
41
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#ifdef HAVE_TERMIOS_H
43#include <termios.h>
44#endif
45
46#ifdef HAVE_TERMIO_H
47#include <termio.h>
48#endif
49
50#ifdef HAVE_GETOPT_H
51#include <getopt.h>
52#endif
53
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000054#ifndef NANO_SMALL
55#include <setjmp.h>
56#endif
57
Chris Allegretta6fe61492001-05-21 12:56:25 +000058#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000059static ssize_t fill = 0; /* Fill - where to wrap lines,
60 basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000061#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000062#ifndef DISABLE_WRAPPING
David Lawrence Ramseyce62e822004-08-05 22:10:22 +000063static bool same_line_wrap = FALSE; /* Whether wrapped text should
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000064 be prepended to the next
65 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000066#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000067
Chris Allegretta6df90f52002-07-19 01:08:59 +000068static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000069static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000071#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000072static sigjmp_buf jmpbuf; /* Used to return to mainloop after
73 SIGWINCH */
David Lawrence Ramsey22fac782004-08-05 15:16:19 +000074static int pid; /* The PID of the newly forked process
75 * in open_pipe(). It must be global
76 * because the signal handler needs
77 * it. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000078#endif
Chris Allegretta08020882001-01-29 23:37:54 +000079
David Lawrence Ramseyda141062004-05-25 19:41:11 +000080/* What we do when we're all set to exit. */
81void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000082{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000083 if (!ISSET(NO_HELP))
84 blank_bottombars();
85 else
86 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000087
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088 wrefresh(bottomwin);
89 endwin();
90
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000091 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000092 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000093
Chris Allegrettad8451932003-03-11 03:50:40 +000094#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
95 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
96 save_history();
97#endif
98
Chris Allegretta6232d662002-05-12 19:52:15 +000099#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000100 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000101#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000102
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000103 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000104}
105
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000106/* Die (gracefully?). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000107void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000108{
109 va_list ap;
110
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000111 endwin();
112 curses_ended = TRUE;
113
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000114 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000115 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000116
Chris Allegretta6df90f52002-07-19 01:08:59 +0000117 va_start(ap, msg);
118 vfprintf(stderr, msg, ap);
119 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000120
Chris Allegretta32da4562002-01-02 15:12:21 +0000121 /* save the currently loaded file if it's been modified */
122 if (ISSET(MODIFIED))
123 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000124
Chris Allegretta355fbe52001-07-14 19:32:47 +0000125#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000126 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000127 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000128 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000129
130 tmp = open_files;
131
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000132 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000133 open_files = open_files->prev;
134
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000135 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000136
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000137 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000138 currently loaded file), don't save it again */
139 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000140 /* make sure open_files->fileage and fileage, and
141 open_files->filebot and filebot, are in sync; they
142 might not be if lines have been cut from the top or
143 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000144 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000145 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000146 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000147 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000148 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150 open_files = open_files->next;
151 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000152 }
153#endif
154
Chris Allegretta6df90f52002-07-19 01:08:59 +0000155 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000156}
157
Chris Allegretta6df90f52002-07-19 01:08:59 +0000158void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000160 char *ret;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000161 bool failed = TRUE;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000162
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000163 /* If we're using restricted mode, don't write any emergency backup
164 * files, since that would allow reading from or writing to files
165 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000166 if (ISSET(RESTRICTED))
167 return;
168
Chris Allegretta6df90f52002-07-19 01:08:59 +0000169 /* If we can't save, we have REAL bad problems, but we might as well
170 TRY. */
171 if (die_filename[0] == '\0')
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000172 die_filename = "nano";
Chris Allegretta6df90f52002-07-19 01:08:59 +0000173
David Lawrence Ramsey049e4a52004-08-10 23:05:59 +0000174 ret = get_next_filename(die_filename);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000175 if (ret[0] != '\0')
David Lawrence Ramsey951d7142004-10-04 15:23:47 +0000176 failed = (write_file(ret, TRUE, FALSE, TRUE) == -1);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000177
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000178 if (!failed)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000179 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000180 else
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000181 fprintf(stderr, _("\nBuffer not written to %s (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000182
183 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000184}
185
Chris Allegrettae61e8302001-01-14 05:18:27 +0000186/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000187 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000188void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000189{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000190 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000191}
192
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000193void print_view_warning(void)
194{
195 statusbar(_("Key illegal in VIEW mode"));
196}
197
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000198/* Initialize global variables -- no better way for now. If
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000199 * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
200void global_init(bool save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000201{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000202 current_x = 0;
203 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000204
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000205 editwinrows = LINES - 5 + no_help();
206 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000207 die_too_small();
208
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000209 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000210 if (!save_cutbuffer)
211 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000212 current = NULL;
213 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000214 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000215 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000216 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000217
Chris Allegretta6fe61492001-05-21 12:56:25 +0000218#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000219 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000220 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000221 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000222 if (fill < 0)
223 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000224#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000225
Chris Allegretta88b09152001-05-17 11:35:43 +0000226 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000227 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000228 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000229}
230
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000231void window_init(void)
232{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000233 editwinrows = LINES - 5 + no_help();
234 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000235 die_too_small();
236
Chris Allegretta1a128af2003-01-26 04:15:56 +0000237 if (topwin != NULL)
238 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000239 if (edit != NULL)
240 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000241 if (bottomwin != NULL)
242 delwin(bottomwin);
243
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000244 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000245 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000246 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000247 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
248
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000249 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000250 keypad(edit, TRUE);
251 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252}
253
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000254#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255void mouse_init(void)
256{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258 mousemask(BUTTON1_RELEASED, NULL);
259 mouseinterval(50);
260 } else
261 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000262}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000263#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000264
265#ifndef DISABLE_HELP
266/* This function allocates help_text, and stores the help string in it.
267 * help_text should be NULL initially. */
268void help_init(void)
269{
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000270 size_t allocsize = 1; /* Space needed for help_text. */
271 const char *htx; /* Untranslated help message. */
272 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000273 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000274#ifndef NANO_SMALL
275 const toggle *t;
276#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000277
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000278 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000279 if (currshortcut == whereis_list || currshortcut == replace_list
280 || currshortcut == replace_list_2)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000281 htx = N_("Search Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000282 "Enter the words or characters you would like to search "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000283 "for, then hit Enter. If there is a match for the text you "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000284 "entered, the screen will be updated to the location of the "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000285 "nearest match for the search string.\n\n The previous "
286 "search string will be shown in brackets after the search "
287 "prompt. Hitting Enter without entering any text will "
288 "perform the previous search. If you have selected text "
289 "with the mark and then search to replace, only matches in "
290 "the selected text will be replaced.\n\n The following "
291 "function keys are available in Search mode:\n\n");
David Lawrence Ramseye5d8f322004-09-30 22:07:21 +0000292 else if (currshortcut == gotoline_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000293 htx = N_("Go To Line Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000294 "Enter the line number that you wish to go to and hit "
295 "Enter. If there are fewer lines of text than the "
296 "number you entered, you will be brought to the last line "
297 "of the file.\n\n The following function keys are "
298 "available in Go To Line mode:\n\n");
299 else if (currshortcut == insertfile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000300 htx = N_("Insert File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000301 "Type in the name of a file to be inserted into the current "
302 "file buffer at the current cursor location.\n\n "
303 "If you have compiled nano with multiple file buffer "
304 "support, and enable multiple buffers with the -F "
305 "or --multibuffer command line flags, the Meta-F toggle, or "
306 "a nanorc file, inserting a file will cause it to be "
307 "loaded into a separate buffer (use Meta-< and > to switch "
308 "between file buffers).\n\n If you need another blank "
309 "buffer, do not enter any filename, or type in a "
310 "nonexistent filename at the prompt and press "
311 "Enter.\n\n The following function keys are "
312 "available in Insert File mode:\n\n");
313 else if (currshortcut == writefile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000314 htx = N_("Write File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000315 "Type the name that you wish to save the current file "
316 "as and hit Enter to save the file.\n\n If you have "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000317 "selected text with the mark, you will be prompted to "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000318 "save only the selected portion to a separate file. To "
319 "reduce the chance of overwriting the current file with "
320 "just a portion of it, the current filename is not the "
321 "default in this mode.\n\n The following function keys "
322 "are available in Write File mode:\n\n");
323#ifndef DISABLE_BROWSER
324 else if (currshortcut == browser_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000325 htx = N_("File Browser Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000326 "The file browser is used to visually browse the "
327 "directory structure to select a file for reading "
328 "or writing. You may use the arrow keys or Page Up/"
329 "Down to browse through the files, and S or Enter to "
330 "choose the selected file or enter the selected "
331 "directory. To move up one level, select the directory "
332 "called \"..\" at the top of the file list.\n\n The "
333 "following function keys are available in the file "
334 "browser:\n\n");
335 else if (currshortcut == gotodir_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000336 htx = N_("Browser Go To Directory Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000337 "Enter the name of the directory you would like to "
338 "browse to.\n\n If tab completion has not been disabled, "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000339 "you can use the Tab key to (attempt to) automatically "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000340 "complete the directory name.\n\n The following function "
341 "keys are available in Browser Go To Directory mode:\n\n");
342#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000343#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000344 else if (currshortcut == spell_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000345 htx = N_("Spell Check Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000346 "The spell checker checks the spelling of all text "
347 "in the current file. When an unknown word is "
348 "encountered, it is highlighted and a replacement can "
349 "be edited. It will then prompt to replace every "
350 "instance of the given misspelled word in the "
David Lawrence Ramsey381d4832004-10-18 01:51:43 +0000351 "current file, or, if you have selected text with the "
352 "mark, in the selected text.\n\n The following other "
353 "functions are available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000354#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000355#ifndef NANO_SMALL
356 else if (currshortcut == extcmd_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000357 htx = N_("External Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000358 "This menu allows you to insert the output of a command "
359 "run by the shell into the current buffer (or a new "
360 "buffer in multibuffer mode).\n\n The following keys are "
361 "available in this mode:\n\n");
362#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000363 else
364 /* Default to the main help list. */
365 htx = N_(" nano help text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000366 "The nano editor is designed to emulate the functionality and "
367 "ease-of-use of the UW Pico text editor. There are four main "
368 "sections of the editor: The top line shows the program "
369 "version, the current filename being edited, and whether "
370 "or not the file has been modified. Next is the main editor "
371 "window showing the file being edited. The status line is "
372 "the third line from the bottom and shows important messages. "
373 "The bottom two lines show the most commonly used shortcuts "
374 "in the editor.\n\n "
375 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000376 "sequences are notated with a caret (^) symbol and can be "
377 "entered either by using the Control (Ctrl) key or pressing the "
378 "Esc key twice. Escape-key sequences are notated with the Meta "
379 "(M) symbol and can be entered using either the Esc, Alt or "
380 "Meta key depending on your keyboard setup. Also, pressing Esc "
381 "twice and then typing a three-digit number from 000 to 255 "
382 "will enter the character with the corresponding ASCII code. "
383 "The following keystrokes are available in the main editor "
384 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000385
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000386 htx = _(htx);
387
388 allocsize += strlen(htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000389
390 /* The space needed for the shortcut lists, at most COLS characters,
391 * plus '\n'. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000392 allocsize += (COLS < 21 ? 21 : COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000393
394#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000395 /* If we're on the main list, we also count the toggle help text.
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000396 * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
397 * plus translated text, plus '\n'. */
Chris Allegretta3a784062003-02-10 02:32:58 +0000398 if (currshortcut == main_list) {
399 size_t endislen = strlen(_("enable/disable"));
400
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000401 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000402 allocsize += 8 + strlen(t->desc) + endislen;
403 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000404#endif /* !NANO_SMALL */
405
406 /* help_text has been freed and set to NULL unless the user resized
407 * while in the help screen. */
408 free(help_text);
409
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000410 /* Allocate space for the help text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000411 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000412
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000413 /* Now add the text we want. */
414 strcpy(help_text, htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000415 ptr = help_text + strlen(help_text);
416
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000417 /* Now add our shortcut info. Assume that each shortcut has, at the
418 * very least, an equivalent control key, an equivalent primary meta
419 * key sequence, or both. Also assume that the meta key values are
420 * not control characters. We can display a maximum of 3 shortcut
421 * entries. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000422 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000423 int entries = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000424
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000425 /* Control key. */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000426 if (s->ctrlval != NANO_NO_KEY) {
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000427 entries++;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000428#ifndef NANO_SMALL
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000429 if (s->ctrlval == NANO_HISTORY_KEY)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000430 ptr += sprintf(ptr, "%.7s", _("Up"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000431 else
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000432#endif
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000433 if (s->ctrlval == NANO_CONTROL_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000434 ptr += sprintf(ptr, "^%.6s", _("Space"));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000435 else if (s->ctrlval == NANO_CONTROL_8)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000436 ptr += sprintf(ptr, "^?");
437 else
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000438 ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000439 *(ptr++) = '\t';
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000440 }
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000441
442 /* Function key. */
443 if (s->funcval != NANO_NO_KEY) {
444 entries++;
445 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
446 *(ptr++) = '\t';
447 }
448
449 /* Primary meta key sequence. */
450 if (s->metaval != NANO_NO_KEY) {
451 entries++;
452 /* If this is the last entry, put it at the end. */
453 if (entries == 2 && s->miscval == NANO_NO_KEY) {
454 entries++;
455 *(ptr++) = '\t';
456 }
457 /* If the primary meta key sequence is the first entry,
458 * don't put parentheses around it. */
459 if (entries == 1 && s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000460 ptr += sprintf(ptr, "M-%.5s", _("Space"));
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000461 else
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000462 ptr += sprintf(ptr, entries == 1 ? "M-%c" : "(M-%c)",
463 toupper(s->metaval));
464 *(ptr++) = '\t';
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000465 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000466
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000467 /* Miscellaneous meta key sequence. */
468 if (entries < 3 && s->miscval != NANO_NO_KEY) {
469 entries++;
470 /* If this is the last entry, put it at the end. */
471 if (entries == 2) {
472 entries++;
473 *(ptr++) = '\t';
474 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000475 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000476 *(ptr++) = '\t';
477 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000478
David Lawrence Ramseydb6015c2004-09-11 21:41:13 +0000479 /* Make sure all the help text starts at the same place. */
480 while (entries < 3) {
481 entries++;
482 *(ptr++) = '\t';
483 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000484
485 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000486 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000487 }
488
489#ifndef NANO_SMALL
490 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000491 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000492 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000493 assert(t->desc != NULL);
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +0000494 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
495 t->desc, _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000496 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000497 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000498#endif /* !NANO_SMALL */
499
500 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000501 * help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000502 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000503}
504#endif
505
506/* Create a new filestruct node. Note that we specifically do not set
507 * prevnode->next equal to the new line. */
508filestruct *make_new_node(filestruct *prevnode)
509{
510 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
511
512 newnode->data = NULL;
513 newnode->prev = prevnode;
514 newnode->next = NULL;
515 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
516
517 return newnode;
518}
519
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000520/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000521filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000522{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000523 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000524
Chris Allegretta6df90f52002-07-19 01:08:59 +0000525 assert(src != NULL);
526
Chris Allegretta88b09152001-05-17 11:35:43 +0000527 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000528 dst->next = src->next;
529 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000530 strcpy(dst->data, src->data);
531 dst->lineno = src->lineno;
532
533 return dst;
534}
535
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000536/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000537void splice_node(filestruct *begin, filestruct *newnode, filestruct
538 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000539{
540 if (newnode != NULL) {
541 newnode->next = end;
542 newnode->prev = begin;
543 }
544 if (begin != NULL)
545 begin->next = newnode;
546 if (end != NULL)
547 end->prev = newnode;
548}
549
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000550/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000552{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000553 assert(fileptr != NULL);
554
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000555 if (fileptr->prev != NULL)
556 fileptr->prev->next = fileptr->next;
557
558 if (fileptr->next != NULL)
559 fileptr->next->prev = fileptr->prev;
560}
561
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000562/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000563void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000564{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000565 if (fileptr != NULL) {
566 if (fileptr->data != NULL)
567 free(fileptr->data);
568 free(fileptr);
569 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000570}
571
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000572/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000575 filestruct *head; /* copy of src, top of the copied list */
576 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000579
Chris Allegretta6df90f52002-07-19 01:08:59 +0000580 prev = copy_node(src);
581 prev->prev = NULL;
582 head = prev;
583 src = src->next;
584 while (src != NULL) {
585 prev->next = copy_node(src);
586 prev->next->prev = prev;
587 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000588
Chris Allegretta6df90f52002-07-19 01:08:59 +0000589 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590 }
591
Chris Allegretta6df90f52002-07-19 01:08:59 +0000592 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000593 return head;
594}
595
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000596/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000597void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000598{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000599 if (src != NULL) {
600 while (src->next != NULL) {
601 src = src->next;
602 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000603#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000604 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000605#endif
606 }
607 delete_node(src);
608#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000609 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000610#endif
611 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000612}
613
Chris Allegretta6df90f52002-07-19 01:08:59 +0000614void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000615{
616 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000617 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000618
Chris Allegretta6df90f52002-07-19 01:08:59 +0000619 assert(fileage == NULL || fileage != fileage->next);
620 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000621 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000622}
623
Chris Allegretta6df90f52002-07-19 01:08:59 +0000624void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000625{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000626 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000627 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000628 else {
629 int lineno = fileptr->prev->lineno;
630
631 assert(fileptr != fileptr->next);
632 for (; fileptr != NULL; fileptr = fileptr->next)
633 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000634 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000635}
636
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000637/* Print one usage string to the screen. This cuts down on duplicate
638 * strings to translate and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000639 * translatable (the flag names). */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000640void print1opt(const char *shortflag, const char *longflag, const char
641 *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000642{
643 printf(" %s\t", shortflag);
644 if (strlen(shortflag) < 8)
645 printf("\t");
646
647#ifdef HAVE_GETOPT_LONG
648 printf("%s\t", longflag);
649 if (strlen(longflag) < 8)
650 printf("\t\t");
651 else if (strlen(longflag) < 16)
652 printf("\t");
653#endif
654
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000655 printf("%s\n", _(desc));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000656}
657
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000658void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000659{
660#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000661 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
662 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000663#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000664 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
665 printf(_("Option\t\tMeaning\n"));
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +0000666#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000667
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000668 print1opt("-h, -?", "--help", N_("Show this message"));
669 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000670#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000671 print1opt("-A", "--smarthome", N_("Enable smart home key"));
672 print1opt("-B", "--backup", N_("Backup existing files on save"));
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000673 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000674#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000675#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000676 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000677#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000678#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000679#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000680 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000681#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000682 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000683#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000684#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000685 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000686#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000687#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000688 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000689#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000690#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000691 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000692#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000693#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000694 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000695#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000696 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
697 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000698#ifdef ENABLE_COLOR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000699 print1opt(_("-Y [str]"), _("--syntax [str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000700#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000701 print1opt("-Z", "--restricted", N_("Restricted mode"));
702 print1opt("-c", "--const", N_("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000703#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000704 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
705 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
706 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000707#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000708 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000709#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000710 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000711#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000712#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000713 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000714#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000715 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000716#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000717 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000718#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000719#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000720 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000721#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000722 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
723 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000724#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000725 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000726#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000727 print1opt("-x", "--nohelp", N_("Don't show help window"));
728 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000729
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000730 /* This is a special case. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000731 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000732
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000733 exit(0);
734}
735
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000736void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000737{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000738 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000739 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000740 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000741 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000742 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000743
Chris Allegrettae6600372003-01-17 03:39:41 +0000744#ifndef ENABLE_NLS
745 printf(" --disable-nls");
746#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000747#ifdef DEBUG
748 printf(" --enable-debug");
749#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000750#ifdef NANO_EXTRA
751 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000752#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000753#ifdef NANO_SMALL
754 printf(" --enable-tiny");
755#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000756#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000757 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000758#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000759#ifdef DISABLE_HELP
760 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000761#endif
762#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000763 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000764#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000765#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000766 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000767#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000768#ifdef DISABLE_OPERATINGDIR
769 printf(" --disable-operatingdir");
770#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000771#ifdef DISABLE_SPELLER
772 printf(" --disable-speller");
773#endif
774#ifdef DISABLE_TABCOMP
775 printf(" --disable-tabcomp");
776#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000777#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000778#ifdef DISABLE_WRAPPING
779 printf(" --disable-wrapping");
780#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000781#ifdef DISABLE_ROOTWRAP
782 printf(" --disable-wrapping-as-root");
783#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000784#ifdef ENABLE_COLOR
785 printf(" --enable-color");
786#endif
787#ifdef ENABLE_MULTIBUFFER
788 printf(" --enable-multibuffer");
789#endif
790#ifdef ENABLE_NANORC
791 printf(" --enable-nanorc");
792#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000793#ifdef USE_SLANG
794 printf(" --with-slang");
795#endif
796 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000797}
798
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000799int no_help(void)
800{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000801 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000802}
803
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000804void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000805{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000806 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000807}
808
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000809#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000810RETSIGTYPE cancel_fork(int signal)
811{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000812 if (kill(pid, SIGKILL) == -1)
813 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000814}
815
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000816/* Return TRUE on success. */
817bool open_pipe(const char *command)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000818{
819 int fd[2];
820 FILE *f;
821 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000822 /* Original and temporary handlers for
823 * SIGINT. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000824 bool sig_failed = FALSE;
825 /* sig_failed means that sigaction() failed without changing the
826 * signal handlers.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000827 *
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000828 * We use this variable since it is important to put things back
829 * when we finish, even if we get errors. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000830
831 /* Make our pipes. */
832
833 if (pipe(fd) == -1) {
834 statusbar(_("Could not pipe"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000835 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000836 }
837
838 /* Fork a child. */
839
840 if ((pid = fork()) == 0) {
841 close(fd[0]);
842 dup2(fd[1], fileno(stdout));
843 dup2(fd[1], fileno(stderr));
844 /* If execl() returns at all, there was an error. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000845
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000846 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000847 exit(0);
848 }
849
850 /* Else continue as parent. */
851
852 close(fd[1]);
853
854 if (pid == -1) {
855 close(fd[0]);
856 statusbar(_("Could not fork"));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000857 return FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000858 }
859
860 /* Before we start reading the forked command's output, we set
861 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000862
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000863 /* Enable interpretation of the special control keys so that we get
864 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000865 enable_signals();
866
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000867 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000868 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000869 nperror("sigaction");
870 } else {
871 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000872 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000873 sig_failed = TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000874 nperror("sigaction");
875 }
876 }
877 /* Note that now oldaction is the previous SIGINT signal handler,
878 * to be restored later. */
879
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000880 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000881 if (f == NULL)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000882 nperror("fdopen");
David Lawrence Ramsey00d77982004-08-07 21:27:37 +0000883
David Lawrence Ramsey02517e02004-09-05 21:40:31 +0000884 read_file(f, "stdin");
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000885 /* If multibuffer mode is on, we could be here in view mode. If so,
886 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000887 if (!ISSET(VIEW_MODE))
888 set_modified();
889
890 if (wait(NULL) == -1)
891 nperror("wait");
892
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000893 if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000894 nperror("sigaction");
895
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000896 /* Disable interpretation of the special control keys so that we can
897 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000898 disable_signals();
899
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000900 return TRUE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000901}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000902#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000903
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000904/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000905void do_char(char ch)
906{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000907 size_t current_len = strlen(current->data);
908#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000909 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000910 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +0000911 * update_line()? */
912#endif
913
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000914 if (ch == '\0') /* Null to newline, if needed. */
915 ch = '\n';
916 else if (ch == '\n') { /* Newline to Enter, if needed. */
917 do_enter();
918 return;
919 }
920
921 assert(current != NULL && current->data != NULL);
922
923 /* When a character is inserted on the current magicline, it means
924 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000925 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000926 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000927
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000928 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000929 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000930 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000931 charmove(&current->data[current_x + 1], &current->data[current_x],
932 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000933 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000934 totsize++;
935 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000936
Chris Allegretta6df90f52002-07-19 01:08:59 +0000937#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000938 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000939 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000940 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000941#endif
942
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000943 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000944
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000945#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000946 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +0000947 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000948 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000949#endif
950
Chris Allegretta6df90f52002-07-19 01:08:59 +0000951#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000952 /* If color syntaxes are turned on, we need to call
953 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000954 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000955 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000956#endif
957
958#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000959 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000960 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000961 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000962#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000963 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000964}
965
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000966void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000967{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000968 int *v_kbinput = NULL; /* Used to hold verbatim input. */
969 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +0000970 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000971
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000972 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000973
David Lawrence Ramsey6da969e2004-08-28 15:51:07 +0000974 v_kbinput = get_verbatim_kbinput(edit, ERR, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000975
976 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
977 * off afterwards, so that if constant cursor position display is
978 * on, it will be updated properly. */
979 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000980 for (i = 0; i < v_len; i++)
981 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000982 UNSET(DISABLE_CURPOS);
983
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +0000984 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000985}
986
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000987void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000988{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000989 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000990 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +0000991 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000992 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000993}
994
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000995void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000996{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +0000997 bool do_refresh = FALSE;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000998 /* Do we have to call edit_refresh(), or can we get away with
999 * update_line()? */
1000
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001001 assert(current != NULL && current->data != NULL && current_x <=
1002 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001003
1004 placewewant = xplustabs();
1005
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001006 if (current->data[current_x] != '\0') {
1007 size_t linelen = strlen(current->data + current_x);
1008
1009 assert(current_x < strlen(current->data));
1010
1011 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001012 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001013 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001014
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001015 null_at(&current->data, linelen + current_x - 1);
1016#ifndef NANO_SMALL
1017 if (current_x < mark_beginx && mark_beginbuf == current)
1018 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001019#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001020 } else if (current != filebot && (current->next != filebot ||
1021 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001022 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001023 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001024 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001025
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001026 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001027
1028 /* If we're deleting at the end of a line, we need to call
1029 * edit_refresh(). */
1030 if (current->data[current_x] == '\0')
1031 do_refresh = TRUE;
1032
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001033 current->data = charealloc(current->data, current_x +
1034 strlen(foo->data) + 1);
1035 strcpy(current->data + current_x, foo->data);
1036#ifndef NANO_SMALL
1037 if (mark_beginbuf == current->next) {
1038 mark_beginx += current_x;
1039 mark_beginbuf = current;
1040 }
1041#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001042 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001043 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001044
1045 unlink_node(foo);
1046 delete_node(foo);
1047 renumber(current);
1048 totlines--;
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001049#ifndef DISABLE_WRAPPING
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001050 wrap_reset();
David Lawrence Ramsey00d77982004-08-07 21:27:37 +00001051#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001052 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001053 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001054
1055 totsize--;
1056 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001057
1058#ifdef ENABLE_COLOR
1059 /* If color syntaxes are turned on, we need to call
1060 * edit_refresh(). */
1061 if (ISSET(COLOR_SYNTAX))
1062 do_refresh = TRUE;
1063#endif
1064
1065 if (do_refresh)
1066 edit_refresh();
1067 else
1068 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001069}
1070
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001071void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001072{
1073 do_char('\t');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001074}
1075
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001076/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001077void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001078{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001079 filestruct *newnode = make_new_node(current);
1080 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001081
Chris Allegretta6df90f52002-07-19 01:08:59 +00001082 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001083
Chris Allegrettaff989832001-09-17 13:48:00 +00001084#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001085 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001086 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001087 /* If we are breaking the line in the indentation, the new
1088 * indentation should have only current_x characters, and
1089 * current_x should not change. */
1090 extra = indent_length(current->data);
1091 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001092 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001093 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001094 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001095#endif
1096 newnode->data = charalloc(strlen(current->data + current_x) +
1097 extra + 1);
1098 strcpy(&newnode->data[extra], current->data + current_x);
1099#ifndef NANO_SMALL
1100 if (ISSET(AUTOINDENT))
1101 strncpy(newnode->data, current->data, extra);
1102#endif
1103 null_at(&current->data, current_x);
1104#ifndef NANO_SMALL
1105 if (current == mark_beginbuf && current_x < mark_beginx) {
1106 mark_beginbuf = newnode;
1107 mark_beginx += extra - current_x;
1108 }
1109#endif
1110 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001111
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001112 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001113 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001114 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001115
1116 totsize++;
1117 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001118 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001119
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001120 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001121
1122 totlines++;
1123 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001124 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001125}
1126
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001127#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001128void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001129{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001130 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001131 const filestruct *old_current = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001132 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001133
Chris Allegretta6df90f52002-07-19 01:08:59 +00001134 /* Skip letters in this word first. */
1135 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001136 isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001137 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001138
Chris Allegretta6df90f52002-07-19 01:08:59 +00001139 for (; current != NULL; current = current->next) {
1140 while (current->data[current_x] != '\0' &&
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001141 !isalnum(current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001142 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001143
Chris Allegretta6df90f52002-07-19 01:08:59 +00001144 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001145 break;
1146
Chris Allegretta6df90f52002-07-19 01:08:59 +00001147 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001148 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001149 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001150 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001151
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001152 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001153
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001154 /* Update the screen. */
1155 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001156}
1157
Chris Allegretta6df90f52002-07-19 01:08:59 +00001158/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001159void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001160{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001161 size_t old_pww = placewewant;
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001162 const filestruct *old_current = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001163 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001164
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001165 current_x++;
1166
Chris Allegretta6df90f52002-07-19 01:08:59 +00001167 /* Skip letters in this word first. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001168 while (current_x > 0 && isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001170
Chris Allegretta6df90f52002-07-19 01:08:59 +00001171 for (; current != NULL; current = current->prev) {
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001172 while (current_x > 0 && !isalnum(current->data[current_x - 1]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001173 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001174
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001175 if (current_x > 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001177
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178 if (current->prev != NULL)
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001179 current_x = strlen(current->prev->data) + 1;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001180 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001181
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001182 current_x--;
1183
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001184 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001185 current = fileage;
1186 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001187 } else {
David Lawrence Ramseyd9fb3e62004-10-21 22:49:51 +00001188 while (current_x > 0 && isalnum(current->data[current_x - 1]))
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001189 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001190 }
1191
Chris Allegretta76e291b2001-10-14 19:05:10 +00001192 placewewant = xplustabs();
1193
David Lawrence Ramsey381d4832004-10-18 01:51:43 +00001194 /* Update the screen. */
1195 edit_redraw(old_current, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001196}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001197
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001198void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001199{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001200 TOGGLE(MARK_ISSET);
1201 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001202 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001203 mark_beginbuf = current;
1204 mark_beginx = current_x;
1205 } else {
1206 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001207 edit_refresh();
1208 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001209}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001210#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001211
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001212#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001213void wrap_reset(void)
1214{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001215 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001216}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001217#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001218
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001219#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001220/* We wrap the given line. Precondition: we assume the cursor has been
1221 * moved forward since the last typed character. Return value: whether
1222 * we wrapped. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001223bool do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001224{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001225 size_t len = strlen(inptr->data);
1226 /* Length of the line we wrap. */
1227 size_t i = 0;
1228 /* Generic loop variable. */
1229 int wrap_loc = -1;
1230 /* Index of inptr->data where we wrap. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001231 int word_back = -1;
1232#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001233 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001234 /* Indentation to prepend to the new line. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001235 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001236#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001237 const char *after_break; /* Text after the wrap point. */
1238 size_t after_break_len; /* strlen(after_break) */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001239 bool wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001240 const char *wrap_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001241 /* The next line, minus indentation. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001242 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1243 char *newline = NULL; /* The line we create. */
1244 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001245
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001246/* There are three steps. First, we decide where to wrap. Then, we
1247 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001248
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001249/* Step 1, finding where to wrap. We are going to add a new line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001250 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001251 * location of this replacement.
1252 *
1253 * Where should we break the line? We need the last "legal wrap point"
1254 * such that the last word before it ended at or before fill. If there
1255 * is no such point, we settle for the first legal wrap point.
1256 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001257 * A "legal wrap point" is a whitespace character that is not followed
1258 * by whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001259 *
1260 * If there is no legal wrap point or we found the last character of the
1261 * line, we should return without wrapping.
1262 *
1263 * Note that the initial indentation does not count as a legal wrap
1264 * point if we are going to auto-indent!
1265 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001266 * Note that the code below could be optimized, by not calling
1267 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001268
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001269#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001270 if (ISSET(AUTOINDENT))
1271 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001272#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001273 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001274 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001275 /* Record where the last word ended. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001276 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001277 word_back = i;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001278 /* If we have found a "legal wrap point" and the current word
1279 * extends too far, then we stop. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001280 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001281 break;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001282 /* We record the latest "legal wrap point". */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001283 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001284 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001285 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001286 if (i == len)
1287 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001288
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001289 /* Step 2, making the new wrap line. It will consist of indentation
1290 * + after_break + " " + wrap_line (although indentation and
1291 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001292
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001293 /* after_break is the text that will be moved to the next line. */
1294 after_break = inptr->data + wrap_loc + 1;
1295 after_break_len = len - wrap_loc - 1;
1296 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001297
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001298 /* new_line_len will later be increased by the lengths of indentation
1299 * and wrap_line. */
1300 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001301
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001302 /* We prepend the wrapped text to the next line, if the flag is set,
1303 * and there is a next line, and prepending would not make the line
1304 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001305 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001306 wrap_line = inptr->next->data;
1307 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001308
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001309 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001310 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001311 wrapping = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001312 new_line_len += (1 + wrap_line_len);
1313 }
1314 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001315
Chris Allegrettaff989832001-09-17 13:48:00 +00001316#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001317 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001318 /* Indentation comes from the next line if wrapping, else from
1319 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001320 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001321 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001322 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001323 /* The wrap_line text should not duplicate indentation.
1324 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001325 wrap_line += indent_len;
1326 else
1327 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001328 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001329#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001330
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001331 /* Now we allocate the new line and copy into it. */
1332 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001333 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001334 *newline = '\0';
1335
1336#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001337 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001338 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001339 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001340 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001341 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001342#endif
1343 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001344 new_line_len += after_break_len;
1345 /* We end the old line after wrap_loc. Note that this does not eat
1346 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001347 null_at(&inptr->data, wrap_loc + 1);
1348 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001349 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001350 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001351 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001352 * in a tab or a space, we don't add a space and decrement
1353 * totsize to account for that. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001354 if (!isblank(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001355 strcat(newline, " ");
1356 else
1357 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001358 strcat(newline, wrap_line);
1359 free(inptr->next->data);
1360 inptr->next->data = newline;
1361 } else {
1362 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001363
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001364 /* In this case, the file size changes by +1 for the new line,
1365 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001366#ifndef NANO_SMALL
1367 totsize += indent_len;
1368#endif
1369 totlines++;
1370 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001371 temp->prev = inptr;
1372 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001373 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001374 /* If temp->next is NULL, then temp is the last line of the
1375 * file, so we must set filebot. */
1376 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001377 temp->next->prev = temp;
1378 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001379 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001380 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001381
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001382 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1383 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001384
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001385 /* Later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001386 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001387
1388 /* Each line knows its line number. We recalculate these if we
1389 * inserted a new line. */
1390 if (!wrapping)
1391 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001392
Chris Allegretta6df90f52002-07-19 01:08:59 +00001393 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001395 current = current->next;
1396 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001397#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001398 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001399#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001400 wrap_loc + 1;
1401 wrap_reset();
1402 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001403 }
1404
Chris Allegretta6df90f52002-07-19 01:08:59 +00001405#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001406 /* If the mark was on this line after the wrap point, we move it
1407 * down. If it was on the next line and we wrapped, we move it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001408 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001409 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1410 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001411 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001412 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001413 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001414#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001415
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001416 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001417}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001418#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001419
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001420#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001421/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001422 * return FALSE if the user cancels. */
1423bool do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001424{
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001425 char *save_search, *save_replace;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001426 size_t current_x_save = current_x, pww_save = placewewant;
David Lawrence Ramseyd4ca9f22004-10-26 21:14:56 +00001427 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001428 /* Save where we are. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001429 bool canceled = FALSE;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001430 /* The return value. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001431 bool case_sens_set = ISSET(CASE_SENSITIVE);
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001432#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001433 bool reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001434#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001435#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001436 bool regexp_set = ISSET(USE_REGEXP);
1437#endif
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001438#ifndef NANO_SMALL
1439 bool old_mark_set = ISSET(MARK_ISSET);
1440#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001441
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001442 /* Make sure spell-check is case sensitive. */
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001443 SET(CASE_SENSITIVE);
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001444
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001445#ifndef NANO_SMALL
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001446 /* Make sure spell-check goes forward only. */
1447 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001448#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001449#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001450 /* Make sure spell-check doesn't use regular expressions. */
1451 UNSET(USE_REGEXP);
1452#endif
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001453#ifndef NANO_SMALL
1454 /* Make sure the marking highlight is off during spell-check. */
1455 UNSET(MARK_ISSET);
1456#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001457
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001458 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001459 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001460 save_search = last_search;
1461 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001462
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001463 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001464 last_search = mallocstrcpy(NULL, word);
1465 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001466
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001467 /* Start from the top of the file. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001468 edittop = fileage;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001469 current = fileage;
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001470 current_x = (size_t)-1;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001471 placewewant = 0;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001472
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001473 /* Find the first whole-word occurrence of word. */
David Lawrence Ramsey77b284a2004-10-27 02:21:01 +00001474 while (findnextstr(TRUE, TRUE, FALSE, fileage, 0, word, NULL)) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001475 if (is_whole_word(current_x, current->data, word)) {
1476 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001477
Chris Allegretta6df90f52002-07-19 01:08:59 +00001478 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001479
David Lawrence Ramsey4b7e3c32004-10-15 16:25:56 +00001480 /* Allow all instances of the word to be corrected. */
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001481 canceled = (statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001482#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001483 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001484#endif
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001485 _("Edit a replacement")) == -1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001486
Chris Allegretta6df90f52002-07-19 01:08:59 +00001487 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001488
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001489 if (!canceled && strcmp(word, answer) != 0) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001490 current_x--;
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001491 do_replace_loop(word, current, &current_x, TRUE,
1492 &canceled);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001493 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001494
1495 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001496 }
David Lawrence Ramsey53752e82004-10-18 22:19:22 +00001497 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001498
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001499 /* Restore the search/replace strings. */
1500 free(last_search);
1501 last_search = save_search;
1502 free(last_replace);
1503 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001504
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001505 /* Restore where we were. */
David Lawrence Ramsey2cc2a572004-10-18 02:06:53 +00001506 edittop = edittop_save;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001507 current = current_save;
1508 current_x = current_x_save;
David Lawrence Ramsey2eb74592004-10-21 16:25:44 +00001509 placewewant = pww_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001510
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001511 /* Restore case sensitivity setting. */
1512 if (!case_sens_set)
1513 UNSET(CASE_SENSITIVE);
1514
David Lawrence Ramsey49d5c1b2004-10-11 13:55:33 +00001515#ifndef NANO_SMALL
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001516 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001517 if (reverse_search_set)
1518 SET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001519#endif
David Lawrence Ramseyb112fe62004-10-09 17:15:46 +00001520#ifdef HAVE_REGEX_H
David Lawrence Ramseyd93ee682004-10-09 16:59:43 +00001521 /* Restore regular expression usage setting. */
1522 if (regexp_set)
1523 SET(USE_REGEXP);
1524#endif
David Lawrence Ramsey9cf7b282004-10-15 16:35:34 +00001525#ifndef NANO_SMALL
1526 /* Restore marking highlight. */
1527 if (old_mark_set)
1528 SET(MARK_ISSET);
1529#endif
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001530
David Lawrence Ramsey9bf486f2004-10-26 20:58:30 +00001531 return !canceled;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001532}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001533
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001534/* Integrated spell checking using 'spell' program. Return value: NULL
1535 * for normal termination, otherwise the error string. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001536const char *do_int_speller(const char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001537{
Chris Allegretta271e9722000-11-10 18:15:43 +00001538 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001539 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001540 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001541 pid_t pid_spell, pid_sort, pid_uniq;
1542 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001543
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001544 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001545 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1546 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001547
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001548 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001549
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001550 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001551 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001552
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001553 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001554
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001555 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001556
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001557 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001558 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1559 goto close_pipes_and_exit;
1560
1561 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1562 goto close_pipes_and_exit;
1563
Chris Allegretta271e9722000-11-10 18:15:43 +00001564 close(tempfile_fd);
1565
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001566 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001567 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1568 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001569
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001570 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001571
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001572 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001573 execlp("spell", "spell", NULL);
1574
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001575 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001576 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001577 }
1578
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001579 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001580 close(spell_fd[1]);
1581
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001582 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001583 if ((pid_sort = fork()) == 0) {
1584
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001585 /* Child continues (i.e, future spell process). Replace the
1586 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001587 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1588 goto close_pipes_and_exit;
1589
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001590 close(spell_fd[0]);
1591
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001592 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001593 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1594 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001595
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001596 close(sort_fd[1]);
1597
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001598 /* Start sort program. Use -f to remove mixed case without
1599 * having to have ANOTHER pipe for tr. If this isn't portable,
1600 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001601 execlp("sort", "sort", "-f", NULL);
1602
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001603 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001604 exit(1);
1605 }
1606
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001607 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001608 close(sort_fd[1]);
1609
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001610 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001611 if ((pid_uniq = fork()) == 0) {
1612
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001613 /* Child continues (i.e, future uniq process). Replace the
1614 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001615 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1616 goto close_pipes_and_exit;
1617
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001618 close(sort_fd[0]);
1619
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001620 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001621 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1622 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001623
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001624 close(uniq_fd[1]);
1625
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001626 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001627 execlp("uniq", "uniq", NULL);
1628
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001629 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001630 exit(1);
1631 }
1632
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001633 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001634 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001635
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001636 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001637 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1638 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001639 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001640 }
1641
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001642 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001643 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1644 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001645 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001646 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001647
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001648 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001649 read_buff_read = 0;
1650 read_buff_size = pipe_buff_size + 1;
1651 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001652
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001653 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001654 read_buff_read += bytesread;
1655 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001656 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001657 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001658
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001659 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001660
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001661 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001662 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001663
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001664 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001665 read_buff_word = read_buff_ptr = read_buff;
1666
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001667 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001668
1669 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001670 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001671 if (read_buff_word != read_buff_ptr) {
1672 if (!do_int_spell_fix(read_buff_word)) {
1673 read_buff_word = read_buff_ptr;
1674 break;
1675 }
1676 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001677 read_buff_word = read_buff_ptr + 1;
1678 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001679 read_buff_ptr++;
1680 }
1681
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001682 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001683 if (read_buff_word != read_buff_ptr)
1684 do_int_spell_fix(read_buff_word);
1685
Chris Allegretta271e9722000-11-10 18:15:43 +00001686 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001687 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001688 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001689
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001690 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001691 waitpid(pid_spell, &spell_status, 0);
1692 waitpid(pid_sort, &sort_status, 0);
1693 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001694
Chris Allegretta334a9402002-12-16 04:25:53 +00001695 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1696 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001697
Chris Allegretta334a9402002-12-16 04:25:53 +00001698 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1699 return _("Error invoking \"sort -f\"");
1700
1701 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1702 return _("Error invoking \"uniq\"");
1703
1704 /* Otherwise... */
1705 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001706
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001707 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001708
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001709 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001710 close(tempfile_fd);
1711 close(spell_fd[0]);
1712 close(spell_fd[1]);
1713 close(sort_fd[0]);
1714 close(sort_fd[1]);
1715 close(uniq_fd[0]);
1716 close(uniq_fd[1]);
1717 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001718}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001719
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001720/* External spell checking. Return value: NULL for normal termination,
1721 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001722const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001723{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001724 int alt_spell_status, lineno_cur = current->lineno;
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00001725 size_t x_cur = current_x, pww_cur = placewewant;
1726 int y_cur = current_y;
Chris Allegretta271e9722000-11-10 18:15:43 +00001727 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001728 char *ptr;
1729 static int arglen = 3;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001730 static char **spellargs = NULL;
1731 FILE *f;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001732#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001733 bool old_mark_set = ISSET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001734 int mbb_lineno_cur = 0;
1735 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001736 * the alternate spell command. The line that mark_beginbuf
1737 * points to will be freed, so we save the line number and
1738 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001739
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001740 if (old_mark_set) {
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001741 mbb_lineno_cur = mark_beginbuf->lineno;
1742 UNSET(MARK_ISSET);
1743 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001744#endif
1745
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001746 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001747
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001748 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001749 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001750 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001751
Chris Allegrettae434b452001-01-27 19:25:00 +00001752 spellargs[0] = strtok(alt_speller, " ");
1753 while ((ptr = strtok(NULL, " ")) != NULL) {
1754 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001755 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001756 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001757 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001758 spellargs[arglen - 1] = NULL;
1759 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001760 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001761
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001762 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001763 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001764 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001765 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001766
1767 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001768 exit(1);
1769 }
1770
1771 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001772 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001773 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001774
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001775 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001776 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001777
Chris Allegretta334a9402002-12-16 04:25:53 +00001778 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1779 char *altspell_error = NULL;
1780 char *invoke_error = _("Could not invoke \"%s\"");
1781 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1782
1783 altspell_error = charalloc(msglen);
1784 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1785 return altspell_error;
1786 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001787
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001788 refresh();
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001789
David Lawrence Ramsey439fbe32004-10-16 04:56:34 +00001790 /* Restore the terminal to its previous state. */
1791 terminal_init();
1792
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001793#ifndef NANO_SMALL
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001794 if (old_mark_set) {
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001795 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1796 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001797 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001798 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001799 SET(MARK_ISSET);
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001800 } else {
1801#endif
1802 /* Only reload the temp file if it isn't a marked selection. */
1803 free_filestruct(fileage);
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001804 global_init(TRUE);
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00001805
1806 /* Do what load_buffer() would do, except for making a new
1807 * buffer for the temp file if multibuffer support is
1808 * available. */
1809 open_file(tempfile_name, FALSE, &f);
1810 read_file(f, tempfile_name);
1811 current = fileage;
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001812#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001813 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001814#endif
1815
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001816 /* Go back to the old position, mark the file as modified, and make
1817 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001818 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001819 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001820 clearok(topwin, FALSE);
1821 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001822
Chris Allegretta334a9402002-12-16 04:25:53 +00001823 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001824}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001825
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001826void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001827{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001828 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001829 char *temp = safe_tempnam(0, "nano.");
1830 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001831
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001832 if (temp == NULL) {
1833 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001834 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00001835 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001836
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001837#ifndef NANO_SMALL
1838 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001839 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001840 else
1841#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001842 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001843
1844 if (i == -1) {
David Lawrence Ramsey95e39e52004-08-12 02:52:14 +00001845 statusbar(_("Error writing temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001846 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001847 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001848 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001849
Chris Allegrettae1f14522001-09-19 03:19:43 +00001850#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001851 /* Update the current open_files entry before spell-checking, in
1852 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001853 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001854#endif
1855
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001856 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1857 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001858 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001859 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001860
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001861 if (spell_msg != NULL)
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001862 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1863 strerror(errno));
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001864 else
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001865 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00001866}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001867#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001868
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001869#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001870/* The "indentation" of a line is the whitespace between the quote part
1871 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001872size_t indent_length(const char *line)
1873{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001874 size_t len = 0;
1875
1876 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001877 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001878 line++;
1879 len++;
1880 }
1881 return len;
1882}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001883#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001884
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001885#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001886/* justify_format() replaces Tab by Space and multiple spaces by 1
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00001887 * (except it maintains 2 after a non-repeated character in punct
1888 * followed by a character in brackets). Note that the terminating \0
1889 * counts as a space.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001890 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001891 * justify_format() might make line->data shorter, and change the actual
1892 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001893 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001894 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001895 * skip should be at most strlen(line->data). The character at
1896 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001897void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001898{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001899 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001900
Chris Allegretta6df90f52002-07-19 01:08:59 +00001901 /* These four asserts are assumptions about the input data. */
1902 assert(line != NULL);
1903 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001904 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001905 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001906
Chris Allegretta6df90f52002-07-19 01:08:59 +00001907 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001908 for (front = back; ; front++) {
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001909 bool remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001910 /* Do we want to remove this space? */
1911
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001912 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001913 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001914
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001915 /* These tests are safe since line->data + skip is not a
1916 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001917 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00001918 const char *bob = back - 2;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001919
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001920 remove_space = TRUE;
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00001921 for (; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001922 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramseyfd73c462004-09-11 21:28:36 +00001923 /* If this character is in punct, don't remove the
1924 * space unless this character and the character
1925 * before it are the same. */
1926 remove_space = (bob > line->data + skip &&
1927 *bob == *(bob - 1));
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001928 break;
1929 }
1930 if (strchr(brackets, *bob) == NULL)
1931 break;
1932 }
1933 }
1934
1935 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001936 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001937 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001938#ifndef NANO_SMALL
1939 if (mark_beginbuf == line && back - line->data < mark_beginx)
1940 mark_beginx--;
1941#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001942 if (*front == '\0')
1943 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001944 } else {
1945 *back = *front;
1946 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001947 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001948 if (*front == '\0')
1949 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001950 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001951
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001952 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001953 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001954
Chris Allegretta6df90f52002-07-19 01:08:59 +00001955 /* Now back is the new end of line->data. */
1956 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001957 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001958 null_at(&line->data, back - line->data);
1959#ifndef NANO_SMALL
1960 if (mark_beginbuf == line && back - line->data < mark_beginx)
1961 mark_beginx = back - line->data;
1962#endif
1963 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001964}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001965
1966/* The "quote part" of a line is the largest initial substring matching
1967 * the quote string. This function returns the length of the quote part
1968 * of the given line.
1969 *
1970 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1971 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001972size_t quote_length(const char *line)
1973{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001974#ifdef HAVE_REGEX_H
1975 regmatch_t matches;
1976 int rc = regexec(&quotereg, line, 1, &matches, 0);
1977
1978 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1979 return 0;
1980 /* matches.rm_so should be 0, since the quote string should start
1981 * with the caret ^. */
1982 return matches.rm_eo;
1983#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001984 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001985
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001986 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001987 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001988 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001989 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001990#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001991}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001992
Chris Allegretta6df90f52002-07-19 01:08:59 +00001993/* a_line and b_line are lines of text. The quotation part of a_line is
1994 * the first a_quote characters. Check that the quotation part of
1995 * b_line is the same. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00001996bool quotes_match(const char *a_line, size_t a_quote, const char
1997 *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001998{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001999 /* Here is the assumption about a_quote: */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002000 assert(a_quote == quote_length(a_line));
2001 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002002 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002003}
2004
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002005/* We assume a_line and b_line have no quote part. Then, we return
2006 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002007bool indents_match(const char *a_line, size_t a_indent, const char
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002008 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002009{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002010 assert(a_indent == indent_length(a_line));
2011 assert(b_indent == indent_length(b_line));
2012
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002013 return b_indent <= a_indent &&
2014 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002015}
2016
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002017/* Is foo the beginning of a paragraph?
2018 *
2019 * A line of text consists of a "quote part", followed by an
2020 * "indentation part", followed by text. The functions quote_length()
2021 * and indent_length() calculate these parts.
2022 *
2023 * A line is "part of a paragraph" if it has a part not in the quote
2024 * part or the indentation.
2025 *
2026 * A line is "the beginning of a paragraph" if it is part of a
2027 * paragraph and
2028 * 1) it is the top line of the file, or
2029 * 2) the line above it is not part of a paragraph, or
2030 * 3) the line above it does not have precisely the same quote
2031 * part, or
2032 * 4) the indentation of this line is not an initial substring of
2033 * the indentation of the previous line, or
2034 * 5) this line has no quote part and some indentation, and
2035 * AUTOINDENT is not set.
2036 * The reason for number 5) is that if AUTOINDENT is not set, then an
2037 * indented line is expected to start a paragraph, like in books.
2038 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2039 * turned on. */
2040bool begpar(const filestruct *const foo)
2041{
2042 size_t quote_len;
2043 size_t indent_len;
2044 size_t temp_id_len;
2045
2046 /* Case 1). */
2047 if (foo->prev == NULL)
2048 return TRUE;
2049
2050 quote_len = quote_length(foo->data);
2051 indent_len = indent_length(foo->data + quote_len);
2052
2053 /* Not part of a paragraph. */
2054 if (foo->data[quote_len + indent_len] == '\0')
2055 return FALSE;
2056
2057 /* Case 3). */
2058 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2059 return TRUE;
2060
2061 temp_id_len = indent_length(foo->prev->data + quote_len);
2062
2063 /* Case 2) or 5) or 4). */
2064 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2065 (quote_len == 0 && indent_len > 0
2066#ifndef NANO_SMALL
2067 && !ISSET(AUTOINDENT)
2068#endif
2069 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2070 foo->data + quote_len, indent_len))
2071 return TRUE;
2072
2073 return FALSE;
2074}
2075
2076/* We find the last beginning-of-paragraph line before the current
2077 * line. */
2078void do_para_begin(void)
2079{
2080 const filestruct *old_current = current;
2081 const size_t old_pww = placewewant;
2082
2083 current_x = 0;
2084 placewewant = 0;
2085
2086 if (current->prev != NULL) {
2087 do {
2088 current = current->prev;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002089 current_y--;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002090 } while (!begpar(current));
2091 }
2092
2093 edit_redraw(old_current, old_pww);
2094}
2095
2096bool inpar(const char *str)
2097{
2098 size_t quote_len = quote_length(str);
2099
2100 return str[quote_len + indent_length(str + quote_len)] != '\0';
2101}
2102
2103/* A line is the last line of a paragraph if it is in a paragraph, and
2104 * the next line isn't, or is the beginning of a paragraph. We move
2105 * down to the end of a paragraph, then one line farther. */
2106void do_para_end(void)
2107{
2108 const filestruct *const old_current = current;
2109 const size_t old_pww = placewewant;
2110
2111 current_x = 0;
2112 placewewant = 0;
2113
2114 while (current->next != NULL && !inpar(current->data))
2115 current = current->next;
2116
2117 while (current->next != NULL && inpar(current->next->data) &&
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002118 !begpar(current->next)) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002119 current = current->next;
David Lawrence Ramsey50c7f2d2004-08-27 17:02:05 +00002120 current_y++;
2121 }
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002122
2123 if (current->next != NULL)
2124 current = current->next;
2125
2126 edit_redraw(old_current, old_pww);
2127}
2128
Chris Allegretta6df90f52002-07-19 01:08:59 +00002129/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002130 * buffer, not allowing them to be concatenated. We assume there are
2131 * enough lines after first_line. We leave copies of the lines in
2132 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002133filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2134 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002135{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002136 /* We put the original lines, not copies, into the cutbuffer, just
2137 * out of a misguided sense of consistency, so if you uncut, you get
2138 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002139 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002140
2141 set_modified();
2142 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002143 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002144 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002145
Chris Allegretta908f7702003-01-15 11:18:58 +00002146 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002147 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002148 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002149 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002150 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002151 edittop = bob;
2152#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002153 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002154 mark_beginbuf = bob;
2155#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002156
Chris Allegretta908f7702003-01-15 11:18:58 +00002157 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002158 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002159 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002160 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002161 }
2162 return first_line;
2163}
2164
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002165/* Is it possible to break line at or before goal? */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002166bool breakable(const char *line, ssize_t goal)
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002167{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002168 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002169 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002170 return TRUE;
2171
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002172 if (is_cntrl_char(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002173 goal -= 2;
2174 else
2175 goal -= 1;
2176 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002177 /* If goal is not negative, the whole line (one word) was short
2178 * enough. */
2179 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002180}
2181
Chris Allegretta6df90f52002-07-19 01:08:59 +00002182/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002183 * that the display length to there is at most goal + 1. If there is no
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002184 * such space, and force is TRUE, then we find the first space. Anyway,
2185 * we then take the last space in that group of spaces. The terminating
2186 * '\0' counts as a space. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002187int break_line(const char *line, ssize_t goal, bool force)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002188{
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002189 ssize_t space_loc = -1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002190 /* Current tentative return value. Index of the last space we
2191 * found with short enough display width. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002192 ssize_t cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002193 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002194
2195 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002196 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002197 if (*line == ' ')
2198 space_loc = cur_loc;
2199 assert(*line != '\t');
2200
Chris Allegrettacf287c82002-07-20 13:57:41 +00002201 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002202 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002203 else
2204 goal--;
2205 }
2206 if (goal >= 0)
2207 /* In fact, the whole line displays shorter than goal. */
2208 return cur_loc;
2209 if (space_loc == -1) {
2210 /* No space found short enough. */
2211 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002212 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002213 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002214 return cur_loc;
2215 return -1;
2216 }
2217 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002218 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002219 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2220 *(line - cur_loc + space_loc + 1) == '\0')
2221 space_loc++;
2222 return space_loc;
2223}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002224
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002225/* Find the beginning of the current paragraph if we're in one, or the
2226 * beginning of the next paragraph if we're not. Afterwards, save the
2227 * quote length and paragraph length in *quote and *par. Return FALSE
2228 * if we found a paragraph, or TRUE if there was an error or we didn't
2229 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002230 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002231 * See the comment at begpar() for more about when a line is the
2232 * beginning of a paragraph. */
2233bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002234{
2235 size_t quote_len;
2236 /* Length of the initial quotation of the paragraph we
2237 * search. */
2238 size_t par_len;
2239 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002240 size_t indent_len;
2241 /* Generic indentation length. */
2242 filestruct *line;
2243 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002244
2245#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002246 if (quoterc != 0) {
2247 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2248 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002249 }
2250#endif
2251
2252 /* Here is an assumption that is always true anyway. */
2253 assert(current != NULL);
2254
2255 current_x = 0;
2256
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002257 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002258 indent_len = indent_length(current->data + quote_len);
2259
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002260 /* Here we find the first line of the paragraph to search. If the
2261 * current line is in a paragraph, then we move back to the first
2262 * line of the paragraph. Otherwise, we move to the first line that
2263 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002264 if (current->data[quote_len + indent_len] != '\0') {
2265 /* This line is part of a paragraph. So we must search back to
2266 * the first line of this paragraph. First we check items 1)
2267 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002268 while (current->prev != NULL && quotes_match(current->data,
2269 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002270 size_t temp_id_len =
David Lawrence Ramseybb50b302004-08-12 21:43:00 +00002271 indent_length(current->prev->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002272 /* The indentation length of the previous line. */
2273
2274 /* Is this line the beginning of a paragraph, according to
2275 * items 2), 5), or 4) above? If so, stop. */
2276 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002277 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002278#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002279 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002280#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002281 ) || !indents_match(current->prev->data + quote_len,
2282 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002283 break;
2284 indent_len = temp_id_len;
2285 current = current->prev;
2286 current_y--;
2287 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002288 } else {
2289 /* This line is not part of a paragraph. Move down until we get
2290 * to a non "blank" line. */
2291 do {
2292 /* There is no next paragraph, so nothing to move to. */
2293 if (current->next == NULL) {
2294 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002295 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002296 }
2297 current = current->next;
2298 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002299 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002300 indent_len = indent_length(current->data + quote_len);
2301 } while (current->data[quote_len + indent_len] == '\0');
2302 }
2303
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002304 /* Now current is the first line of the paragraph, and quote_len is
2305 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002306
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002307 /* Next step, compute par_len, the number of lines in this
2308 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002309 line = current;
2310 par_len = 1;
2311 indent_len = indent_length(line->data + quote_len);
2312
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002313 while (line->next != NULL &&
2314 quotes_match(current->data, quote_len, line->next->data)) {
2315 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002316
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002317 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002318 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002319 line->next->data[quote_len + temp_id_len] == '\0' ||
2320 (quote_len == 0 && temp_id_len > 0
2321#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002322 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002323#endif
2324 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002325 break;
2326 indent_len = temp_id_len;
2327 line = line->next;
2328 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002329 }
2330
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002331 /* Now par_len is the number of lines in this paragraph. We should
2332 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002333
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002334 /* Save the values of quote_len and par_len. */
2335 assert(quote != NULL && par != NULL);
2336 *quote = quote_len;
2337 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002338
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002339 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002340}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002341
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002342/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2343 * the current paragraph. */
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002344void do_justify(bool full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002345{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002346 filestruct *first_par_line = NULL;
2347 /* Will be the first line of the resulting justified paragraph.
2348 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002349 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002350 /* Will be the last line of the result, also for uncut. */
2351 filestruct *cutbuffer_save = cutbuffer;
2352 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002353 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002354 * original to restore it later. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002355 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002356 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002357 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002358 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002359
2360 /* We save these global variables to be restored if the user
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002361 * unjustifies. Note that we don't need to save totlines. */
David Lawrence Ramsey7a97e182004-10-30 01:03:15 +00002362 size_t current_x_save = current_x;
2363 int current_y_save = current_y;
David Lawrence Ramsey59f5e042004-10-29 15:48:40 +00002364 long flags_save = flags, totsize_save = totsize;
2365 filestruct *edittop_save = edittop, *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002366#ifndef NANO_SMALL
2367 filestruct *mark_beginbuf_save = mark_beginbuf;
2368 int mark_beginx_save = mark_beginx;
2369#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002370 int kbinput;
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00002371 bool meta_key, func_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002372
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002373 /* If we're justifying the entire file, start at the beginning. */
2374 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002375 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002376
2377 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002378
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002379 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002380 size_t quote_len;
2381 /* Length of the initial quotation of the paragraph we
2382 * justify. */
2383 size_t par_len;
2384 /* Number of lines in that paragraph. */
2385
2386 /* Find the first line of the paragraph to be justified. That
2387 * is the start of this paragraph if we're in one, or the start
2388 * of the next otherwise. Save the quote length and paragraph
2389 * length (number of lines). Don't refresh the screen yet
2390 * (since we'll do that after we justify). If the search failed
2391 * and we're justifying the whole file, move the last line of
2392 * the text we're justifying to just before the magicline, which
2393 * is where it'll be anyway if we've searched the entire file,
2394 * and break out of the loop; otherwise, refresh the screen and
2395 * get out. */
2396 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002397 if (full_justify) {
2398 /* This should be safe in the event of filebot->prev's
2399 * being NULL, since only last_par_line->next is used if
2400 * we eventually unjustify. */
2401 last_par_line = filebot->prev;
2402 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002403 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002404 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002405 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002406 }
2407 }
2408
2409 /* Next step, we loop through the lines of this paragraph,
2410 * justifying each one individually. */
2411 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002412 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002413 size_t line_len;
2414 size_t display_len;
2415 /* The width of current in screen columns. */
David Lawrence Ramseyd08348b2004-09-18 22:02:21 +00002416 ssize_t break_pos;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002417 /* Where we will break the line. */
2418
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002419 /* We'll be moving to the next line after justifying the
2420 * current line in almost all cases, so allow changing the
2421 * spacing at the ends of justified lines by default. */
2422 allow_respacing = TRUE;
2423
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002424 indent_len = quote_len + indent_length(current->data +
2425 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002426
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002427 /* If we haven't already done it, copy the original
2428 * paragraph to the cutbuffer for unjustification. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002429 if (first_par_line == NULL)
2430 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002431 filebot->lineno - current->lineno : par_len, quote_len);
2432
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002433 /* Now we call justify_format() on the current line of the
2434 * paragraph, which will remove excess spaces from it and
2435 * change tabs to spaces. */
2436 justify_format(current, quote_len +
2437 indent_length(current->data + quote_len));
2438
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002439 line_len = strlen(current->data);
2440 display_len = strlenpt(current->data);
2441
2442 if (display_len > fill) {
2443 /* The line is too long. Try to wrap it to the next. */
2444 break_pos = break_line(current->data + indent_len,
2445 fill - strnlenpt(current->data, indent_len), TRUE);
2446 if (break_pos == -1 || break_pos + indent_len == line_len)
2447 /* We can't break the line, or don't need to, so
2448 * just go on to the next. */
2449 goto continue_loc;
2450 break_pos += indent_len;
2451 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002452 if (par_len == 1) {
2453 /* There is no next line in this paragraph. We make
2454 * a new line and copy text after break_pos into
2455 * it. */
2456 splice_node(current, make_new_node(current), current->next);
2457 /* In a non-quoted paragraph, we copy the indent
2458 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002459 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002460#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002461 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002462#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002463 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002464 indent_len = 0;
2465 current->next->data = charalloc(indent_len + line_len -
2466 break_pos);
2467 strncpy(current->next->data, current->data, indent_len);
2468 strcpy(current->next->data + indent_len,
2469 current->data + break_pos + 1);
2470 assert(strlen(current->next->data) ==
2471 indent_len + line_len - break_pos - 1);
2472 totlines++;
2473 totsize += indent_len;
2474 par_len++;
2475 } else {
2476 size_t next_line_len = strlen(current->next->data);
2477
2478 indent_len = quote_len +
2479 indent_length(current->next->data + quote_len);
2480 current->next->data = charealloc(current->next->data,
2481 next_line_len + line_len - break_pos + 1);
2482
2483 charmove(current->next->data + indent_len + line_len -
2484 break_pos, current->next->data + indent_len,
2485 next_line_len - indent_len + 1);
2486 strcpy(current->next->data + indent_len,
2487 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002488 current->next->data[indent_len + line_len -
2489 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002490#ifndef NANO_SMALL
2491 if (mark_beginbuf == current->next) {
2492 if (mark_beginx < indent_len)
2493 mark_beginx = indent_len;
2494 mark_beginx += line_len - break_pos;
2495 }
2496#endif
2497 }
2498#ifndef NANO_SMALL
2499 if (mark_beginbuf == current && mark_beginx > break_pos) {
2500 mark_beginbuf = current->next;
2501 mark_beginx -= break_pos + 1 - indent_len;
2502 }
2503#endif
2504 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002505
2506 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002507 current = current->next;
2508 } else if (display_len < fill && par_len > 1) {
2509 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002510
2511 indent_len = quote_len +
2512 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002513 /* If we can't pull a word from the next line up to this
2514 * one, just go on. */
2515 if (!breakable(current->next->data + indent_len,
2516 fill - display_len - 1))
2517 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002518
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002519 break_pos = break_line(current->next->data + indent_len,
2520 fill - display_len - 1, FALSE);
2521 assert(break_pos != -1);
2522
2523 current->data = charealloc(current->data,
2524 line_len + break_pos + 2);
2525 current->data[line_len] = ' ';
2526 strncpy(current->data + line_len + 1,
2527 current->next->data + indent_len, break_pos);
2528 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002529#ifndef NANO_SMALL
2530 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002531 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002532 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002533 if (mark_beginx <= indent_len)
2534 mark_beginx = line_len + 1;
2535 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002536 mark_beginx = line_len + 1 + mark_beginx -
2537 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002538 } else
2539 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002540 }
2541#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002542 next_line_len = strlen(current->next->data);
2543 if (indent_len + break_pos == next_line_len) {
2544 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002545
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002546 /* Don't destroy edittop! */
2547 if (line == edittop)
2548 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002549
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002550 unlink_node(line);
2551 delete_node(line);
2552 totlines--;
2553 totsize -= indent_len;
2554 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002555
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002556 /* Don't go to the next line. Accordingly, don't
2557 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002558 * previous justified line, so that we don't end up
2559 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002560 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002561 } else {
2562 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002563 current->next->data + indent_len + break_pos + 1,
2564 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002565 null_at(&current->next->data, next_line_len - break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002566
2567 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002568 current = current->next;
2569 }
2570 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002571 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002572 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002573 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002574
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002575 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002576 * current line. If the justified line was not the last
2577 * line of the paragraph, add a space to the end of it to
2578 * replace the one removed or left out by justify_format().
2579 * If it was the last line of the paragraph, and
2580 * justify_format() left a space on the end of it, remove
2581 * the space. */
2582 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002583 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002584
2585 if (par_len > 1) {
2586 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002587 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002588 current->prev->data[prev_line_len] = ' ';
2589 current->prev->data[prev_line_len + 1] = '\0';
2590 totsize++;
2591 } else if (par_len == 1 &&
2592 current->prev->data[prev_line_len - 1] == ' ') {
2593 current->prev->data = charealloc(current->prev->data,
2594 prev_line_len);
2595 current->prev->data[prev_line_len - 1] = '\0';
2596 totsize--;
2597 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002598 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002599 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002600
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002601 /* We've just justified a paragraph. If we're not justifying the
2602 * entire file, break out of the loop. Otherwise, continue the
2603 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002604 if (!full_justify)
2605 break;
2606
2607 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002608
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002609 /* We are now done justifying the paragraph or the file, so clean
2610 * up. totlines, totsize, and current_y have been maintained above.
2611 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002612 * fileage, and renumber() since edit_refresh() needs the line
2613 * numbers to be right (but only do the last two if we actually
2614 * justified something). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002615 last_par_line = current->prev;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002616 if (first_par_line != NULL) {
2617 if (first_par_line->prev == NULL)
2618 fileage = first_par_line;
2619 renumber(first_par_line);
2620 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002621
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002622 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002623
Chris Allegretta9149e612000-11-27 00:23:41 +00002624 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002625
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002626 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002627 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002628 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002629
Chris Allegretta6df90f52002-07-19 01:08:59 +00002630 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002631 * keystroke and return. */
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00002632 kbinput = get_edit_input(&meta_key, &func_key, FALSE);
Chris Allegretta5f071802001-05-06 02:34:31 +00002633
David Lawrence Ramsey45f971d2004-09-27 01:10:48 +00002634 if (!meta_key && !func_key && kbinput == NANO_UNJUSTIFY_KEY) {
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002635 /* Restore the justify we just did (ungrateful user!). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002636 filestruct *cutbottom = get_cutbottom();
2637
Chris Allegretta6df90f52002-07-19 01:08:59 +00002638 current = current_save;
2639 current_x = current_x_save;
2640 current_y = current_y_save;
2641 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002642
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002643 /* Splice the cutbuffer back into the file, but only if we
2644 * actually justified something. */
2645 if (first_par_line != NULL) {
2646 cutbottom->next = last_par_line->next;
2647 cutbottom->next->prev = cutbottom;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002648 /* The line numbers after the end of the paragraph have been
2649 * changed, so we change them back. */
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002650 renumber(cutbottom->next);
2651 if (first_par_line->prev != NULL) {
2652 cutbuffer->prev = first_par_line->prev;
2653 cutbuffer->prev->next = cutbuffer;
2654 } else
2655 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002656
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002657 last_par_line->next = NULL;
2658 free_filestruct(first_par_line);
2659 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002660
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002661 /* Restore global variables from before the justify. */
2662 totsize = totsize_save;
2663 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002664#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002665 mark_beginbuf = mark_beginbuf_save;
2666 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002667#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002668 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002669 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002670 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671 edit_refresh();
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00002672 } else {
2673 placewewant = 0;
David Lawrence Ramseyc59979f2004-10-23 02:47:39 +00002674 unget_kbinput(kbinput, meta_key, func_key);
Chris Allegretta9149e612000-11-27 00:23:41 +00002675 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002676
Chris Allegretta6df90f52002-07-19 01:08:59 +00002677 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002678 /* Note that now cutbottom is invalid, but that's okay. */
2679 blank_statusbar();
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00002680
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002681 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002682 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002683 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002684}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002685
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002686void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002687{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002688 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002689}
2690
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002691void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002692{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002693 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002694}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002695#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002696
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002697void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002698{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002699 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002700
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002701 if (!ISSET(MODIFIED))
2702 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002703 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002704 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002705 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002706 i = do_yesno(FALSE,
2707 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2708
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002709#ifdef DEBUG
2710 dump_buffer(fileage);
2711#endif
2712
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002713 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002714#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002715 /* Exit only if there are no more open buffers. */
David Lawrence Ramsey3e189a82004-10-03 19:18:48 +00002716 if (!close_open_file())
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002717#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002718 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002719 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002720 statusbar(_("Cancelled"));
2721
2722 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002723}
2724
2725void signal_init(void)
2726{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002727 /* Trap SIGINT and SIGQUIT because we want them to do useful
2728 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002729 memset(&act, 0, sizeof(struct sigaction));
2730 act.sa_handler = SIG_IGN;
2731 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002732 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002733
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002734 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002735 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002736 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002737 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002738
2739#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002740 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002741 act.sa_handler = handle_sigwinch;
2742 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002743 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002744#endif
2745
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002746 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002747 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002748 act.sa_handler = SIG_IGN;
2749 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002750 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002751 /* Block all other signals in the suspend and continue handlers.
2752 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002753 sigfillset(&act.sa_mask);
2754
2755 act.sa_handler = do_suspend;
2756 sigaction(SIGTSTP, &act, NULL);
2757
2758 act.sa_handler = do_cont;
2759 sigaction(SIGCONT, &act, NULL);
2760 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002761}
2762
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002763/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002764RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002765{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002766 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002767}
2768
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002769/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002770RETSIGTYPE do_suspend(int signal)
2771{
2772 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002773 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002774 fflush(stdout);
2775
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002776 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002777 tcsetattr(0, TCSANOW, &oldterm);
2778
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002779 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002780 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002781 act.sa_handler = handle_hupterm;
2782 sigaction(SIGHUP, &act, NULL);
2783 sigaction(SIGTERM, &act, NULL);
2784
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002785 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002786 kill(0, SIGSTOP);
2787}
2788
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002789/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002790RETSIGTYPE do_cont(int signal)
2791{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002792#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002793 /* Perhaps the user resized the window while we slept. Handle it
2794 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002796#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002797 /* Just update the screen. */
2798 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002799#endif
2800}
2801
2802#ifndef NANO_SMALL
2803void handle_sigwinch(int s)
2804{
2805 const char *tty = ttyname(0);
2806 int fd;
2807 int result = 0;
2808 struct winsize win;
2809
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002810 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002811 return;
2812 fd = open(tty, O_RDWR);
2813 if (fd == -1)
2814 return;
2815 result = ioctl(fd, TIOCGWINSZ, &win);
2816 close(fd);
2817 if (result == -1)
2818 return;
2819
2820 /* Could check whether the COLS or LINES changed, and return
2821 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2822 * variables, and in some cases ncurses has already updated them.
2823 * But not in all cases, argh. */
2824 COLS = win.ws_col;
2825 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002826 editwinrows = LINES - 5 + no_help();
2827 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002828 die_too_small();
2829
2830#ifndef DISABLE_WRAPJUSTIFY
2831 fill = wrap_at;
2832 if (fill <= 0)
2833 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002834 if (fill < 0)
2835 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002836#endif
2837
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002838 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002839 memset(hblank, ' ', COLS);
2840 hblank[COLS] = '\0';
2841
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002842#ifdef USE_SLANG
2843 /* Slang curses emulation brain damage, part 1: If we just do what
2844 * curses does here, it'll only work properly if the resize made the
2845 * window smaller. Do what mutt does: Leave and immediately reenter
2846 * Slang screen management mode. */
2847 SLsmg_reset_smg();
2848 SLsmg_init_smg();
2849#else
2850 /* Do the equivalent of what Minimum Profit does: Leave and
2851 * immediately reenter curses mode. */
2852 endwin();
2853 refresh();
2854#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002855
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002856 /* Restore the terminal to its previous state. */
2857 terminal_init();
2858
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002859 /* Do the equivalent of what both mutt and Minimum Profit do:
2860 * Reinitialize all the windows based on the new screen
2861 * dimensions. */
2862 window_init();
2863
2864 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002865 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002866 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002867 total_refresh();
2868
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002869 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002870 curs_set(1);
2871
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002872 /* Reset all the input routines that rely on character sequences. */
2873 reset_kbinput();
2874
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002875 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002876 siglongjmp(jmpbuf, 1);
2877}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002878
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002879void allow_pending_sigwinch(bool allow)
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002880{
2881 sigset_t winch;
2882 sigemptyset(&winch);
2883 sigaddset(&winch, SIGWINCH);
2884 if (allow)
2885 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2886 else
2887 sigprocmask(SIG_BLOCK, &winch, NULL);
2888}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002889#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002890
Chris Allegrettadab017e2002-04-23 10:56:06 +00002891#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002892void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002893{
David Lawrence Ramseyce62e822004-08-05 22:10:22 +00002894 bool enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002895
Chris Allegretta658399a2001-06-14 02:54:22 +00002896 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002897 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002898
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002899 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002900 case TOGGLE_SUSPEND_KEY:
2901 signal_init();
2902 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002903#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002904 case TOGGLE_MOUSE_KEY:
2905 mouse_init();
2906 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002907#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002908 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002909 blank_statusbar();
2910 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002911 wrefresh(bottomwin);
2912 window_init();
2913 edit_refresh();
2914 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002915 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002916#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002917 case TOGGLE_SYNTAX_KEY:
2918 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002919 break;
2920#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002921#ifdef ENABLE_NANORC
2922 case TOGGLE_WHITESPACE_KEY:
2923 edit_refresh();
2924 break;
2925#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002926 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002927
Chris Allegretta6df90f52002-07-19 01:08:59 +00002928 /* We are assuming here that shortcut_init() above didn't free and
2929 * reallocate the toggles. */
2930 enabled = ISSET(which->flag);
2931 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2932 enabled = !enabled;
2933 statusbar("%s %s", which->desc,
2934 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002935}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002936#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002937
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00002938void disable_extended_input(void)
2939{
2940 struct termios term;
2941
2942 tcgetattr(0, &term);
2943 term.c_lflag &= ~IEXTEN;
2944 tcsetattr(0, TCSANOW, &term);
2945}
2946
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002947void disable_signals(void)
2948{
2949 struct termios term;
2950
2951 tcgetattr(0, &term);
2952 term.c_lflag &= ~ISIG;
2953 tcsetattr(0, TCSANOW, &term);
2954}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002955
2956#ifndef NANO_SMALL
2957void enable_signals(void)
2958{
2959 struct termios term;
2960
2961 tcgetattr(0, &term);
2962 term.c_lflag |= ISIG;
2963 tcsetattr(0, TCSANOW, &term);
2964}
2965#endif
2966
2967void disable_flow_control(void)
2968{
2969 struct termios term;
2970
2971 tcgetattr(0, &term);
2972 term.c_iflag &= ~(IXON|IXOFF);
2973 tcsetattr(0, TCSANOW, &term);
2974}
2975
2976void enable_flow_control(void)
2977{
2978 struct termios term;
2979
2980 tcgetattr(0, &term);
2981 term.c_iflag |= (IXON|IXOFF);
2982 tcsetattr(0, TCSANOW, &term);
2983}
2984
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002985/* Set up the terminal state. Put the terminal in cbreak mode (read one
2986 * character at a time and interpret the special control keys), disable
2987 * translation of carriage return (^M) into newline (^J) so that we can
2988 * tell the difference between the Enter key and Ctrl-J, and disable
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00002989 * echoing of characters as they're typed. Finally, disable extended
2990 * input processing, disable interpretation of the special control keys,
2991 * and if we're not in preserve mode, disable interpretation of the flow
2992 * control characters too. */
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002993void terminal_init(void)
2994{
2995 cbreak();
2996 nonl();
2997 noecho();
David Lawrence Ramsey013344c2004-09-22 22:45:08 +00002998 disable_extended_input();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002999 disable_signals();
3000 if (!ISSET(PRESERVE))
3001 disable_flow_control();
3002}
3003
David Lawrence Ramseya27bd652004-08-17 05:23:38 +00003004int main(int argc, char **argv)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003005{
3006 int optchr;
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003007 int startline = 0;
3008 /* Line to try and start at. */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003009#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003010 bool fill_flag_used = FALSE;
3011 /* Was the fill option used? */
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003012#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003013#ifdef ENABLE_MULTIBUFFER
3014 bool old_multibuffer;
3015 /* The old value of the multibuffer option, restored after we
3016 * load all files on the command line. */
3017#endif
3018 int kbinput;
3019 /* Input from keyboard. */
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00003020 bool meta_key, func_key;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003021#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003022 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003023 {"help", 0, 0, 'h'},
3024#ifdef ENABLE_MULTIBUFFER
3025 {"multibuffer", 0, 0, 'F'},
3026#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003027#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003028#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003029 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003030#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003031 {"ignorercfiles", 0, 0, 'I'},
3032#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003033#ifndef DISABLE_JUSTIFY
3034 {"quotestr", 1, 0, 'Q'},
3035#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003036#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003037 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003038#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003039 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003040 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003041#ifdef ENABLE_COLOR
3042 {"syntax", 1, 0, 'Y'},
3043#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003044 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003045 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003046 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003047#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003048 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003049#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003050#ifndef DISABLE_OPERATINGDIR
3051 {"operatingdir", 1, 0, 'o'},
3052#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003053 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054#ifndef DISABLE_WRAPJUSTIFY
3055 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003056#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003057#ifndef DISABLE_SPELLER
3058 {"speller", 1, 0, 's'},
3059#endif
3060 {"tempfile", 0, 0, 't'},
3061 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003062#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003063 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003064#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003065 {"nohelp", 0, 0, 'x'},
3066 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003067#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003068 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003069 {"backup", 0, 0, 'B'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003070 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003071 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003072 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003073 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003074 {"autoindent", 0, 0, 'i'},
3075 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003076#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003077 {0, 0, 0, 0}
3078 };
3079#endif
3080
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003081 setlocale(LC_ALL, "");
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003082#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003083 bindtextdomain(PACKAGE, LOCALEDIR);
3084 textdomain(PACKAGE);
3085#endif
3086
Chris Allegretta7662c862003-01-13 01:35:15 +00003087#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003088 /* If we don't have rcfile support, we're root, and
3089 * --disable-wrapping-as-root is used, turn wrapping off. */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003090 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003091 SET(NO_WRAP);
3092#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003093
Chris Allegretta6df90f52002-07-19 01:08:59 +00003094 while ((optchr =
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003095#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey28caf142004-10-07 20:54:52 +00003096 getopt_long(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz", long_options, NULL)
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003097#else
David Lawrence Ramsey28caf142004-10-07 20:54:52 +00003098 getopt(argc, argv, "h?ABE:FHINQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003099#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003100 ) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003101
3102 switch (optchr) {
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003103 case 'a':
3104 case 'b':
3105 case 'e':
3106 case 'f':
3107 case 'g':
3108 case 'j':
3109 /* Pico compatibility flags. */
3110 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003111#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003112 case 'A':
3113 SET(SMART_HOME);
3114 break;
3115 case 'B':
3116 SET(BACKUP_FILE);
3117 break;
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003118 case 'E':
3119 backup_dir = mallocstrcpy(backup_dir, optarg);
3120 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003121#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003122#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003123 case 'F':
3124 SET(MULTIBUFFER);
3125 break;
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003126#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003127#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003128#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003129 case 'H':
3130 SET(HISTORYLOG);
3131 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003132#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003133 case 'I':
3134 SET(NO_RCFILE);
3135 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003136#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003137#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003138 case 'N':
3139 SET(NO_CONVERT);
3140 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003141#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003142#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003143 case 'Q':
3144 quotestr = mallocstrcpy(quotestr, optarg);
3145 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003146#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003147#ifdef HAVE_REGEX_H
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003148 case 'R':
3149 SET(USE_REGEXP);
3150 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003151#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003152#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003153 case 'S':
3154 SET(SMOOTHSCROLL);
3155 break;
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003156#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003157 case 'T':
3158 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003159 fprintf(stderr, _("Requested tab size %s invalid"), optarg);
3160 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003161 exit(1);
3162 }
3163 break;
3164 case 'V':
3165 version();
3166 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003167#ifdef ENABLE_COLOR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003168 case 'Y':
3169 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3170 break;
Chris Allegretta09900ff2002-05-04 04:23:30 +00003171#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003172 case 'Z':
3173 SET(RESTRICTED);
3174 break;
3175 case 'c':
3176 SET(CONSTUPDATE);
3177 break;
3178 case 'd':
3179 SET(REBIND_DELETE);
3180 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003181#ifndef NANO_SMALL
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003182 case 'i':
3183 SET(AUTOINDENT);
3184 break;
3185 case 'k':
3186 SET(CUT_TO_END);
3187 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003188#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003189 case 'l':
3190 SET(NOFOLLOW_SYMLINKS);
3191 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003192#ifndef DISABLE_MOUSE
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003193 case 'm':
3194 SET(USE_MOUSE);
3195 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003196#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003197#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003198 case 'o':
3199 operating_dir = mallocstrcpy(operating_dir, optarg);
3200 break;
Chris Allegrettae1f14522001-09-19 03:19:43 +00003201#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003202 case 'p':
3203 SET(PRESERVE);
3204 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003205#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003206 case 'r':
3207 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramsey6420d442004-08-11 05:13:08 +00003208 fprintf(stderr, _("Requested fill size %s invalid"), optarg);
3209 fprintf(stderr, "\n");
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003210 exit(1);
3211 }
3212 fill_flag_used = TRUE;
3213 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003214#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003215#ifndef DISABLE_SPELLER
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003216 case 's':
3217 alt_speller = mallocstrcpy(alt_speller, optarg);
3218 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003219#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003220 case 't':
3221 SET(TEMP_FILE);
3222 break;
3223 case 'v':
3224 SET(VIEW_MODE);
3225 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003226#ifndef DISABLE_WRAPPING
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003227 case 'w':
3228 SET(NO_WRAP);
3229 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003230#endif
David Lawrence Ramseyc7b6ac52004-08-07 22:00:02 +00003231 case 'x':
3232 SET(NO_HELP);
3233 break;
3234 case 'z':
3235 SET(SUSPEND);
3236 break;
3237 default:
3238 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003239 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003240 }
3241
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003242 /* If the executable filename starts with 'r', we use restricted
3243 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003244 if (*(tail(argv[0])) == 'r')
3245 SET(RESTRICTED);
3246
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003247 /* If we're using restricted mode, disable suspending, backups, and
3248 * reading rcfiles, since they all would allow reading from or
3249 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003250 if (ISSET(RESTRICTED)) {
3251 UNSET(SUSPEND);
3252 UNSET(BACKUP_FILE);
3253 SET(NO_RCFILE);
3254 }
3255
Chris Allegretta7662c862003-01-13 01:35:15 +00003256/* We've read through the command line options. Now back up the flags
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003257 * and values that are set, and read the rcfile(s). If the values
3258 * haven't changed afterward, restore the backed-up values. */
Chris Allegretta7662c862003-01-13 01:35:15 +00003259#ifdef ENABLE_NANORC
3260 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003261#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003262 char *operating_dir_cpy = operating_dir;
3263#endif
David Lawrence Ramsey7e8dd192004-08-12 20:06:20 +00003264#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003265 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003266#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003267#ifndef NANO_SMALL
3268 char *backup_dir_cpy = backup_dir;
3269#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003270#ifndef DISABLE_JUSTIFY
3271 char *quotestr_cpy = quotestr;
3272#endif
3273#ifndef DISABLE_SPELLER
3274 char *alt_speller_cpy = alt_speller;
3275#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003276 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003277 long flags_cpy = flags;
3278
Chris Allegretta5ec68622003-02-05 02:39:34 +00003279#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003280 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003281#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003282#ifndef NANO_SMALL
3283 backup_dir = NULL;
3284#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003285#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003286 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003287#endif
3288#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003289 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003290#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003291
3292 do_rcfile();
3293
3294#ifndef DISABLE_OPERATINGDIR
3295 if (operating_dir_cpy != NULL) {
3296 free(operating_dir);
3297 operating_dir = operating_dir_cpy;
3298 }
3299#endif
David Lawrence Ramseydf13e3b2004-08-12 19:48:21 +00003300#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003301 if (fill_flag_used)
3302 wrap_at = wrap_at_cpy;
3303#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003304#ifndef NANO_SMALL
3305 if (backup_dir_cpy != NULL) {
3306 free(backup_dir);
3307 backup_dir = backup_dir_cpy;
3308 }
3309#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003310#ifndef DISABLE_JUSTIFY
3311 if (quotestr_cpy != NULL) {
3312 free(quotestr);
3313 quotestr = quotestr_cpy;
3314 }
3315#endif
3316#ifndef DISABLE_SPELLER
3317 if (alt_speller_cpy != NULL) {
3318 free(alt_speller);
3319 alt_speller = alt_speller_cpy;
3320 }
3321#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00003322 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00003323 tabsize = tabsize_cpy;
3324 flags |= flags_cpy;
3325 }
3326#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003327 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003328 SET(NO_WRAP);
3329#endif
3330#endif /* ENABLE_NANORC */
3331
Chris Allegrettad8451932003-03-11 03:50:40 +00003332#ifndef NANO_SMALL
3333 history_init();
3334#ifdef ENABLE_NANORC
3335 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3336 load_history();
3337#endif
3338#endif
3339
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003340#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003341 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003342 * in which case backups are disabled, since they would allow
3343 * reading from or writing to files not specified on the command
3344 * line). This entails making sure it exists and is a directory, so
3345 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003346 if (!ISSET(RESTRICTED))
3347 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003348#endif
3349
Chris Allegretta7662c862003-01-13 01:35:15 +00003350#ifndef DISABLE_OPERATINGDIR
3351 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003352 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003353 init_operating_dir();
3354#endif
3355
Chris Allegretta7662c862003-01-13 01:35:15 +00003356#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003357 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003358 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003359
3360 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003361 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003362
Chris Allegretta7662c862003-01-13 01:35:15 +00003363 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003364 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003365#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003366 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003367#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003368 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003369#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003370 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003371#ifdef HAVE_REGEX_H
3372 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
3373
3374 if (quoterc == 0) {
3375 /* We no longer need quotestr, just quotereg. */
3376 free(quotestr);
3377 quotestr = NULL;
3378 } else {
3379 size_t size = regerror(quoterc, &quotereg, NULL, 0);
3380
3381 quoteerr = charalloc(size);
3382 regerror(quoterc, &quotereg, quoteerr, size);
3383 }
3384#else
3385 quotelen = strlen(quotestr);
3386#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00003387#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003388
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003389#ifndef DISABLE_SPELLER
3390 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003391 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003392 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003393 * checking is disabled, since it would allow reading from or
3394 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003395 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003396 char *spellenv = getenv("SPELL");
3397 if (spellenv != NULL)
3398 alt_speller = mallocstrcpy(NULL, spellenv);
3399 }
3400#endif
3401
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003402#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003403 /* If whitespace wasn't specified, set its default value. */
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003404 if (whitespace == NULL)
3405 whitespace = mallocstrcpy(NULL, " ");
3406#endif
3407
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003408 /* If tabsize wasn't specified, set its default value. */
Chris Allegretta7662c862003-01-13 01:35:15 +00003409 if (tabsize == -1)
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003410 tabsize = WIDTH_OF_TAB;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003411
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003412 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003413 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003414
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003415 /* Curses initialization stuff: Start curses and set up the
3416 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003417 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003418 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003419
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003420 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003421 global_init(FALSE);
3422 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003423
3424 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003425 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003426
3427#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003428 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003429#endif
3430
Chris Allegretta2a42af12000-09-12 23:02:49 +00003431 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003432#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003433 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003434#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003435
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003436#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003437 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003438#endif
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003439
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00003440 /* If there's a +LINE flag here, it is the first non-option
3441 * argument, and it is followed by at least one other argument, the
3442 * filename it applies to. */
3443 if (0 < optind && optind < argc - 1 && argv[optind][0] == '+') {
3444 startline = atoi(&argv[optind][1]);
3445 optind++;
3446 }
3447
Chris Allegretta7662c862003-01-13 01:35:15 +00003448#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003449 old_multibuffer = ISSET(MULTIBUFFER);
3450 SET(MULTIBUFFER);
3451
3452 /* Read all the files after the first one on the command line into
3453 * new buffers. */
3454 {
David Lawrence Ramseybf1346f2004-10-22 20:25:56 +00003455 int i = optind + 1, iline = 0;
3456 for (; i < argc; i++) {
3457 /* If there's a +LINE flag here, it is followed by at least
3458 * one other argument, the filename it applies to. */
3459 if (i < argc - 1 && argv[i][0] == '+' && iline == 0) {
3460 iline = atoi(&argv[i][1]);
3461 } else {
3462 load_buffer(argv[i]);
3463 if (iline > 0) {
3464 do_gotoline(iline, FALSE);
3465 iline = 0;
3466 }
3467 }
3468 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003469 }
3470#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003471
David Lawrence Ramsey02517e02004-09-05 21:40:31 +00003472 /* Read the first file on the command line into either the current
3473 * buffer or a new buffer, depending on whether multibuffer mode is
3474 * enabled. */
3475 if (optind < argc)
3476 load_buffer(argv[optind]);
3477
3478 /* We didn't open any files if all the command line arguments were
3479 * invalid files like directories or if there were no command line
3480 * arguments given. In this case, we have to load a blank buffer.
3481 * Also, we unset view mode to allow editing. */
3482 if (filename == NULL) {
3483 filename = mallocstrcpy(NULL, "");
3484 new_file();
3485 UNSET(VIEW_MODE);
3486
3487 /* Add this new entry to the open_files structure if we have
3488 * multibuffer support, or to the main filestruct if we don't. */
3489 load_file();
3490 }
3491
3492#ifdef ENABLE_MULTIBUFFER
3493 if (!old_multibuffer)
3494 UNSET(MULTIBUFFER);
3495#endif
3496
3497#ifdef DEBUG
3498 fprintf(stderr, "Main: top and bottom win\n");
3499#endif
3500
3501 titlebar(NULL);
3502 display_main_list();
3503
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003504 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003505 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003506
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003507#ifndef NANO_SMALL
3508 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003509 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003510#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003511
Robert Siemborski6967eec2000-07-08 14:23:32 +00003512 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00003513
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003514 while (TRUE) {
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00003515 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003516 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003517 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003518
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003519#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003520 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003521#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003522
David Lawrence Ramseyeb16f432004-09-27 01:04:50 +00003523 kbinput = get_edit_input(&meta_key, &func_key, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003524
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003525 /* Last gasp, stuff that's not in the main lists. */
David Lawrence Ramseye6ef8b92004-09-12 22:01:38 +00003526 if (kbinput != ERR && !is_cntrl_char(kbinput)) {
David Lawrence Ramsey807657b2004-09-12 21:40:04 +00003527 /* Don't stop unhandled printable sequences, so that people
3528 * with odd character sets can type. */
David Lawrence Ramseya0b5ba22004-08-25 15:39:10 +00003529 if (ISSET(VIEW_MODE))
3530 print_view_warning();
3531 else
3532 do_char(kbinput);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003533 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003534 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003535 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003536}