blob: 28e3de868f74eae3c7bbda26d7f6caf4e4275e08 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +00005 * Copyright (C) 1999-2004 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
28#include <unistd.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/stat.h>
32#include <sys/ioctl.h>
33#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000034#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000035#include <errno.h>
36#include <ctype.h>
37#include <locale.h>
38#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000039#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000040#include "proto.h"
41#include "nano.h"
42
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000043#ifdef HAVE_TERMIOS_H
44#include <termios.h>
45#endif
46
47#ifdef HAVE_TERMIO_H
48#include <termio.h>
49#endif
50
51#ifdef HAVE_GETOPT_H
52#include <getopt.h>
53#endif
54
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000055#ifndef NANO_SMALL
56#include <setjmp.h>
57#endif
58
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +000060static ssize_t fill = 0; /* Fill - where to wrap lines,
61 basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000062#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000063#ifndef DISABLE_WRAPPING
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000064static int same_line_wrap = FALSE; /* Whether wrapped text should
65 be prepended to the next
66 line */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000067#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000068
Chris Allegretta6df90f52002-07-19 01:08:59 +000069static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000070static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000071
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000072#ifndef NANO_SMALL
David Lawrence Ramsey85529b32004-06-22 15:38:47 +000073static sigjmp_buf jmpbuf; /* Used to return to mainloop after
74 SIGWINCH */
David Lawrence Ramsey22fac782004-08-05 15:16:19 +000075static int pid; /* The PID of the newly forked process
76 * in open_pipe(). It must be global
77 * because the signal handler needs
78 * it. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000079#endif
Chris Allegretta08020882001-01-29 23:37:54 +000080
David Lawrence Ramseyda141062004-05-25 19:41:11 +000081/* What we do when we're all set to exit. */
82void finish(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000083{
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000084 if (!ISSET(NO_HELP))
85 blank_bottombars();
86 else
87 blank_statusbar();
Chris Allegretta6b58acd2001-04-12 03:01:53 +000088
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000089 wrefresh(bottomwin);
90 endwin();
91
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +000092 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000093 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094
Chris Allegrettad8451932003-03-11 03:50:40 +000095#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
96 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
97 save_history();
98#endif
99
Chris Allegretta6232d662002-05-12 19:52:15 +0000100#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000101 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +0000102#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +0000103
David Lawrence Ramseyda141062004-05-25 19:41:11 +0000104 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105}
106
107/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000108void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000109{
110 va_list ap;
111
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000112 endwin();
113 curses_ended = TRUE;
114
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000115 /* Restore the old terminal settings. */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000116 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000117
Chris Allegretta6df90f52002-07-19 01:08:59 +0000118 va_start(ap, msg);
119 vfprintf(stderr, msg, ap);
120 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000121
Chris Allegretta32da4562002-01-02 15:12:21 +0000122 /* save the currently loaded file if it's been modified */
123 if (ISSET(MODIFIED))
124 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000125
Chris Allegretta355fbe52001-07-14 19:32:47 +0000126#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000127 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000128 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000129 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000130
131 tmp = open_files;
132
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000133 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000134 open_files = open_files->prev;
135
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000136 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000137
David Lawrence Ramseya3370c42004-04-05 01:08:14 +0000138 /* if we already saved the file above (i.e, if it was the
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000139 currently loaded file), don't save it again */
140 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000141 /* make sure open_files->fileage and fileage, and
142 open_files->filebot and filebot, are in sync; they
143 might not be if lines have been cut from the top or
144 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000145 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000146 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000147 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000148 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000149 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000151 open_files = open_files->next;
152 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153 }
154#endif
155
Chris Allegretta6df90f52002-07-19 01:08:59 +0000156 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000157}
158
Chris Allegretta6df90f52002-07-19 01:08:59 +0000159void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000160{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000161 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000162 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000163
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +0000164 /* If we're using restricted mode, don't write any emergency backup
165 * files, since that would allow reading from or writing to files
166 * not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +0000167 if (ISSET(RESTRICTED))
168 return;
169
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170 /* If we can't save, we have REAL bad problems, but we might as well
171 TRY. */
172 if (die_filename[0] == '\0')
173 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000174 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000175 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000176
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000177 strcpy(buf, die_filename);
178 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000179 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000180 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000181 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000182 if (ret[0] != '\0')
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +0000183 i = write_file(ret, TRUE, FALSE, TRUE);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000184
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000185 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000186 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000187 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000188 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000189
190 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000191}
192
Chris Allegrettae61e8302001-01-14 05:18:27 +0000193/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000194 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000195void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000196{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000197 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000198}
199
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000200void print_view_warning(void)
201{
202 statusbar(_("Key illegal in VIEW mode"));
203}
204
David Lawrence Ramseyf28f50e2004-01-09 23:04:55 +0000205/* Initialize global variables -- no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000206 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000207void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000209 current_x = 0;
210 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000211
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000212 editwinrows = LINES - 5 + no_help();
213 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000214 die_too_small();
215
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000216 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000217 if (!save_cutbuffer)
218 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000219 current = NULL;
220 edittop = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000221 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000222 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000223 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000224
Chris Allegretta6fe61492001-05-21 12:56:25 +0000225#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000226 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000227 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000228 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000229 if (fill < 0)
230 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000231#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000232
Chris Allegretta88b09152001-05-17 11:35:43 +0000233 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000234 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000235 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000236}
237
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000238void window_init(void)
239{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000240 editwinrows = LINES - 5 + no_help();
241 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000242 die_too_small();
243
Chris Allegretta1a128af2003-01-26 04:15:56 +0000244 if (topwin != NULL)
245 delwin(topwin);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000246 if (edit != NULL)
247 delwin(edit);
Chris Allegretta1a128af2003-01-26 04:15:56 +0000248 if (bottomwin != NULL)
249 delwin(bottomwin);
250
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000251 /* Set up the windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252 topwin = newwin(2, COLS, 0, 0);
David Lawrence Ramseyce991bb2004-03-29 18:36:39 +0000253 edit = newwin(editwinrows, COLS, 2, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000254 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
255
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000256 /* Turn the keypad back on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257 keypad(edit, TRUE);
258 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000259}
260
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000261#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000262void mouse_init(void)
263{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000264 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000265 mousemask(BUTTON1_RELEASED, NULL);
266 mouseinterval(50);
267 } else
268 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000269}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000270#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000271
272#ifndef DISABLE_HELP
273/* This function allocates help_text, and stores the help string in it.
274 * help_text should be NULL initially. */
275void help_init(void)
276{
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000277 size_t allocsize = 1; /* Space needed for help_text. */
278 const char *htx; /* Untranslated help message. */
279 char *ptr;
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000280 const shortcut *s;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000281#ifndef NANO_SMALL
282 const toggle *t;
283#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000284
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000285 /* First, set up the initial help text for the current function. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000286 if (currshortcut == whereis_list || currshortcut == replace_list
287 || currshortcut == replace_list_2)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000288 htx = N_("Search Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000289 "Enter the words or characters you would like to search "
290 "for, then hit enter. If there is a match for the text you "
291 "entered, the screen will be updated to the location of the "
292 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000293 "The previous search string will be shown in brackets after "
294 "the Search: prompt. Hitting Enter without entering any text "
295 "will perform the previous search.\n\n The following function "
296 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000297 else if (currshortcut == goto_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000298 htx = N_("Go To Line Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000299 "Enter the line number that you wish to go to and hit "
300 "Enter. If there are fewer lines of text than the "
301 "number you entered, you will be brought to the last line "
302 "of the file.\n\n The following function keys are "
303 "available in Go To Line mode:\n\n");
304 else if (currshortcut == insertfile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000305 htx = N_("Insert File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000306 "Type in the name of a file to be inserted into the current "
307 "file buffer at the current cursor location.\n\n "
308 "If you have compiled nano with multiple file buffer "
309 "support, and enable multiple buffers with the -F "
310 "or --multibuffer command line flags, the Meta-F toggle, or "
311 "a nanorc file, inserting a file will cause it to be "
312 "loaded into a separate buffer (use Meta-< and > to switch "
313 "between file buffers).\n\n If you need another blank "
314 "buffer, do not enter any filename, or type in a "
315 "nonexistent filename at the prompt and press "
316 "Enter.\n\n The following function keys are "
317 "available in Insert File mode:\n\n");
318 else if (currshortcut == writefile_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000319 htx = N_("Write File Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000320 "Type the name that you wish to save the current file "
321 "as and hit Enter to save the file.\n\n If you have "
322 "selected text with Ctrl-^, you will be prompted to "
323 "save only the selected portion to a separate file. To "
324 "reduce the chance of overwriting the current file with "
325 "just a portion of it, the current filename is not the "
326 "default in this mode.\n\n The following function keys "
327 "are available in Write File mode:\n\n");
328#ifndef DISABLE_BROWSER
329 else if (currshortcut == browser_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000330 htx = N_("File Browser Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000331 "The file browser is used to visually browse the "
332 "directory structure to select a file for reading "
333 "or writing. You may use the arrow keys or Page Up/"
334 "Down to browse through the files, and S or Enter to "
335 "choose the selected file or enter the selected "
336 "directory. To move up one level, select the directory "
337 "called \"..\" at the top of the file list.\n\n The "
338 "following function keys are available in the file "
339 "browser:\n\n");
340 else if (currshortcut == gotodir_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000341 htx = N_("Browser Go To Directory Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000342 "Enter the name of the directory you would like to "
343 "browse to.\n\n If tab completion has not been disabled, "
344 "you can use the TAB key to (attempt to) automatically "
345 "complete the directory name.\n\n The following function "
346 "keys are available in Browser Go To Directory mode:\n\n");
347#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000348#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000349 else if (currshortcut == spell_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000350 htx = N_("Spell Check Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000351 "The spell checker checks the spelling of all text "
352 "in the current file. When an unknown word is "
353 "encountered, it is highlighted and a replacement can "
354 "be edited. It will then prompt to replace every "
355 "instance of the given misspelled word in the "
356 "current file.\n\n The following other functions are "
357 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000358#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000359#ifndef NANO_SMALL
360 else if (currshortcut == extcmd_list)
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000361 htx = N_("External Command Help Text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000362 "This menu allows you to insert the output of a command "
363 "run by the shell into the current buffer (or a new "
364 "buffer in multibuffer mode).\n\n The following keys are "
365 "available in this mode:\n\n");
366#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000367 else
368 /* Default to the main help list. */
369 htx = N_(" nano help text\n\n "
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000370 "The nano editor is designed to emulate the functionality and "
371 "ease-of-use of the UW Pico text editor. There are four main "
372 "sections of the editor: The top line shows the program "
373 "version, the current filename being edited, and whether "
374 "or not the file has been modified. Next is the main editor "
375 "window showing the file being edited. The status line is "
376 "the third line from the bottom and shows important messages. "
377 "The bottom two lines show the most commonly used shortcuts "
378 "in the editor.\n\n "
379 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000380 "sequences are notated with a caret (^) symbol and can be "
381 "entered either by using the Control (Ctrl) key or pressing the "
382 "Esc key twice. Escape-key sequences are notated with the Meta "
383 "(M) symbol and can be entered using either the Esc, Alt or "
384 "Meta key depending on your keyboard setup. Also, pressing Esc "
385 "twice and then typing a three-digit number from 000 to 255 "
386 "will enter the character with the corresponding ASCII code. "
387 "The following keystrokes are available in the main editor "
388 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000389
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000390 htx = _(htx);
391
392 allocsize += strlen(htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000393
394 /* The space needed for the shortcut lists, at most COLS characters,
395 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000396 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000397
398#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000399 /* If we're on the main list, we also count the toggle help text.
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000400 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
401 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000402 if (currshortcut == main_list) {
403 size_t endislen = strlen(_("enable/disable"));
404
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000405 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000406 allocsize += 8 + strlen(t->desc) + endislen;
407 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000408#endif /* !NANO_SMALL */
409
410 /* help_text has been freed and set to NULL unless the user resized
411 * while in the help screen. */
412 free(help_text);
413
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000414 /* Allocate space for the help text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000415 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000416
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000417 /* Now add the text we want. */
418 strcpy(help_text, htx);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000419 ptr = help_text + strlen(help_text);
420
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000421 /* Now add our shortcut info. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000422 for (s = currshortcut; s != NULL; s = s->next) {
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000423 int meta_shortcut = FALSE;
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000424 /* TRUE if the character in s->metaval is shown in the
425 * first column. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000426
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000427 if (s->ctrlval != NANO_NO_KEY) {
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 Ramseyf4276942003-12-24 03:33:09 +0000430 ptr += sprintf(ptr, "%.2s", _("Up"));
431 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 Ramseyf4276942003-12-24 03:33:09 +0000434 ptr += sprintf(ptr, "^%.5s", _("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 Ramseya593f532003-11-28 19:47:42 +0000439 }
440#ifndef NANO_SMALL
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000441 else if (s->metaval != NANO_NO_KEY) {
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000442 meta_shortcut = TRUE;
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000443 if (s->metaval == NANO_ALT_SPACE)
David Lawrence Ramseyf4276942003-12-24 03:33:09 +0000444 ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
445 else
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000446 ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000447 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000448#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000449
450 *(ptr++) = '\t';
451
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000452 if (s->funcval != NANO_NO_KEY)
453 ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000454
455 *(ptr++) = '\t';
456
David Lawrence Ramsey82138502003-12-24 08:03:54 +0000457 if (!meta_shortcut && s->metaval != NANO_NO_KEY)
458 ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000459 else if (meta_shortcut && s->miscval != NANO_NO_KEY)
460 ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000461
462 *(ptr++) = '\t';
463
464 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000465 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000466 }
467
468#ifndef NANO_SMALL
469 /* And the toggles... */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000470 if (currshortcut == main_list) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000471 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000472 assert(t->desc != NULL);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000473 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val), t->desc,
Chris Allegretta3a784062003-02-10 02:32:58 +0000474 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000475 }
David Lawrence Ramsey1576d532004-03-19 21:46:34 +0000476 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000477#endif /* !NANO_SMALL */
478
479 /* If all went well, we didn't overwrite the allocated space for
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000480 * help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000481 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000482}
483#endif
484
485/* Create a new filestruct node. Note that we specifically do not set
486 * prevnode->next equal to the new line. */
487filestruct *make_new_node(filestruct *prevnode)
488{
489 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
490
491 newnode->data = NULL;
492 newnode->prev = prevnode;
493 newnode->next = NULL;
494 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
495
496 return newnode;
497}
498
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000499/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000500filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000501{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000502 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000503
Chris Allegretta6df90f52002-07-19 01:08:59 +0000504 assert(src != NULL);
505
Chris Allegretta88b09152001-05-17 11:35:43 +0000506 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000507 dst->next = src->next;
508 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000509 strcpy(dst->data, src->data);
510 dst->lineno = src->lineno;
511
512 return dst;
513}
514
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000515/* Splice a node into an existing filestruct. */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000516void splice_node(filestruct *begin, filestruct *newnode, filestruct
517 *end)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000518{
519 if (newnode != NULL) {
520 newnode->next = end;
521 newnode->prev = begin;
522 }
523 if (begin != NULL)
524 begin->next = newnode;
525 if (end != NULL)
526 end->prev = newnode;
527}
528
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000529/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000531{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000532 assert(fileptr != NULL);
533
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000534 if (fileptr->prev != NULL)
535 fileptr->prev->next = fileptr->next;
536
537 if (fileptr->next != NULL)
538 fileptr->next->prev = fileptr->prev;
539}
540
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000541/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000542void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000544 if (fileptr != NULL) {
545 if (fileptr->data != NULL)
546 free(fileptr->data);
547 free(fileptr);
548 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000549}
550
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000551/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000552filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000553{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000554 filestruct *head; /* copy of src, top of the copied list */
555 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000556
Chris Allegretta6df90f52002-07-19 01:08:59 +0000557 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000558
Chris Allegretta6df90f52002-07-19 01:08:59 +0000559 prev = copy_node(src);
560 prev->prev = NULL;
561 head = prev;
562 src = src->next;
563 while (src != NULL) {
564 prev->next = copy_node(src);
565 prev->next->prev = prev;
566 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000567
Chris Allegretta6df90f52002-07-19 01:08:59 +0000568 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000569 }
570
Chris Allegretta6df90f52002-07-19 01:08:59 +0000571 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000572 return head;
573}
574
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000575/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000576void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578 if (src != NULL) {
579 while (src->next != NULL) {
580 src = src->next;
581 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000582#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000583 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000584#endif
585 }
586 delete_node(src);
587#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000588 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000589#endif
590 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000591}
592
Chris Allegretta6df90f52002-07-19 01:08:59 +0000593void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594{
595 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000596 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000597
Chris Allegretta6df90f52002-07-19 01:08:59 +0000598 assert(fileage == NULL || fileage != fileage->next);
599 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000600 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000601}
602
Chris Allegretta6df90f52002-07-19 01:08:59 +0000603void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000604{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000605 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000606 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000607 else {
608 int lineno = fileptr->prev->lineno;
609
610 assert(fileptr != fileptr->next);
611 for (; fileptr != NULL; fileptr = fileptr->next)
612 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000613 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000614}
615
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000616/* Print one usage string to the screen. This cuts down on duplicate
617 * strings to translate and leaves out the parts that shouldn't be
Chris Allegretta6df90f52002-07-19 01:08:59 +0000618 * translatable (the flag names). */
David Lawrence Ramseyf7080372004-07-08 17:15:10 +0000619void print1opt(const char *shortflag, const char *longflag, const char
620 *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000621{
622 printf(" %s\t", shortflag);
623 if (strlen(shortflag) < 8)
624 printf("\t");
625
626#ifdef HAVE_GETOPT_LONG
627 printf("%s\t", longflag);
628 if (strlen(longflag) < 8)
629 printf("\t\t");
630 else if (strlen(longflag) < 16)
631 printf("\t");
632#endif
633
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000634 printf("%s\n", _(desc));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000635}
636
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000637void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000638{
639#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000640 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
641 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000642#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000643 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
644 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000645#endif /* HAVE_GETOPT_LONG */
646
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000647 print1opt("-h, -?", "--help", N_("Show this message"));
648 print1opt(_("+LINE"), "", N_("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000649#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000650 print1opt("-A", "--smarthome", N_("Enable smart home key"));
651 print1opt("-B", "--backup", N_("Backup existing files on save"));
652 print1opt("-D", "--dos", N_("Write file in DOS format"));
653 print1opt(_("-E [dir]"), _("--backupdir=[dir]"), N_("Directory for writing backup files"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000654#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000655#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000656 print1opt("-F", "--multibuffer", N_("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000657#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000658#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000659#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000660 print1opt("-H", "--historylog", N_("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000661#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000662 print1opt("-I", "--ignorercfiles", N_("Don't look at nanorc files"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000663#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000664#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000665 print1opt("-M", "--mac", N_("Write file in Mac format"));
666 print1opt("-N", "--noconvert", N_("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000667#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000668#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000669 print1opt(_("-Q [str]"), _("--quotestr=[str]"), N_("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000670#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000671#ifdef HAVE_REGEX_H
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000672 print1opt("-R", "--regexp", N_("Do regular expression searches"));
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000673#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000674#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000675 print1opt("-S", "--smooth", N_("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000676#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000677 print1opt(_("-T [#cols]"), _("--tabsize=[#cols]"), N_("Set width of a tab in cols to #cols"));
678 print1opt("-V", "--version", N_("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000679#ifdef ENABLE_COLOR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000680 print1opt(_("-Y [str]"), _("--syntax [str]"), N_("Syntax definition to use"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000681#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000682 print1opt("-Z", "--restricted", N_("Restricted mode"));
683 print1opt("-c", "--const", N_("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000684#ifndef NANO_SMALL
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000685 print1opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem"));
686 print1opt("-i", "--autoindent", N_("Automatically indent new lines"));
687 print1opt("-k", "--cut", N_("Cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000688#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000689 print1opt("-l", "--nofollow", N_("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000690#ifndef DISABLE_MOUSE
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000691 print1opt("-m", "--mouse", N_("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000692#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000693#ifndef DISABLE_OPERATINGDIR
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000694 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), N_("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000695#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000696 print1opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000697#ifndef DISABLE_WRAPJUSTIFY
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000698 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), N_("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000699#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000700#ifndef DISABLE_SPELLER
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000701 print1opt(_("-s [prog]"), _("--speller=[prog]"), N_("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000702#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000703 print1opt("-t", "--tempfile", N_("Auto save on exit, don't prompt"));
704 print1opt("-v", "--view", N_("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000705#ifndef DISABLE_WRAPPING
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000706 print1opt("-w", "--nowrap", N_("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000707#endif
David Lawrence Ramsey76f63ff2004-08-05 15:45:09 +0000708 print1opt("-x", "--nohelp", N_("Don't show help window"));
709 print1opt("-z", "--suspend", N_("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000710
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000711 /* This is a special case. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000712 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000713
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000714 exit(0);
715}
716
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000717void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000718{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000719 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000720 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000721 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000722 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000723 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000724
Chris Allegrettae6600372003-01-17 03:39:41 +0000725#ifndef ENABLE_NLS
726 printf(" --disable-nls");
727#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000728#ifdef DEBUG
729 printf(" --enable-debug");
730#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000731#ifdef NANO_EXTRA
732 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000733#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000734#ifdef NANO_SMALL
735 printf(" --enable-tiny");
736#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000737#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000738 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000739#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000740#ifdef DISABLE_HELP
741 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000742#endif
743#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000744 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000745#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000746#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000747 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000748#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000749#ifdef DISABLE_OPERATINGDIR
750 printf(" --disable-operatingdir");
751#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000752#ifdef DISABLE_SPELLER
753 printf(" --disable-speller");
754#endif
755#ifdef DISABLE_TABCOMP
756 printf(" --disable-tabcomp");
757#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000758#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000759#ifdef DISABLE_WRAPPING
760 printf(" --disable-wrapping");
761#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000762#ifdef DISABLE_ROOTWRAP
763 printf(" --disable-wrapping-as-root");
764#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000765#ifdef ENABLE_COLOR
766 printf(" --enable-color");
767#endif
768#ifdef ENABLE_MULTIBUFFER
769 printf(" --enable-multibuffer");
770#endif
771#ifdef ENABLE_NANORC
772 printf(" --enable-nanorc");
773#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000774#ifdef USE_SLANG
775 printf(" --with-slang");
776#endif
777 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000778}
779
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000780int no_help(void)
781{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000782 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000783}
784
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000785void nano_disabled_msg(void)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000786{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000787 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000788}
789
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000790#ifndef NANO_SMALL
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000791RETSIGTYPE cancel_fork(int signal)
792{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000793 if (kill(pid, SIGKILL) == -1)
794 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000795}
796
797int open_pipe(const char *command)
798{
799 int fd[2];
800 FILE *f;
801 struct sigaction oldaction, newaction;
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000802 /* Original and temporary handlers for
803 * SIGINT. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000804 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000805 /* cancel_sigs == 1 means that sigaction() failed without changing
806 * the signal handlers. cancel_sigs == 2 means the signal handler
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000807 * was changed, but the tcsetattr() didn't succeed.
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000808 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000809 * I use this variable since it is important to put things back when
810 * we finish, even if we get errors. */
811
812 /* Make our pipes. */
813
814 if (pipe(fd) == -1) {
815 statusbar(_("Could not pipe"));
816 return 1;
817 }
818
819 /* Fork a child. */
820
821 if ((pid = fork()) == 0) {
822 close(fd[0]);
823 dup2(fd[1], fileno(stdout));
824 dup2(fd[1], fileno(stderr));
825 /* If execl() returns at all, there was an error. */
826
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000827 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000828 exit(0);
829 }
830
831 /* Else continue as parent. */
832
833 close(fd[1]);
834
835 if (pid == -1) {
836 close(fd[0]);
837 statusbar(_("Could not fork"));
838 return 1;
839 }
840
841 /* Before we start reading the forked command's output, we set
842 * things up so that ^C will cancel the new process. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000843
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000844 /* Enable interpretation of the special control keys so that we get
845 * SIGINT when Ctrl-C is pressed. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000846 enable_signals();
847
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000848 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000849 cancel_sigs = 1;
850 nperror("sigaction");
851 } else {
852 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000853 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000854 cancel_sigs = 1;
855 nperror("sigaction");
856 }
857 }
858 /* Note that now oldaction is the previous SIGINT signal handler,
859 * to be restored later. */
860
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000861 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000862 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000863 nperror("fdopen");
864
865 read_file(f, "stdin", 0);
David Lawrence Ramsey22fac782004-08-05 15:16:19 +0000866 /* If multibuffer mode is on, we could be here in view mode. If so,
867 * don't set the modification flag. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000868 if (!ISSET(VIEW_MODE))
869 set_modified();
870
871 if (wait(NULL) == -1)
872 nperror("wait");
873
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000874 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000875 nperror("sigaction");
876
David Lawrence Ramseye608f942004-05-19 16:04:27 +0000877 /* Disable interpretation of the special control keys so that we can
878 * use Ctrl-C for other things. */
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +0000879 disable_signals();
880
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000881 return 0;
882}
David Lawrence Ramseya9cd41c2004-03-05 19:54:58 +0000883#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000884
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000885#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000886void do_mouse(void)
887{
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000888 int mouse_x, mouse_y;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000889
David Lawrence Ramsey4d44d2d2004-08-01 22:35:31 +0000890 if (!get_mouseinput(&mouse_x, &mouse_y, TRUE)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000891 /* Click in the edit window to move the cursor, but only when
892 we're not in a subfunction. */
893 if (wenclose(edit, mouse_y, mouse_x) && currshortcut == main_list) {
894 int sameline;
895 /* Did they click on the line with the cursor? If they
896 clicked on the cursor, we set the mark. */
897 size_t xcur;
898 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000899
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000900 /* Subtract out size of topwin. Perhaps we need a constant
901 somewhere? */
902 mouse_y -= 2;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000903
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000904 sameline = (mouse_y == current_y);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000905
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000906 /* Move to where the click occurred. */
907 for (; current_y < mouse_y && current->next != NULL; current_y++)
908 current = current->next;
909 for (; current_y > mouse_y && current->prev != NULL; current_y--)
910 current = current->prev;
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000911
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000912 xcur = actual_x(current->data, get_page_start(xplustabs()) +
913 mouse_x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000914
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +0000915 /* Selecting where the cursor is toggles the mark, as does
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000916 selecting beyond the line length with the cursor at the
917 end of the line. */
918 if (sameline && xcur == current_x) {
919 if (ISSET(VIEW_MODE)) {
920 print_view_warning();
921 return;
922 }
923 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000924 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000925
926 current_x = xcur;
927 placewewant = xplustabs();
928 edit_refresh();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000929 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000930 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000931 /* FIXME: If we clicked on a location in the statusbar, the cursor
932 should move to the location we clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000933}
934#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000935
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000936/* The user typed a character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000937void do_char(char ch)
938{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000939 size_t current_len = strlen(current->data);
940#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000941 int do_refresh = FALSE;
942 /* Do we have to call edit_refresh(), or can we get away with
Chris Allegretta6df90f52002-07-19 01:08:59 +0000943 * update_line()? */
944#endif
945
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000946 if (ch == '\0') /* Null to newline, if needed. */
947 ch = '\n';
948 else if (ch == '\n') { /* Newline to Enter, if needed. */
949 do_enter();
950 return;
951 }
952
953 assert(current != NULL && current->data != NULL);
954
955 /* When a character is inserted on the current magicline, it means
956 * we need a new one! */
David Lawrence Ramseyb9775152004-03-19 02:15:42 +0000957 if (filebot == current)
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000958 new_magicline();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000959
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000960 /* More dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000961 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000962 assert(current_x <= current_len);
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000963 charmove(&current->data[current_x + 1], &current->data[current_x],
964 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000965 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000966 totsize++;
967 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000968
Chris Allegretta6df90f52002-07-19 01:08:59 +0000969#ifndef NANO_SMALL
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000970 /* Note that current_x has not yet been incremented. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000971 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000972 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000973#endif
974
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000975 do_right(FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000977#ifndef DISABLE_WRAPPING
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000978 /* If we're wrapping text, we need to call edit_refresh(). */
Chris Allegrettadffa2072002-07-24 01:02:26 +0000979 if (!ISSET(NO_WRAP) && ch != '\t')
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000980 do_refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000981#endif
982
Chris Allegretta6df90f52002-07-19 01:08:59 +0000983#ifdef ENABLE_COLOR
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000984 /* If color syntaxes are turned on, we need to call
985 * edit_refresh(). */
David Lawrence Ramsey760a2dc2004-01-14 06:38:00 +0000986 if (ISSET(COLOR_SYNTAX))
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000987 do_refresh = TRUE;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000988#endif
989
990#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000991 if (do_refresh)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000992 edit_refresh();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000993 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000994#endif
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +0000995 update_line(current, current_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000996}
997
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +0000998void do_verbatim_input(void)
David Lawrence Ramseya593f532003-11-28 19:47:42 +0000999{
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001000 int *v_kbinput = NULL; /* Used to hold verbatim input. */
1001 size_t v_len; /* Length of verbatim input. */
David Lawrence Ramsey805547f2004-04-22 03:41:04 +00001002 size_t i;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001003
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001004 statusbar(_("Verbatim input"));
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001005
1006 v_kbinput = get_verbatim_kbinput(edit, v_kbinput, &v_len, TRUE);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001007
1008 /* Turn on DISABLE_CURPOS while inserting character(s) and turn it
1009 * off afterwards, so that if constant cursor position display is
1010 * on, it will be updated properly. */
1011 SET(DISABLE_CURPOS);
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001012 for (i = 0; i < v_len; i++)
1013 do_char((char)v_kbinput[i]);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001014 UNSET(DISABLE_CURPOS);
1015
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00001016 free(v_kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00001017}
1018
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001019void do_backspace(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001020{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001021 if (current != fileage || current_x > 0) {
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001022 do_left(FALSE);
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001023 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001024 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001025}
1026
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001027void do_delete(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001028{
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001029 int do_refresh = FALSE;
1030 /* Do we have to call edit_refresh(), or can we get away with
1031 * update_line()? */
1032
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001033 assert(current != NULL && current->data != NULL && current_x <=
1034 strlen(current->data));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001035
1036 placewewant = xplustabs();
1037
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001038 if (current->data[current_x] != '\0') {
1039 size_t linelen = strlen(current->data + current_x);
1040
1041 assert(current_x < strlen(current->data));
1042
1043 /* Let's get dangerous. */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001044 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001045 linelen);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001046
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001047 null_at(&current->data, linelen + current_x - 1);
1048#ifndef NANO_SMALL
1049 if (current_x < mark_beginx && mark_beginbuf == current)
1050 mark_beginx--;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001051#endif
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001052 } else if (current != filebot && (current->next != filebot ||
1053 current->data[0] == '\0')) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001054 /* We can delete the line before filebot only if it is blank: it
David Lawrence Ramsey32d19ce2004-05-24 05:05:07 +00001055 * becomes the new magicline then. */
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001056 filestruct *foo = current->next;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001057
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001058 assert(current_x == strlen(current->data));
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001059
1060 /* If we're deleting at the end of a line, we need to call
1061 * edit_refresh(). */
1062 if (current->data[current_x] == '\0')
1063 do_refresh = TRUE;
1064
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001065 current->data = charealloc(current->data, current_x +
1066 strlen(foo->data) + 1);
1067 strcpy(current->data + current_x, foo->data);
1068#ifndef NANO_SMALL
1069 if (mark_beginbuf == current->next) {
1070 mark_beginx += current_x;
1071 mark_beginbuf = current;
1072 }
1073#endif
David Lawrence Ramseyb9775152004-03-19 02:15:42 +00001074 if (filebot == foo)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001075 filebot = current;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001076
1077 unlink_node(foo);
1078 delete_node(foo);
1079 renumber(current);
1080 totlines--;
David Lawrence Ramsey604caf32004-04-19 02:44:13 +00001081 wrap_reset();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001082 } else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001083 return;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001084
1085 totsize--;
1086 set_modified();
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001087
1088#ifdef ENABLE_COLOR
1089 /* If color syntaxes are turned on, we need to call
1090 * edit_refresh(). */
1091 if (ISSET(COLOR_SYNTAX))
1092 do_refresh = TRUE;
1093#endif
1094
1095 if (do_refresh)
1096 edit_refresh();
1097 else
1098 update_line(current, current_x);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001099}
1100
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001101void do_tab(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001102{
1103 do_char('\t');
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001104}
1105
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001106/* Someone hits return *gasp!* */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001107void do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001108{
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001109 filestruct *newnode = make_new_node(current);
1110 size_t extra = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001111
Chris Allegretta6df90f52002-07-19 01:08:59 +00001112 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001113
Chris Allegrettaff989832001-09-17 13:48:00 +00001114#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001115 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001116 if (ISSET(AUTOINDENT)) {
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001117 /* If we are breaking the line in the indentation, the new
1118 * indentation should have only current_x characters, and
1119 * current_x should not change. */
1120 extra = indent_length(current->data);
1121 if (extra > current_x)
Chris Allegrettadab017e2002-04-23 10:56:06 +00001122 extra = current_x;
Chris Allegrettadab017e2002-04-23 10:56:06 +00001123 totsize += extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001124 }
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001125#endif
1126 newnode->data = charalloc(strlen(current->data + current_x) +
1127 extra + 1);
1128 strcpy(&newnode->data[extra], current->data + current_x);
1129#ifndef NANO_SMALL
1130 if (ISSET(AUTOINDENT))
1131 strncpy(newnode->data, current->data, extra);
1132#endif
1133 null_at(&current->data, current_x);
1134#ifndef NANO_SMALL
1135 if (current == mark_beginbuf && current_x < mark_beginx) {
1136 mark_beginbuf = newnode;
1137 mark_beginx += extra - current_x;
1138 }
1139#endif
1140 current_x = extra;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001141
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001142 if (current == filebot)
Chris Allegrettae3167732001-03-18 16:59:34 +00001143 filebot = newnode;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001144 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001145
1146 totsize++;
1147 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001148 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001149
David Lawrence Ramsey228148b2004-05-27 20:09:52 +00001150 edit_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001151
1152 totlines++;
1153 set_modified();
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001154 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001155}
1156
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001157#ifndef NANO_SMALL
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001158void do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001159{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001160 size_t old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001161 const filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001162 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001163
Chris Allegretta6df90f52002-07-19 01:08:59 +00001164 /* Skip letters in this word first. */
1165 while (current->data[current_x] != '\0' &&
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001166 isalnum((int)current->data[current_x]))
Chris Allegretta6df90f52002-07-19 01:08:59 +00001167 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 for (; current != NULL; current = current->next) {
1170 while (current->data[current_x] != '\0' &&
1171 !isalnum((int)current->data[current_x]))
1172 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173
Chris Allegretta6df90f52002-07-19 01:08:59 +00001174 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175 break;
1176
Chris Allegretta6df90f52002-07-19 01:08:59 +00001177 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001179 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001181
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001183
David Lawrence Ramseybf3c93e2004-03-13 19:42:58 +00001184 /* Refresh the screen. If current has run off the bottom, this
1185 * call puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001186 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001187}
1188
Chris Allegretta6df90f52002-07-19 01:08:59 +00001189/* The same thing for backwards. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001190void do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001191{
David Lawrence Ramsey86e851b2004-07-28 20:46:25 +00001192 size_t old_pww = placewewant;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001193 const filestruct *current_save = current;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001194 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001195
Chris Allegretta6df90f52002-07-19 01:08:59 +00001196 /* Skip letters in this word first. */
1197 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1198 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001199
Chris Allegretta6df90f52002-07-19 01:08:59 +00001200 for (; current != NULL; current = current->prev) {
1201 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1202 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001203
Chris Allegretta6df90f52002-07-19 01:08:59 +00001204 if (current_x >= 0)
1205 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001206
Chris Allegretta6df90f52002-07-19 01:08:59 +00001207 if (current->prev != NULL)
1208 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001209 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001210
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001211 if (current == NULL) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001212 current = fileage;
1213 current_x = 0;
David Lawrence Ramsey1b525e92004-05-24 02:35:02 +00001214 } else {
1215 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1216 current_x--;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001217 }
1218
Chris Allegretta76e291b2001-10-14 19:05:10 +00001219 placewewant = xplustabs();
1220
David Lawrence Ramseyb6aa4282004-03-14 01:42:17 +00001221 /* Refresh the screen. If current has run off the top, this call
1222 * puts it at the center line. */
David Lawrence Ramseyc21790d2004-05-30 03:19:52 +00001223 edit_redraw(current_save, old_pww);
Chris Allegretta6232d662002-05-12 19:52:15 +00001224}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001225
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001226void do_mark(void)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001227{
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001228 TOGGLE(MARK_ISSET);
1229 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001230 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001231 mark_beginbuf = current;
1232 mark_beginx = current_x;
1233 } else {
1234 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001235 edit_refresh();
1236 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001237}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001238#endif /* !NANO_SMALL */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001239
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001240#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001241void wrap_reset(void)
1242{
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001243 same_line_wrap = FALSE;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001244}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001245#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001246
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001247#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001248/* We wrap the given line. Precondition: we assume the cursor has been
1249 * moved forward since the last typed character. Return value: whether
1250 * we wrapped. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001251int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001252{
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001253 size_t len = strlen(inptr->data);
1254 /* Length of the line we wrap. */
1255 size_t i = 0;
1256 /* Generic loop variable. */
1257 int wrap_loc = -1;
1258 /* Index of inptr->data where we wrap. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001259 int word_back = -1;
1260#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001261 const char *indentation = NULL;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001262 /* Indentation to prepend to the new line. */
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001263 size_t indent_len = 0; /* strlen(indentation) */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001264#endif
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001265 const char *after_break; /* Text after the wrap point. */
1266 size_t after_break_len; /* strlen(after_break) */
1267 int wrapping = FALSE; /* Do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001268 const char *wrap_line = NULL;
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001269 /* The next line, minus indentation. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001270 size_t wrap_line_len = 0; /* strlen(wrap_line) */
1271 char *newline = NULL; /* The line we create. */
1272 size_t new_line_len = 0; /* Eventual length of newline. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001273
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001274/* There are three steps. First, we decide where to wrap. Then, we
1275 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001276
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001277/* Step 1, finding where to wrap. We are going to add a new line
David Lawrence Ramsey89bb9372004-05-29 16:47:52 +00001278 * after a whitespace character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001279 * location of this replacement.
1280 *
1281 * Where should we break the line? We need the last "legal wrap point"
1282 * such that the last word before it ended at or before fill. If there
1283 * is no such point, we settle for the first legal wrap point.
1284 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001285 * A "legal wrap point" is a whitespace character that is not followed
1286 * by whitespace.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001287 *
1288 * If there is no legal wrap point or we found the last character of the
1289 * line, we should return without wrapping.
1290 *
1291 * Note that the initial indentation does not count as a legal wrap
1292 * point if we are going to auto-indent!
1293 *
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001294 * Note that the code below could be optimized, by not calling
1295 * strnlenpt() so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001296
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001297#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001298 if (ISSET(AUTOINDENT))
1299 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001300#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001301 wrap_line = inptr->data + i;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00001302 for (; i < len; i++, wrap_line++) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001303 /* Record where the last word ended. */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001304 if (!isblank(*wrap_line))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001305 word_back = i;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001306 /* If we have found a "legal wrap point" and the current word
1307 * extends too far, then we stop. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001308 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001309 break;
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001310 /* We record the latest "legal wrap point". */
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001311 if (word_back != i && !isblank(wrap_line[1]))
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001312 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001313 }
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001314 if (i == len)
1315 return FALSE;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001316
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001317 /* Step 2, making the new wrap line. It will consist of indentation
1318 * + after_break + " " + wrap_line (although indentation and
1319 * wrap_line are conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001320
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001321 /* after_break is the text that will be moved to the next line. */
1322 after_break = inptr->data + wrap_loc + 1;
1323 after_break_len = len - wrap_loc - 1;
1324 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001325
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001326 /* new_line_len will later be increased by the lengths of indentation
1327 * and wrap_line. */
1328 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001329
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001330 /* We prepend the wrapped text to the next line, if the flag is set,
1331 * and there is a next line, and prepending would not make the line
1332 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001333 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001334 wrap_line = inptr->next->data;
1335 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001336
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001337 /* +1 for the space between after_break and wrap_line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001338 if ((new_line_len + 1 + wrap_line_len) <= fill) {
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001339 wrapping = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001340 new_line_len += (1 + wrap_line_len);
1341 }
1342 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001343
Chris Allegrettaff989832001-09-17 13:48:00 +00001344#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001345 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001346 /* Indentation comes from the next line if wrapping, else from
1347 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001348 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001349 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001350 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001351 /* The wrap_line text should not duplicate indentation.
1352 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001353 wrap_line += indent_len;
1354 else
1355 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001356 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001357#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001358
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001359 /* Now we allocate the new line and copy into it. */
1360 newline = charalloc(new_line_len + 1); /* +1 for \0 */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001361 new_line_len = 0;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001362 *newline = '\0';
1363
1364#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001365 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001366 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001367 newline[indent_len] = '\0';
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001368 new_line_len = indent_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001369 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001370#endif
1371 strcat(newline, after_break);
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001372 new_line_len += after_break_len;
1373 /* We end the old line after wrap_loc. Note that this does not eat
1374 * the space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001375 null_at(&inptr->data, wrap_loc + 1);
1376 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001377 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001378 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001379 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001380 * in a tab or a space, we don't add a space and decrement
1381 * totsize to account for that. */
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001382 if (!isblank(newline[new_line_len - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001383 strcat(newline, " ");
1384 else
1385 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001386 strcat(newline, wrap_line);
1387 free(inptr->next->data);
1388 inptr->next->data = newline;
1389 } else {
1390 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001391
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001392 /* In this case, the file size changes by +1 for the new line,
1393 * and +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001394#ifndef NANO_SMALL
1395 totsize += indent_len;
1396#endif
1397 totlines++;
1398 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001399 temp->prev = inptr;
1400 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001401 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001402 /* If temp->next is NULL, then temp is the last line of the
1403 * file, so we must set filebot. */
1404 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001405 temp->next->prev = temp;
1406 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001407 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001408 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001409
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001410 /* Step 3, clean up. Here we reposition the cursor and mark, and do
1411 * some other sundry things. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001412
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001413 /* Later wraps of this line will be prepended to the next line. */
David Lawrence Ramsey85529b32004-06-22 15:38:47 +00001414 same_line_wrap = TRUE;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001415
1416 /* Each line knows its line number. We recalculate these if we
1417 * inserted a new line. */
1418 if (!wrapping)
1419 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420
Chris Allegretta6df90f52002-07-19 01:08:59 +00001421 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001422 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001423 current = current->next;
1424 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001425#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001426 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001427#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001428 wrap_loc + 1;
1429 wrap_reset();
1430 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001431 }
1432
Chris Allegretta6df90f52002-07-19 01:08:59 +00001433#ifndef NANO_SMALL
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001434 /* If the mark was on this line after the wrap point, we move it
1435 * down. If it was on the next line and we wrapped, we move it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001436 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001437 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1438 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001439 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001440 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001441 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001442#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001443
David Lawrence Ramsey9a527f52004-05-31 14:58:59 +00001444 return TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001445}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001446#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001447
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001448#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001449/* A word is misspelled in the file. Let the user replace it. We
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001450 * return zero if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001451int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001452{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001453 char *save_search;
1454 char *save_replace;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001455 size_t current_x_save = current_x;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00001456 filestruct *current_save = current;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001457 filestruct *edittop_save = edittop;
1458 /* Save where we are. */
1459 int i = 0;
1460 /* The return value. */
1461 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001462#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001463 int case_sens_set = ISSET(CASE_SENSITIVE);
1464 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001465
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001466 SET(CASE_SENSITIVE);
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001467 /* Make sure the marking highlight is off during spell-check. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001468 UNSET(MARK_ISSET);
1469#endif
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001470 /* Make sure spell-check goes forward only. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001471 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001472
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001473 /* Save the current search/replace strings. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001474 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001475 save_search = last_search;
1476 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001477
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001478 /* Set search/replace strings to misspelled word. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001479 last_search = mallocstrcpy(NULL, word);
1480 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001481
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001482 /* Start from the top of the file. */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001483 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001484 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001485
1486 search_last_line = FALSE;
1487
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001488 /* Find the first whole-word occurrence of word. */
1489 while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001490 if (is_whole_word(current_x, current->data, word)) {
1491 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001492
Chris Allegretta6df90f52002-07-19 01:08:59 +00001493 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001494
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001495 /* Allow the replace word to be corrected. */
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00001496 i = statusq(FALSE, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001497#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001498 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001499#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001500 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001501
Chris Allegretta6df90f52002-07-19 01:08:59 +00001502 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001503
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001504 if (i != -1 && strcmp(word, answer) != 0) {
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001505 search_last_line = FALSE;
1506 current_x--;
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001507 do_replace_loop(word, current_save, &current_x_save, TRUE);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001508 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001509
1510 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001511 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001512
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001513 /* Restore the search/replace strings. */
1514 free(last_search);
1515 last_search = save_search;
1516 free(last_replace);
1517 last_replace = save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001518
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001519 /* Restore where we were. */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001520 current = current_save;
1521 current_x = current_x_save;
1522 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001523
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001524 /* Restore search/replace direction. */
Chris Allegretta23b74b22002-01-21 20:32:22 +00001525 if (reverse_search_set)
1526 SET(REVERSE_SEARCH);
1527
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001528#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001529 if (!case_sens_set)
1530 UNSET(CASE_SENSITIVE);
1531
David Lawrence Ramsey1044d742004-02-24 20:41:39 +00001532 /* Restore marking highlight. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001533 if (mark_set)
1534 SET(MARK_ISSET);
1535#endif
1536
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001537 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001538}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001539
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001540/* Integrated spell checking using 'spell' program. Return value: NULL
1541 * for normal termination, otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001542const char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001543{
Chris Allegretta271e9722000-11-10 18:15:43 +00001544 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001545 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001546 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001547 pid_t pid_spell, pid_sort, pid_uniq;
1548 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001549
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001550 /* Create all three pipes up front. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001551 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1552 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001553
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001554 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001555
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001556 /* A new process to run spell in. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001557 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001558
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001559 /* Child continues (i.e, future spell process). */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001560
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001561 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001562
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001563 /* Replace the standard input with the temp file. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001564 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1565 goto close_pipes_and_exit;
1566
1567 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1568 goto close_pipes_and_exit;
1569
Chris Allegretta271e9722000-11-10 18:15:43 +00001570 close(tempfile_fd);
1571
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001572 /* Send spell's standard output to the pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001573 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1574 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001575
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001576 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001577
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001578 /* Start spell program; we are using PATH. */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001579 execlp("spell", "spell", NULL);
1580
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001581 /* Should not be reached, if spell is found. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001582 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001583 }
1584
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001585 /* Parent continues here. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001586 close(spell_fd[1]);
1587
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001588 /* A new process to run sort in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001589 if ((pid_sort = fork()) == 0) {
1590
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001591 /* Child continues (i.e, future spell process). Replace the
1592 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001593 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1594 goto close_pipes_and_exit;
1595
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001596 close(spell_fd[0]);
1597
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001598 /* Send sort's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001599 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1600 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001601
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001602 close(sort_fd[1]);
1603
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001604 /* Start sort program. Use -f to remove mixed case without
1605 * having to have ANOTHER pipe for tr. If this isn't portable,
1606 * let me know. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001607 execlp("sort", "sort", "-f", NULL);
1608
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001609 /* Should not be reached, if sort is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001610 exit(1);
1611 }
1612
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001613 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001614 close(sort_fd[1]);
1615
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001616 /* A new process to run uniq in. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001617 if ((pid_uniq = fork()) == 0) {
1618
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001619 /* Child continues (i.e, future uniq process). Replace the
1620 * standard input with the standard output of the old pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001621 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1622 goto close_pipes_and_exit;
1623
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001624 close(sort_fd[0]);
1625
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001626 /* Send uniq's standard output to the new pipe. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001627 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1628 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001629
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001630 close(uniq_fd[1]);
1631
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001632 /* Start uniq program; we are using PATH. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001633 execlp("uniq", "uniq", NULL);
1634
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001635 /* Should not be reached, if uniq is found. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001636 exit(1);
1637 }
1638
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001639 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001640 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001641
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001642 /* Child process was not forked successfully. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001643 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1644 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001645 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001646 }
1647
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001648 /* Get system pipe buffer size. */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001649 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1650 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001651 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001652 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001653
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001654 /* Read in the returned spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001655 read_buff_read = 0;
1656 read_buff_size = pipe_buff_size + 1;
1657 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001658
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001659 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001660 read_buff_read += bytesread;
1661 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001662 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001663 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001664
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001665 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001666
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001667 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001668 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001669
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001670 /* Process the spelling errors. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001671 read_buff_word = read_buff_ptr = read_buff;
1672
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001673 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001674
1675 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001676 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001677 if (read_buff_word != read_buff_ptr) {
1678 if (!do_int_spell_fix(read_buff_word)) {
1679 read_buff_word = read_buff_ptr;
1680 break;
1681 }
1682 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001683 read_buff_word = read_buff_ptr + 1;
1684 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001685 read_buff_ptr++;
1686 }
1687
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001688 /* Special case where last word doesn't end with \n or \r. */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001689 if (read_buff_word != read_buff_ptr)
1690 do_int_spell_fix(read_buff_word);
1691
Chris Allegretta271e9722000-11-10 18:15:43 +00001692 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001693 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001694 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001695
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001696 /* Process end of spell process. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001697 waitpid(pid_spell, &spell_status, 0);
1698 waitpid(pid_sort, &sort_status, 0);
1699 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001700
Chris Allegretta334a9402002-12-16 04:25:53 +00001701 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1702 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001703
Chris Allegretta334a9402002-12-16 04:25:53 +00001704 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1705 return _("Error invoking \"sort -f\"");
1706
1707 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1708 return _("Error invoking \"uniq\"");
1709
1710 /* Otherwise... */
1711 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001712
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001713 close_pipes_and_exit:
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001714
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001715 /* Don't leak any handles. */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001716 close(tempfile_fd);
1717 close(spell_fd[0]);
1718 close(spell_fd[1]);
1719 close(sort_fd[0]);
1720 close(sort_fd[1]);
1721 close(uniq_fd[0]);
1722 close(uniq_fd[1]);
1723 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001724}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001725
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001726/* External spell checking. Return value: NULL for normal termination,
1727 * otherwise the error string. */
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001728const char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001729{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001730 int alt_spell_status, lineno_cur = current->lineno;
David Lawrence Ramsey360093a2004-07-28 20:53:55 +00001731 int x_cur = current_x, y_cur = current_y;
1732 size_t pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001733 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001734 char *ptr;
1735 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001736 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001737#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001738 int mark_set = ISSET(MARK_ISSET);
1739 int mbb_lineno_cur = 0;
1740 /* We're going to close the current file, and open the output of
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001741 * the alternate spell command. The line that mark_beginbuf
1742 * points to will be freed, so we save the line number and
1743 * restore afterwards. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001744
1745 if (mark_set) {
1746 mbb_lineno_cur = mark_beginbuf->lineno;
1747 UNSET(MARK_ISSET);
1748 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001749#endif
1750
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001751 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001752
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001753 /* Set up an argument list to pass execvp(). */
Chris Allegrettae434b452001-01-27 19:25:00 +00001754 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001755 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001756
Chris Allegrettae434b452001-01-27 19:25:00 +00001757 spellargs[0] = strtok(alt_speller, " ");
1758 while ((ptr = strtok(NULL, " ")) != NULL) {
1759 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001760 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001761 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001762 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001763 spellargs[arglen - 1] = NULL;
1764 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001765 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001766
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001767 /* Start a new process for the alternate speller. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001768 if ((pid_spell = fork()) == 0) {
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001769 /* Start alternate spell program; we are using PATH. */
Chris Allegretta169ee842001-01-26 01:57:32 +00001770 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001771
1772 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001773 exit(1);
1774 }
1775
1776 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001777 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001778 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001779
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001780 /* Wait for alternate speller to complete. */
Chris Allegretta271e9722000-11-10 18:15:43 +00001781 wait(&alt_spell_status);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001782
Chris Allegretta334a9402002-12-16 04:25:53 +00001783 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1784 char *altspell_error = NULL;
1785 char *invoke_error = _("Could not invoke \"%s\"");
1786 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1787
1788 altspell_error = charalloc(msglen);
1789 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1790 return altspell_error;
1791 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001792
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001793 refresh();
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001794#ifndef NANO_SMALL
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001795 if (!mark_set) {
1796 /* Only reload the temp file if it isn't a marked selection. */
1797#endif
1798 free_filestruct(fileage);
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00001799 terminal_init();
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00001800 global_init(TRUE);
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00001801 open_file(tempfile_name, FALSE, TRUE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001802#ifndef NANO_SMALL
1803 }
1804
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001805 if (mark_set) {
1806 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1807 mark_beginbuf = current;
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001808 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001809 mark_beginx = current_x;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001810 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001811 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001812#endif
1813
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001814 /* Go back to the old position, mark the file as modified, and make
1815 * sure that the titlebar is refreshed. */
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001816 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001817 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001818 clearok(topwin, FALSE);
1819 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001820
Chris Allegretta334a9402002-12-16 04:25:53 +00001821 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001822}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001823
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001824void do_spell(void)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001825{
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001826 int i;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001827 char *temp = safe_tempnam(0, "nano.");
1828 const char *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001829
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001830 if (temp == NULL) {
1831 statusbar(_("Could not create temp file: %s"), strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001832 return;
Chris Allegretta271e9722000-11-10 18:15:43 +00001833 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001834
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001835#ifndef NANO_SMALL
1836 if (ISSET(MARK_ISSET))
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001837 i = write_marked(temp, TRUE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001838 else
1839#endif
David Lawrence Ramsey2f0d03b2004-05-28 00:15:28 +00001840 i = write_file(temp, TRUE, FALSE, FALSE);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001841
1842 if (i == -1) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001843 statusbar(_("Unable to write temp file: %s"), strerror(errno));
Chris Allegrettabef12972002-03-06 03:30:40 +00001844 free(temp);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001845 return;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001846 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001847
Chris Allegrettae1f14522001-09-19 03:19:43 +00001848#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001849 /* Update the current open_files entry before spell-checking, in
1850 * case any problems occur. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001851 add_open_file(TRUE);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001852#endif
1853
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001854 spell_msg = alt_speller != NULL ? do_alt_speller(temp) :
1855 do_int_speller(temp);
David Lawrence Ramsey35961c42004-01-23 19:34:03 +00001856 unlink(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001857 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001858
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001859 if (spell_msg != NULL) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001860 statusbar(_("Spell checking failed: %s: %s"), spell_msg,
1861 strerror(errno));
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00001862 return;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00001863 } else
1864 statusbar(_("Finished checking spelling"));
Chris Allegretta67105eb2000-07-03 03:18:32 +00001865}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00001866#endif /* !DISABLE_SPELLER */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001867
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001868#if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
David Lawrence Ramsey8d911992004-05-29 17:05:52 +00001869/* The "indentation" of a line is the whitespace between the quote part
1870 * and the non-whitespace of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001871size_t indent_length(const char *line)
1872{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001873 size_t len = 0;
1874
1875 assert(line != NULL);
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001876 while (isblank(*line)) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001877 line++;
1878 len++;
1879 }
1880 return len;
1881}
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00001882#endif /* !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001883
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001884#ifndef DISABLE_JUSTIFY
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001885/* justify_format() replaces Tab by Space and multiple spaces by 1
1886 * (except it maintains 2 after a . ! or ?). Note the terminating \0
Chris Allegretta6df90f52002-07-19 01:08:59 +00001887 * counts as a space.
1888 *
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001889 * justify_format() might make line->data shorter, and change the actual
1890 * pointer with null_at().
Chris Allegretta6df90f52002-07-19 01:08:59 +00001891 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001892 * justify_format() will not look at the first skip characters of line.
David Lawrence Ramseyf613ca72004-05-13 22:23:58 +00001893 * skip should be at most strlen(line->data). The character at
1894 * line[skip + 1] must not be whitespace. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001895void justify_format(filestruct *line, size_t skip)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001896{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001897 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001898
Chris Allegretta6df90f52002-07-19 01:08:59 +00001899 /* These four asserts are assumptions about the input data. */
1900 assert(line != NULL);
1901 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001902 assert(skip < strlen(line->data));
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00001903 assert(!isblank(line->data[skip]));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001904
Chris Allegretta6df90f52002-07-19 01:08:59 +00001905 back = line->data + skip;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001906 for (front = back; ; front++) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001907 int remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001908 /* Do we want to remove this space? */
1909
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001910 if (*front == '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001911 *front = ' ';
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00001912
David Lawrence Ramsey021960d2004-05-13 23:19:01 +00001913 /* These tests are safe since line->data + skip is not a
1914 * space. */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001915 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001916 const char *bob = front - 2;
1917
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001918 remove_space = TRUE;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001919 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001920 if (strchr(punct, *bob) != NULL) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00001921 remove_space = FALSE;
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001922 break;
1923 }
1924 if (strchr(brackets, *bob) == NULL)
1925 break;
1926 }
1927 }
1928
1929 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001930 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001931 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001932#ifndef NANO_SMALL
1933 if (mark_beginbuf == line && back - line->data < mark_beginx)
1934 mark_beginx--;
1935#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001936 if (*front == '\0')
1937 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00001938 } else {
1939 *back = *front;
1940 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001941 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001942 if (*front == '\0')
1943 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001944 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001945
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001946 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00001947 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00001948
Chris Allegretta6df90f52002-07-19 01:08:59 +00001949 /* Now back is the new end of line->data. */
1950 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00001951 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001952 null_at(&line->data, back - line->data);
1953#ifndef NANO_SMALL
1954 if (mark_beginbuf == line && back - line->data < mark_beginx)
1955 mark_beginx = back - line->data;
1956#endif
1957 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001958}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001959
1960/* The "quote part" of a line is the largest initial substring matching
1961 * the quote string. This function returns the length of the quote part
1962 * of the given line.
1963 *
1964 * Note that if !HAVE_REGEX_H then we match concatenated copies of
1965 * quotestr. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001966size_t quote_length(const char *line)
1967{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001968#ifdef HAVE_REGEX_H
1969 regmatch_t matches;
1970 int rc = regexec(&quotereg, line, 1, &matches, 0);
1971
1972 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t)-1)
1973 return 0;
1974 /* matches.rm_so should be 0, since the quote string should start
1975 * with the caret ^. */
1976 return matches.rm_eo;
1977#else /* !HAVE_REGEX_H */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001978 size_t qdepth = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001979
David Lawrence Ramseyfd3039a2004-07-17 19:49:12 +00001980 /* Compute quote depth level. */
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001981 while (strncmp(line + qdepth, quotestr, quotelen) == 0)
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001982 qdepth += quotelen;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001983 return qdepth;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001984#endif /* !HAVE_REGEX_H */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001985}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001986
Chris Allegretta6df90f52002-07-19 01:08:59 +00001987/* a_line and b_line are lines of text. The quotation part of a_line is
1988 * the first a_quote characters. Check that the quotation part of
1989 * b_line is the same. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001990int quotes_match(const char *a_line, size_t a_quote, const char *b_line)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001991{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001992 /* Here is the assumption about a_quote: */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001993 assert(a_quote == quote_length(a_line));
1994 return a_quote == quote_length(b_line) &&
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00001995 strncmp(a_line, b_line, a_quote) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001996}
1997
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00001998/* We assume a_line and b_line have no quote part. Then, we return
1999 * whether b_line could follow a_line in a paragraph. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002000size_t indents_match(const char *a_line, size_t a_indent, const char
2001 *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002002{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002003 assert(a_indent == indent_length(a_line));
2004 assert(b_indent == indent_length(b_line));
2005
David Lawrence Ramseyb8c479a2004-07-31 14:10:23 +00002006 return b_indent <= a_indent &&
2007 strncmp(a_line, b_line, b_indent) == 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002008}
2009
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002010/* Is foo the beginning of a paragraph?
2011 *
2012 * A line of text consists of a "quote part", followed by an
2013 * "indentation part", followed by text. The functions quote_length()
2014 * and indent_length() calculate these parts.
2015 *
2016 * A line is "part of a paragraph" if it has a part not in the quote
2017 * part or the indentation.
2018 *
2019 * A line is "the beginning of a paragraph" if it is part of a
2020 * paragraph and
2021 * 1) it is the top line of the file, or
2022 * 2) the line above it is not part of a paragraph, or
2023 * 3) the line above it does not have precisely the same quote
2024 * part, or
2025 * 4) the indentation of this line is not an initial substring of
2026 * the indentation of the previous line, or
2027 * 5) this line has no quote part and some indentation, and
2028 * AUTOINDENT is not set.
2029 * The reason for number 5) is that if AUTOINDENT is not set, then an
2030 * indented line is expected to start a paragraph, like in books.
2031 * Thus, nano can justify an indented paragraph only if AUTOINDENT is
2032 * turned on. */
2033bool begpar(const filestruct *const foo)
2034{
2035 size_t quote_len;
2036 size_t indent_len;
2037 size_t temp_id_len;
2038
2039 /* Case 1). */
2040 if (foo->prev == NULL)
2041 return TRUE;
2042
2043 quote_len = quote_length(foo->data);
2044 indent_len = indent_length(foo->data + quote_len);
2045
2046 /* Not part of a paragraph. */
2047 if (foo->data[quote_len + indent_len] == '\0')
2048 return FALSE;
2049
2050 /* Case 3). */
2051 if (!quotes_match(foo->data, quote_len, foo->prev->data))
2052 return TRUE;
2053
2054 temp_id_len = indent_length(foo->prev->data + quote_len);
2055
2056 /* Case 2) or 5) or 4). */
2057 if (foo->prev->data[quote_len + temp_id_len] == '\0' ||
2058 (quote_len == 0 && indent_len > 0
2059#ifndef NANO_SMALL
2060 && !ISSET(AUTOINDENT)
2061#endif
2062 ) || !indents_match(foo->prev->data + quote_len, temp_id_len,
2063 foo->data + quote_len, indent_len))
2064 return TRUE;
2065
2066 return FALSE;
2067}
2068
2069/* We find the last beginning-of-paragraph line before the current
2070 * line. */
2071void do_para_begin(void)
2072{
2073 const filestruct *old_current = current;
2074 const size_t old_pww = placewewant;
2075
2076 current_x = 0;
2077 placewewant = 0;
2078
2079 if (current->prev != NULL) {
2080 do {
2081 current = current->prev;
2082 } while (!begpar(current));
2083 }
2084
2085 edit_redraw(old_current, old_pww);
2086}
2087
2088bool inpar(const char *str)
2089{
2090 size_t quote_len = quote_length(str);
2091
2092 return str[quote_len + indent_length(str + quote_len)] != '\0';
2093}
2094
2095/* A line is the last line of a paragraph if it is in a paragraph, and
2096 * the next line isn't, or is the beginning of a paragraph. We move
2097 * down to the end of a paragraph, then one line farther. */
2098void do_para_end(void)
2099{
2100 const filestruct *const old_current = current;
2101 const size_t old_pww = placewewant;
2102
2103 current_x = 0;
2104 placewewant = 0;
2105
2106 while (current->next != NULL && !inpar(current->data))
2107 current = current->next;
2108
2109 while (current->next != NULL && inpar(current->next->data) &&
2110 !begpar(current->next))
2111 current = current->next;
2112
2113 if (current->next != NULL)
2114 current = current->next;
2115
2116 edit_redraw(old_current, old_pww);
2117}
2118
Chris Allegretta6df90f52002-07-19 01:08:59 +00002119/* Put the next par_len lines, starting with first_line, in the cut
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002120 * buffer, not allowing them to be concatenated. We assume there are
2121 * enough lines after first_line. We leave copies of the lines in
2122 * place, too. We return the new copy of first_line. */
David Lawrence Ramseyd4693cb2004-05-14 01:17:25 +00002123filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t
2124 quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002125{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002126 /* We put the original lines, not copies, into the cutbuffer, just
2127 * out of a misguided sense of consistency, so if you uncut, you get
2128 * the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002129 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002130
2131 set_modified();
2132 cutbuffer = NULL;
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002133 for (; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002134 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002135
Chris Allegretta908f7702003-01-15 11:18:58 +00002136 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002137 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002138 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002139 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002140 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002141 edittop = bob;
2142#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002143 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002144 mark_beginbuf = bob;
2145#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002146
Chris Allegretta908f7702003-01-15 11:18:58 +00002147 assert(alice != NULL && bob != NULL);
David Lawrence Ramsey44e7f822004-03-30 04:17:10 +00002148 add_to_cutbuffer(alice, FALSE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002149 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002150 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002151 }
2152 return first_line;
2153}
2154
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002155/* Is it possible to break line at or before goal? */
2156int breakable(const char *line, int goal)
2157{
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002158 for (; *line != '\0' && goal >= 0; line++) {
David Lawrence Ramsey9830d752004-05-13 17:19:54 +00002159 if (isblank(*line))
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002160 return TRUE;
2161
2162 if (is_cntrl_char(*line) != 0)
2163 goal -= 2;
2164 else
2165 goal -= 1;
2166 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002167 /* If goal is not negative, the whole line (one word) was short
2168 * enough. */
2169 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002170}
2171
Chris Allegretta6df90f52002-07-19 01:08:59 +00002172/* We are trying to break a chunk off line. We find the last space such
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002173 * that the display length to there is at most goal + 1. If there is no
2174 * such space, and force is not 0, then we find the first space.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002175 * Anyway, we then take the last space in that group of spaces. The
2176 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002177int break_line(const char *line, int goal, int force)
2178{
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002179 /* Note that we use int instead of size_t, since goal is at most
2180 * COLS, the screen width, which will always be reasonably small. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002181 int space_loc = -1;
2182 /* Current tentative return value. Index of the last space we
2183 * found with short enough display width. */
2184 int cur_loc = 0;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002185 /* Current index in line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002186
2187 assert(line != NULL);
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002188 for (; *line != '\0' && goal >= 0; line++, cur_loc++) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002189 if (*line == ' ')
2190 space_loc = cur_loc;
2191 assert(*line != '\t');
2192
Chris Allegrettacf287c82002-07-20 13:57:41 +00002193 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002194 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002195 else
2196 goal--;
2197 }
2198 if (goal >= 0)
2199 /* In fact, the whole line displays shorter than goal. */
2200 return cur_loc;
2201 if (space_loc == -1) {
2202 /* No space found short enough. */
2203 if (force)
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002204 for (; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002205 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002206 return cur_loc;
2207 return -1;
2208 }
2209 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002210 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002211 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2212 *(line - cur_loc + space_loc + 1) == '\0')
2213 space_loc++;
2214 return space_loc;
2215}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002216
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002217/* Find the beginning of the current paragraph if we're in one, or the
2218 * beginning of the next paragraph if we're not. Afterwards, save the
2219 * quote length and paragraph length in *quote and *par. Return FALSE
2220 * if we found a paragraph, or TRUE if there was an error or we didn't
2221 * find a paragraph.
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002222 *
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002223 * See the comment at begpar() for more about when a line is the
2224 * beginning of a paragraph. */
2225bool do_para_search(size_t *const quote, size_t *const par)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002226{
2227 size_t quote_len;
2228 /* Length of the initial quotation of the paragraph we
2229 * search. */
2230 size_t par_len;
2231 /* Number of lines in that paragraph. */
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002232 size_t indent_len;
2233 /* Generic indentation length. */
2234 filestruct *line;
2235 /* Generic line of text. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002236
2237#ifdef HAVE_REGEX_H
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002238 if (quoterc != 0) {
2239 statusbar(_("Bad quote string %s: %s"), quotestr, quoteerr);
2240 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002241 }
2242#endif
2243
2244 /* Here is an assumption that is always true anyway. */
2245 assert(current != NULL);
2246
2247 current_x = 0;
2248
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002249 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002250 indent_len = indent_length(current->data + quote_len);
2251
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002252 /* Here we find the first line of the paragraph to search. If the
2253 * current line is in a paragraph, then we move back to the first
2254 * line of the paragraph. Otherwise, we move to the first line that
2255 * is in a paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002256 if (current->data[quote_len + indent_len] != '\0') {
2257 /* This line is part of a paragraph. So we must search back to
2258 * the first line of this paragraph. First we check items 1)
2259 * and 3) above. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002260 while (current->prev != NULL && quotes_match(current->data,
2261 quote_len, current->prev->data)) {
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002262 size_t temp_id_len =
2263 indent_length(current->prev->data + quote_len);
2264 /* The indentation length of the previous line. */
2265
2266 /* Is this line the beginning of a paragraph, according to
2267 * items 2), 5), or 4) above? If so, stop. */
2268 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002269 (quote_len == 0 && indent_len > 0
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002270#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002271 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002272#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002273 ) || !indents_match(current->prev->data + quote_len,
2274 temp_id_len, current->data + quote_len, indent_len))
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002275 break;
2276 indent_len = temp_id_len;
2277 current = current->prev;
2278 current_y--;
2279 }
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002280 } else {
2281 /* This line is not part of a paragraph. Move down until we get
2282 * to a non "blank" line. */
2283 do {
2284 /* There is no next paragraph, so nothing to move to. */
2285 if (current->next == NULL) {
2286 placewewant = 0;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002287 return TRUE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002288 }
2289 current = current->next;
2290 current_y++;
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002291 quote_len = quote_length(current->data);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002292 indent_len = indent_length(current->data + quote_len);
2293 } while (current->data[quote_len + indent_len] == '\0');
2294 }
2295
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002296 /* Now current is the first line of the paragraph, and quote_len is
2297 * the quotation length of that line. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002298
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002299 /* Next step, compute par_len, the number of lines in this
2300 * paragraph. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002301 line = current;
2302 par_len = 1;
2303 indent_len = indent_length(line->data + quote_len);
2304
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002305 while (line->next != NULL &&
2306 quotes_match(current->data, quote_len, line->next->data)) {
2307 size_t temp_id_len = indent_length(line->next->data + quote_len);
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002308
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002309 if (!indents_match(line->data + quote_len, indent_len,
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002310 line->next->data + quote_len, temp_id_len) ||
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002311 line->next->data[quote_len + temp_id_len] == '\0' ||
2312 (quote_len == 0 && temp_id_len > 0
2313#ifndef NANO_SMALL
David Lawrence Ramseydbde9d72004-06-27 00:54:08 +00002314 && !ISSET(AUTOINDENT)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002315#endif
2316 ))
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002317 break;
2318 indent_len = temp_id_len;
2319 line = line->next;
2320 par_len++;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002321 }
2322
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002323 /* Now par_len is the number of lines in this paragraph. We should
2324 * never call quotes_match() or quote_length() again. */
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002325
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002326 /* Save the values of quote_len and par_len. */
2327 assert(quote != NULL && par != NULL);
2328 *quote = quote_len;
2329 *par = par_len;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002330
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002331 return FALSE;
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002332}
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002333
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002334/* If full_justify is TRUE, justify the entire file. Otherwise, justify
2335 * the current paragraph. */
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002336void do_justify(int full_justify)
David Lawrence Ramsey281e0562004-02-27 18:54:04 +00002337{
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002338 filestruct *first_par_line = NULL;
2339 /* Will be the first line of the resulting justified paragraph.
2340 * For restoring after uncut. */
David Lawrence Ramsey36e363f2004-05-17 20:38:00 +00002341 filestruct *last_par_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002342 /* Will be the last line of the result, also for uncut. */
2343 filestruct *cutbuffer_save = cutbuffer;
2344 /* When the paragraph gets modified, all lines from the changed
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002345 * one down are stored in the cutbuffer. We back up the
David Lawrence Ramsey4e254102003-11-05 22:04:08 +00002346 * original to restore it later. */
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002347 bool allow_respacing;
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002348 /* Whether we should change the spacing at the end of a line
David Lawrence Ramseyf7b5d932004-07-05 14:27:29 +00002349 * after justifying it. This should be TRUE whenever we move
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002350 * to the next line after justifying the current line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002351
2352 /* We save these global variables to be restored if the user
2353 * unjustifies. Note we don't need to save totlines. */
2354 int current_x_save = current_x;
2355 int current_y_save = current_y;
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002356 long flags_save = flags;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002357 long totsize_save = totsize;
David Lawrence Ramsey2ed225f2004-05-28 20:44:09 +00002358 filestruct *current_save = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002359 filestruct *edittop_save = edittop;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002360#ifndef NANO_SMALL
2361 filestruct *mark_beginbuf_save = mark_beginbuf;
2362 int mark_beginx_save = mark_beginx;
2363#endif
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002364 int kbinput;
2365 int meta_key;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002366
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002367 /* If we're justifying the entire file, start at the beginning. */
2368 if (full_justify)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002369 current = fileage;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002370
2371 last_par_line = current;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002372
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002373 while (TRUE) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002374 size_t quote_len;
2375 /* Length of the initial quotation of the paragraph we
2376 * justify. */
2377 size_t par_len;
2378 /* Number of lines in that paragraph. */
2379
2380 /* Find the first line of the paragraph to be justified. That
2381 * is the start of this paragraph if we're in one, or the start
2382 * of the next otherwise. Save the quote length and paragraph
2383 * length (number of lines). Don't refresh the screen yet
2384 * (since we'll do that after we justify). If the search failed
2385 * and we're justifying the whole file, move the last line of
2386 * the text we're justifying to just before the magicline, which
2387 * is where it'll be anyway if we've searched the entire file,
2388 * and break out of the loop; otherwise, refresh the screen and
2389 * get out. */
2390 if (do_para_search(&quote_len, &par_len)) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002391 if (full_justify) {
2392 /* This should be safe in the event of filebot->prev's
2393 * being NULL, since only last_par_line->next is used if
2394 * we eventually unjustify. */
2395 last_par_line = filebot->prev;
2396 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002397 } else {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002398 edit_refresh();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002399 return;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002400 }
2401 }
2402
2403 /* Next step, we loop through the lines of this paragraph,
2404 * justifying each one individually. */
2405 for (; par_len > 0; current_y++, par_len--) {
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002406 size_t indent_len; /* Generic indentation length. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002407 size_t line_len;
2408 size_t display_len;
2409 /* The width of current in screen columns. */
2410 int break_pos;
2411 /* Where we will break the line. */
2412
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002413 /* We'll be moving to the next line after justifying the
2414 * current line in almost all cases, so allow changing the
2415 * spacing at the ends of justified lines by default. */
2416 allow_respacing = TRUE;
2417
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002418 indent_len = quote_len + indent_length(current->data +
2419 quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002420
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002421 /* If we haven't already done it, copy the original
2422 * paragraph to the cutbuffer for unjustification. */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002423 if (first_par_line == NULL)
2424 first_par_line = backup_lines(current, full_justify ?
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002425 filebot->lineno - current->lineno : par_len, quote_len);
2426
David Lawrence Ramsey91bc83a2004-06-25 01:52:10 +00002427 /* Now we call justify_format() on the current line of the
2428 * paragraph, which will remove excess spaces from it and
2429 * change tabs to spaces. */
2430 justify_format(current, quote_len +
2431 indent_length(current->data + quote_len));
2432
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002433 line_len = strlen(current->data);
2434 display_len = strlenpt(current->data);
2435
2436 if (display_len > fill) {
2437 /* The line is too long. Try to wrap it to the next. */
2438 break_pos = break_line(current->data + indent_len,
2439 fill - strnlenpt(current->data, indent_len), TRUE);
2440 if (break_pos == -1 || break_pos + indent_len == line_len)
2441 /* We can't break the line, or don't need to, so
2442 * just go on to the next. */
2443 goto continue_loc;
2444 break_pos += indent_len;
2445 assert(break_pos < line_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002446 if (par_len == 1) {
2447 /* There is no next line in this paragraph. We make
2448 * a new line and copy text after break_pos into
2449 * it. */
2450 splice_node(current, make_new_node(current), current->next);
2451 /* In a non-quoted paragraph, we copy the indent
2452 * only if AUTOINDENT is turned on. */
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002453 if (quote_len == 0
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002454#ifndef NANO_SMALL
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002455 && !ISSET(AUTOINDENT)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002456#endif
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002457 )
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002458 indent_len = 0;
2459 current->next->data = charalloc(indent_len + line_len -
2460 break_pos);
2461 strncpy(current->next->data, current->data, indent_len);
2462 strcpy(current->next->data + indent_len,
2463 current->data + break_pos + 1);
2464 assert(strlen(current->next->data) ==
2465 indent_len + line_len - break_pos - 1);
2466 totlines++;
2467 totsize += indent_len;
2468 par_len++;
2469 } else {
2470 size_t next_line_len = strlen(current->next->data);
2471
2472 indent_len = quote_len +
2473 indent_length(current->next->data + quote_len);
2474 current->next->data = charealloc(current->next->data,
2475 next_line_len + line_len - break_pos + 1);
2476
2477 charmove(current->next->data + indent_len + line_len -
2478 break_pos, current->next->data + indent_len,
2479 next_line_len - indent_len + 1);
2480 strcpy(current->next->data + indent_len,
2481 current->data + break_pos + 1);
David Lawrence Ramsey537a8802004-06-24 22:39:24 +00002482 current->next->data[indent_len + line_len -
2483 break_pos - 1] = ' ';
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002484#ifndef NANO_SMALL
2485 if (mark_beginbuf == current->next) {
2486 if (mark_beginx < indent_len)
2487 mark_beginx = indent_len;
2488 mark_beginx += line_len - break_pos;
2489 }
2490#endif
2491 }
2492#ifndef NANO_SMALL
2493 if (mark_beginbuf == current && mark_beginx > break_pos) {
2494 mark_beginbuf = current->next;
2495 mark_beginx -= break_pos + 1 - indent_len;
2496 }
2497#endif
2498 null_at(&current->data, break_pos);
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002499
2500 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002501 current = current->next;
2502 } else if (display_len < fill && par_len > 1) {
2503 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002504
2505 indent_len = quote_len +
2506 indent_length(current->next->data + quote_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002507 /* If we can't pull a word from the next line up to this
2508 * one, just go on. */
2509 if (!breakable(current->next->data + indent_len,
2510 fill - display_len - 1))
2511 goto continue_loc;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002512
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002513 break_pos = break_line(current->next->data + indent_len,
2514 fill - display_len - 1, FALSE);
2515 assert(break_pos != -1);
2516
2517 current->data = charealloc(current->data,
2518 line_len + break_pos + 2);
2519 current->data[line_len] = ' ';
2520 strncpy(current->data + line_len + 1,
2521 current->next->data + indent_len, break_pos);
2522 current->data[line_len + break_pos + 1] = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002523#ifndef NANO_SMALL
2524 if (mark_beginbuf == current->next) {
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002525 if (mark_beginx < indent_len + break_pos) {
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002526 mark_beginbuf = current;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002527 if (mark_beginx <= indent_len)
2528 mark_beginx = line_len + 1;
2529 else
David Lawrence Ramsey2e3aeae2004-05-24 05:52:35 +00002530 mark_beginx = line_len + 1 + mark_beginx -
2531 indent_len;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002532 } else
2533 mark_beginx -= break_pos + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002534 }
2535#endif
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002536 next_line_len = strlen(current->next->data);
2537 if (indent_len + break_pos == next_line_len) {
2538 filestruct *line = current->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002539
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002540 /* Don't destroy edittop! */
2541 if (line == edittop)
2542 edittop = current;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002543
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002544 unlink_node(line);
2545 delete_node(line);
2546 totlines--;
2547 totsize -= indent_len;
2548 current_y--;
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002549
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002550 /* Don't go to the next line. Accordingly, don't
2551 * allow changing the spacing at the end of the
David Lawrence Ramsey309fbcb2004-07-03 14:34:03 +00002552 * previous justified line, so that we don't end up
2553 * doing it more than once on the same line. */
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002554 allow_respacing = FALSE;
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002555 } else {
2556 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002557 current->next->data + indent_len + break_pos + 1,
2558 next_line_len - break_pos - indent_len);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002559 null_at(&current->next->data, next_line_len - break_pos);
David Lawrence Ramsey01a6bf42004-07-03 05:23:19 +00002560
2561 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002562 current = current->next;
2563 }
2564 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002565 continue_loc:
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002566 /* Go to the next line. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002567 current = current->next;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002568
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002569 /* We've moved to the next line after justifying the
David Lawrence Ramsey46938642004-07-03 14:15:58 +00002570 * current line. If the justified line was not the last
2571 * line of the paragraph, add a space to the end of it to
2572 * replace the one removed or left out by justify_format().
2573 * If it was the last line of the paragraph, and
2574 * justify_format() left a space on the end of it, remove
2575 * the space. */
2576 if (allow_respacing) {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002577 size_t prev_line_len = strlen(current->prev->data);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002578
2579 if (par_len > 1) {
2580 current->prev->data = charealloc(current->prev->data,
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002581 prev_line_len + 2);
David Lawrence Ramseya9a6ce02004-06-05 22:09:56 +00002582 current->prev->data[prev_line_len] = ' ';
2583 current->prev->data[prev_line_len + 1] = '\0';
2584 totsize++;
2585 } else if (par_len == 1 &&
2586 current->prev->data[prev_line_len - 1] == ' ') {
2587 current->prev->data = charealloc(current->prev->data,
2588 prev_line_len);
2589 current->prev->data[prev_line_len - 1] = '\0';
2590 totsize--;
2591 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002592 }
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002593 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002594
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002595 /* We've just justified a paragraph. If we're not justifying the
2596 * entire file, break out of the loop. Otherwise, continue the
2597 * loop so that we justify all the paragraphs in the file. */
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002598 if (!full_justify)
2599 break;
2600
2601 } /* while (TRUE) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002602
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002603 /* We are now done justifying the paragraph or the file, so clean
2604 * up. totlines, totsize, and current_y have been maintained above.
2605 * Set last_par_line to the new end of the paragraph, update
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002606 * fileage, and renumber() since edit_refresh() needs the line
2607 * numbers to be right (but only do the last two if we actually
2608 * justified something). */
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002609 last_par_line = current->prev;
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002610 if (first_par_line != NULL) {
2611 if (first_par_line->prev == NULL)
2612 fileage = first_par_line;
2613 renumber(first_par_line);
2614 }
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002615
David Lawrence Ramsey7097d7b2004-05-17 16:11:18 +00002616 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002617
Chris Allegretta9149e612000-11-27 00:23:41 +00002618 statusbar(_("Can now UnJustify!"));
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002619 /* Display the shortcut list with UnJustify. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002620 shortcut_init(TRUE);
Chris Allegretta07798352000-11-27 22:58:23 +00002621 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002622
Chris Allegretta6df90f52002-07-19 01:08:59 +00002623 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002624 * keystroke and return. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002625 kbinput = get_kbinput(edit, &meta_key);
Chris Allegretta5f071802001-05-06 02:34:31 +00002626
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002627#ifndef DISABLE_MOUSE
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00002628 /* If it was a mouse click, parse it with do_mouse() and it might
2629 * become the unjustify key. Else give it back to the input
2630 * stream. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002631 if (kbinput == KEY_MOUSE) {
2632 do_mouse();
2633 kbinput = get_kbinput(edit, &meta_key);
2634 }
2635#endif
2636
2637 if (meta_key || (kbinput != NANO_UNJUSTIFY_KEY &&
2638 kbinput != NANO_UNJUSTIFY_FKEY)) {
2639 ungetch(kbinput);
2640 if (meta_key)
2641 ungetch(NANO_CONTROL_3);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002642 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002643 } else {
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002644 /* Else restore the justify we just did (ungrateful user!). */
2645 filestruct *cutbottom = get_cutbottom();
2646
Chris Allegretta6df90f52002-07-19 01:08:59 +00002647 current = current_save;
2648 current_x = current_x_save;
2649 current_y = current_y_save;
2650 edittop = edittop_save;
Chris Allegrettad022eac2000-11-27 02:50:49 +00002651
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002652 /* Splice the cutbuffer back into the file, but only if we
2653 * actually justified something. */
2654 if (first_par_line != NULL) {
2655 cutbottom->next = last_par_line->next;
2656 cutbottom->next->prev = cutbottom;
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002657 /* The line numbers after the end of the paragraph have been
2658 * changed, so we change them back. */
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002659 renumber(cutbottom->next);
2660 if (first_par_line->prev != NULL) {
2661 cutbuffer->prev = first_par_line->prev;
2662 cutbuffer->prev->next = cutbuffer;
2663 } else
2664 fileage = cutbuffer;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002665
David Lawrence Ramsey8037fe02004-07-23 12:30:40 +00002666 last_par_line->next = NULL;
2667 free_filestruct(first_par_line);
2668 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002669
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002670 /* Restore global variables from before the justify. */
2671 totsize = totsize_save;
2672 totlines = filebot->lineno;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002673#ifndef NANO_SMALL
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002674 mark_beginbuf = mark_beginbuf_save;
2675 mark_beginx = mark_beginx_save;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002676#endif
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002677 flags = flags_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002678 if (!ISSET(MODIFIED))
David Lawrence Ramsey1cadddd2004-05-17 20:32:51 +00002679 titlebar(NULL);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002680 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002681 }
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002682
Chris Allegretta6df90f52002-07-19 01:08:59 +00002683 cutbuffer = cutbuffer_save;
David Lawrence Ramseyfa394042004-05-23 21:11:14 +00002684 /* Note that now cutbottom is invalid, but that's okay. */
2685 blank_statusbar();
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002686 /* Display the shortcut list with UnCut. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00002687 shortcut_init(FALSE);
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002688 display_main_list();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002689}
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002690
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002691void do_justify_void(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002692{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002693 do_justify(FALSE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002694}
2695
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002696void do_full_justify(void)
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002697{
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002698 do_justify(TRUE);
David Lawrence Ramsey8d3e7f32004-05-13 17:28:03 +00002699}
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00002700#endif /* !DISABLE_JUSTIFY */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002701
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002702void do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002703{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002704 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002705
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002706 if (!ISSET(MODIFIED))
2707 i = 0; /* Pretend the user chose not to save. */
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00002708 else if (ISSET(TEMP_FILE))
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002709 i = 1;
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00002710 else
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002711 i = do_yesno(FALSE,
2712 _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2713
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002714#ifdef DEBUG
2715 dump_buffer(fileage);
2716#endif
2717
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002718 if (i == 0 || (i == 1 && do_writeout(TRUE) > 0)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002719#ifdef ENABLE_MULTIBUFFER
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002720 /* Exit only if there are no more open buffers. */
2721 if (close_open_file() != 0)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002722#endif
David Lawrence Ramseyda141062004-05-25 19:41:11 +00002723 finish();
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00002724 } else if (i != 1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002725 statusbar(_("Cancelled"));
2726
2727 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002728}
2729
2730void signal_init(void)
2731{
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002732 /* Trap SIGINT and SIGQUIT because we want them to do useful
2733 * things. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002734 memset(&act, 0, sizeof(struct sigaction));
2735 act.sa_handler = SIG_IGN;
2736 sigaction(SIGINT, &act, NULL);
David Lawrence Ramsey2897d2b2004-01-26 20:56:20 +00002737 sigaction(SIGQUIT, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002738
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002739 /* Trap SIGHUP and SIGTERM because we want to write the file out. */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002740 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002741 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002742 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002743
2744#ifndef NANO_SMALL
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002745 /* Trap SIGWINCH because we want to handle window resizes. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002746 act.sa_handler = handle_sigwinch;
2747 sigaction(SIGWINCH, &act, NULL);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002748 allow_pending_sigwinch(FALSE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002749#endif
2750
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002751 /* Trap normal suspend (^Z) so we can handle it ourselves. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002752 if (!ISSET(SUSPEND)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002753 act.sa_handler = SIG_IGN;
2754 sigaction(SIGTSTP, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002755 } else {
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002756 /* Block all other signals in the suspend and continue handlers.
2757 * If we don't do this, other stuff interrupts them! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002758 sigfillset(&act.sa_mask);
2759
2760 act.sa_handler = do_suspend;
2761 sigaction(SIGTSTP, &act, NULL);
2762
2763 act.sa_handler = do_cont;
2764 sigaction(SIGCONT, &act, NULL);
2765 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002766}
2767
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002768/* Handler for SIGHUP (hangup) and SIGTERM (terminate). */
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002769RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002770{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002771 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002772}
2773
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002774/* Handler for SIGTSTP (suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002775RETSIGTYPE do_suspend(int signal)
2776{
2777 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002778 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002779 fflush(stdout);
2780
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002781 /* Restore the old terminal settings. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002782 tcsetattr(0, TCSANOW, &oldterm);
2783
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002784 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002785 * suspended. */
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002786 act.sa_handler = handle_hupterm;
2787 sigaction(SIGHUP, &act, NULL);
2788 sigaction(SIGTERM, &act, NULL);
2789
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002790 /* Do what mutt does: send ourselves a SIGSTOP. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002791 kill(0, SIGSTOP);
2792}
2793
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002794/* Handler for SIGCONT (continue after suspend). */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002795RETSIGTYPE do_cont(int signal)
2796{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002797#ifndef NANO_SMALL
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002798 /* Perhaps the user resized the window while we slept. Handle it
2799 * and update the screen in the process. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002800 handle_sigwinch(0);
David Lawrence Ramsey5520e852004-04-07 00:44:35 +00002801#else
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002802 /* Just update the screen. */
2803 doupdate();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002804#endif
2805}
2806
2807#ifndef NANO_SMALL
2808void handle_sigwinch(int s)
2809{
2810 const char *tty = ttyname(0);
2811 int fd;
2812 int result = 0;
2813 struct winsize win;
2814
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002815 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002816 return;
2817 fd = open(tty, O_RDWR);
2818 if (fd == -1)
2819 return;
2820 result = ioctl(fd, TIOCGWINSZ, &win);
2821 close(fd);
2822 if (result == -1)
2823 return;
2824
2825 /* Could check whether the COLS or LINES changed, and return
2826 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2827 * variables, and in some cases ncurses has already updated them.
2828 * But not in all cases, argh. */
2829 COLS = win.ws_col;
2830 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002831 editwinrows = LINES - 5 + no_help();
2832 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002833 die_too_small();
2834
2835#ifndef DISABLE_WRAPJUSTIFY
2836 fill = wrap_at;
2837 if (fill <= 0)
2838 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002839 if (fill < 0)
2840 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002841#endif
2842
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002843 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002844 memset(hblank, ' ', COLS);
2845 hblank[COLS] = '\0';
2846
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002847#ifdef USE_SLANG
2848 /* Slang curses emulation brain damage, part 1: If we just do what
2849 * curses does here, it'll only work properly if the resize made the
2850 * window smaller. Do what mutt does: Leave and immediately reenter
2851 * Slang screen management mode. */
2852 SLsmg_reset_smg();
2853 SLsmg_init_smg();
2854#else
2855 /* Do the equivalent of what Minimum Profit does: Leave and
2856 * immediately reenter curses mode. */
2857 endwin();
2858 refresh();
2859#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002860
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002861 /* Restore the terminal to its previous state. */
2862 terminal_init();
2863
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002864 /* Do the equivalent of what both mutt and Minimum Profit do:
2865 * Reinitialize all the windows based on the new screen
2866 * dimensions. */
2867 window_init();
2868
2869 /* Redraw the contents of the windows that need it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002870 blank_statusbar();
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002871 display_main_list();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002872 total_refresh();
2873
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002874 /* Turn cursor back on for sure. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002875 curs_set(1);
2876
David Lawrence Ramsey48ae9862004-05-28 17:23:33 +00002877 /* Reset all the input routines that rely on character sequences. */
2878 reset_kbinput();
2879
David Lawrence Ramsey273d2ce2004-01-30 04:20:28 +00002880 /* Jump back to the main loop. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002881 siglongjmp(jmpbuf, 1);
2882}
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00002883
2884void allow_pending_sigwinch(int allow)
2885{
2886 sigset_t winch;
2887 sigemptyset(&winch);
2888 sigaddset(&winch, SIGWINCH);
2889 if (allow)
2890 sigprocmask(SIG_UNBLOCK, &winch, NULL);
2891 else
2892 sigprocmask(SIG_BLOCK, &winch, NULL);
2893}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002894#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002895
Chris Allegrettadab017e2002-04-23 10:56:06 +00002896#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002897void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002898{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002899 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002900
Chris Allegretta658399a2001-06-14 02:54:22 +00002901 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002902 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002903
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002904 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002905 case TOGGLE_SUSPEND_KEY:
2906 signal_init();
2907 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002908#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002909 case TOGGLE_MOUSE_KEY:
2910 mouse_init();
2911 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002912#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002913 case TOGGLE_NOHELP_KEY:
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002914 blank_statusbar();
2915 blank_bottombars();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002916 wrefresh(bottomwin);
2917 window_init();
2918 edit_refresh();
2919 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002920 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002921 case TOGGLE_DOS_KEY:
2922 UNSET(MAC_FILE);
2923 break;
2924 case TOGGLE_MAC_KEY:
2925 UNSET(DOS_FILE);
2926 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002927#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002928 case TOGGLE_SYNTAX_KEY:
2929 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002930 break;
2931#endif
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00002932#ifdef ENABLE_NANORC
2933 case TOGGLE_WHITESPACE_KEY:
2934 edit_refresh();
2935 break;
2936#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002937 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002938
Chris Allegretta6df90f52002-07-19 01:08:59 +00002939 /* We are assuming here that shortcut_init() above didn't free and
2940 * reallocate the toggles. */
2941 enabled = ISSET(which->flag);
2942 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2943 enabled = !enabled;
2944 statusbar("%s %s", which->desc,
2945 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002946}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002947#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002948
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002949void disable_signals(void)
2950{
2951 struct termios term;
2952
2953 tcgetattr(0, &term);
2954 term.c_lflag &= ~ISIG;
2955 tcsetattr(0, TCSANOW, &term);
2956}
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00002957
2958#ifndef NANO_SMALL
2959void enable_signals(void)
2960{
2961 struct termios term;
2962
2963 tcgetattr(0, &term);
2964 term.c_lflag |= ISIG;
2965 tcsetattr(0, TCSANOW, &term);
2966}
2967#endif
2968
2969void disable_flow_control(void)
2970{
2971 struct termios term;
2972
2973 tcgetattr(0, &term);
2974 term.c_iflag &= ~(IXON|IXOFF);
2975 tcsetattr(0, TCSANOW, &term);
2976}
2977
2978void enable_flow_control(void)
2979{
2980 struct termios term;
2981
2982 tcgetattr(0, &term);
2983 term.c_iflag |= (IXON|IXOFF);
2984 tcsetattr(0, TCSANOW, &term);
2985}
2986
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00002987/* Set up the terminal state. Put the terminal in cbreak mode (read one
2988 * character at a time and interpret the special control keys), disable
2989 * translation of carriage return (^M) into newline (^J) so that we can
2990 * tell the difference between the Enter key and Ctrl-J, and disable
2991 * echoing of characters as they're typed. Finally, disable
2992 * interpretation of the special control keys, and if we're not in
2993 * preserve mode, disable interpretation of the flow control characters
2994 * too. */
2995void terminal_init(void)
2996{
2997 cbreak();
2998 nonl();
2999 noecho();
3000 disable_signals();
3001 if (!ISSET(PRESERVE))
3002 disable_flow_control();
3003}
3004
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003005int main(int argc, char *argv[])
3006{
3007 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003008 int startline = 0; /* Line to try and start at */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003009 int fill_flag_used = FALSE; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003010 const shortcut *s;
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003011 int keyhandled = FALSE; /* Have we handled the keystroke yet? */
David Lawrence Ramseyf8ddf312004-01-09 22:38:09 +00003012 int kbinput; /* Input from keyboard */
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003013 int meta_key;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003014
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003015#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003016 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003017#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003018#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003019 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003020 {"help", 0, 0, 'h'},
3021#ifdef ENABLE_MULTIBUFFER
3022 {"multibuffer", 0, 0, 'F'},
3023#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003024#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003025#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003026 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003027#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003028 {"ignorercfiles", 0, 0, 'I'},
3029#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003030#ifndef DISABLE_JUSTIFY
3031 {"quotestr", 1, 0, 'Q'},
3032#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003033#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003034 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003035#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003036 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003037 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003038#ifdef ENABLE_COLOR
3039 {"syntax", 1, 0, 'Y'},
3040#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003041 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003042 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003043 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003044#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003045 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003046#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003047#ifndef DISABLE_OPERATINGDIR
3048 {"operatingdir", 1, 0, 'o'},
3049#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003050 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003051#ifndef DISABLE_WRAPJUSTIFY
3052 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003053#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054#ifndef DISABLE_SPELLER
3055 {"speller", 1, 0, 's'},
3056#endif
3057 {"tempfile", 0, 0, 't'},
3058 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003059#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003060 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003061#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062 {"nohelp", 0, 0, 'x'},
3063 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003064#ifndef NANO_SMALL
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003065 {"smarthome", 0, 0, 'A'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003066 {"backup", 0, 0, 'B'},
3067 {"dos", 0, 0, 'D'},
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003068 {"backupdir", 1, 0, 'E'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003069 {"mac", 0, 0, 'M'},
3070 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003071 {"smooth", 0, 0, 'S'},
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003072 {"restricted", 0, 0, 'Z'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003073 {"autoindent", 0, 0, 'i'},
3074 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003075#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003076 {0, 0, 0, 0}
3077 };
3078#endif
3079
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003080 setlocale(LC_ALL, "");
David Lawrence Ramseyad1fd0d2004-07-27 15:46:58 +00003081#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003082 bindtextdomain(PACKAGE, LOCALEDIR);
3083 textdomain(PACKAGE);
3084#endif
3085
Chris Allegretta7662c862003-01-13 01:35:15 +00003086#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003087 /* if we don't have rcfile support, we're root, and
3088 --disable-wrapping-as-root is used, turn wrapping off */
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003089 if (geteuid() == NANO_ROOT_UID)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003090 SET(NO_WRAP);
3091#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003092
3093#ifdef HAVE_GETOPT_LONG
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003094 while ((optchr = getopt_long(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz",
David Lawrence Ramseyf4276942003-12-24 03:33:09 +00003095 long_options, NULL)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003096#else
3097 while ((optchr =
David Lawrence Ramseyc7acf692004-05-22 20:15:20 +00003098 getopt(argc, argv, "h?ABDE:FHIMNQ:RST:VY:Zabcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003099#endif
3100
3101 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003102
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +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 Ramseyc7acf692004-05-22 20:15:20 +00003112 case 'A':
3113 SET(SMART_HOME);
3114 break;
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003115 case 'B':
3116 SET(BACKUP_FILE);
3117 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003118 case 'D':
3119 SET(DOS_FILE);
3120 break;
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003121 case 'E':
3122 backup_dir = mallocstrcpy(backup_dir, optarg);
3123 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003124#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003125#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003126 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003127 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003128 break;
3129#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003130#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003131#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003132 case 'H':
3133 SET(HISTORYLOG);
3134 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003135#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003136 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003137 SET(NO_RCFILE);
3138 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003139#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003140#ifndef NANO_SMALL
3141 case 'M':
3142 SET(MAC_FILE);
3143 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003144 case 'N':
3145 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003146 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003147#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003148#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003149 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003150 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003151 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003152#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003153#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003154 case 'R':
3155 SET(USE_REGEXP);
3156 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003157#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003158#ifndef NANO_SMALL
3159 case 'S':
3160 SET(SMOOTHSCROLL);
3161 break;
3162#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003163 case 'T':
David Lawrence Ramseyc53ab2a2004-08-04 18:24:53 +00003164 if (!parse_num(optarg, &tabsize) || tabsize <= 0) {
David Lawrence Ramseya6d26d02004-07-30 22:52:44 +00003165 fprintf(stderr, _("Requested tab size %s invalid\n"), optarg);
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003166 exit(1);
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003167 }
3168 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003169 case 'V':
3170 version();
3171 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003172#ifdef ENABLE_COLOR
3173 case 'Y':
3174 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3175 break;
3176#endif
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003177 case 'Z':
3178 SET(RESTRICTED);
3179 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003180 case 'c':
3181 SET(CONSTUPDATE);
3182 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003183 case 'd':
3184 SET(REBIND_DELETE);
3185 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003186#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003187 case 'i':
3188 SET(AUTOINDENT);
3189 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003190 case 'k':
3191 SET(CUT_TO_END);
3192 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003193#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003194 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003195 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003196 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003197#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003198 case 'm':
3199 SET(USE_MOUSE);
3200 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003201#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003202#ifndef DISABLE_OPERATINGDIR
3203 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003204 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003205 break;
3206#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003207 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003208 SET(PRESERVE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003209 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003210#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003211 case 'r':
David Lawrence Ramseyc53ab2a2004-08-04 18:24:53 +00003212 if (!parse_num(optarg, &wrap_at)) {
David Lawrence Ramseya6d26d02004-07-30 22:52:44 +00003213 fprintf(stderr, _("Requested fill size %s invalid\n"), optarg);
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003214 exit(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003215 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003216 fill_flag_used = TRUE;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003217 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003218#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003219#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003220 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003221 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003222 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003223#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003224 case 't':
David Lawrence Ramseyedab0cc2004-07-03 03:09:12 +00003225 SET(TEMP_FILE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003226 break;
3227 case 'v':
3228 SET(VIEW_MODE);
3229 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003230#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003231 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003232 SET(NO_WRAP);
3233 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003234#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003235 case 'x':
3236 SET(NO_HELP);
3237 break;
3238 case 'z':
3239 SET(SUSPEND);
3240 break;
3241 default:
3242 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003243 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003244 }
3245
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003246 /* If the executable filename starts with 'r', we use restricted
3247 * mode. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003248 if (*(tail(argv[0])) == 'r')
3249 SET(RESTRICTED);
3250
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003251 /* If we're using restricted mode, disable suspending, backups, and
3252 * reading rcfiles, since they all would allow reading from or
3253 * writing to files not specified on the command line. */
David Lawrence Ramseyd893fa92004-04-30 04:49:02 +00003254 if (ISSET(RESTRICTED)) {
3255 UNSET(SUSPEND);
3256 UNSET(BACKUP_FILE);
3257 SET(NO_RCFILE);
3258 }
3259
Chris Allegretta7662c862003-01-13 01:35:15 +00003260/* We've read through the command line options. Now back up the flags
3261 and values that are set, and read the rcfile(s). If the values
3262 haven't changed afterward, restore the backed-up values. */
3263#ifdef ENABLE_NANORC
3264 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003265#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003266 char *operating_dir_cpy = operating_dir;
3267#endif
3268#ifndef DISABLE_WRAPPING
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003269 ssize_t wrap_at_cpy = wrap_at;
Chris Allegretta7662c862003-01-13 01:35:15 +00003270#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003271#ifndef NANO_SMALL
3272 char *backup_dir_cpy = backup_dir;
3273#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003274#ifndef DISABLE_JUSTIFY
3275 char *quotestr_cpy = quotestr;
3276#endif
3277#ifndef DISABLE_SPELLER
3278 char *alt_speller_cpy = alt_speller;
3279#endif
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003280 ssize_t tabsize_cpy = tabsize;
Chris Allegretta7662c862003-01-13 01:35:15 +00003281 long flags_cpy = flags;
3282
Chris Allegretta5ec68622003-02-05 02:39:34 +00003283#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003284 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003285#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003286#ifndef NANO_SMALL
3287 backup_dir = NULL;
3288#endif
Chris Allegretta5ec68622003-02-05 02:39:34 +00003289#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003290 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003291#endif
3292#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003293 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003294#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003295
3296 do_rcfile();
3297
3298#ifndef DISABLE_OPERATINGDIR
3299 if (operating_dir_cpy != NULL) {
3300 free(operating_dir);
3301 operating_dir = operating_dir_cpy;
3302 }
3303#endif
3304#ifndef DISABLE_WRAPPING
3305 if (fill_flag_used)
3306 wrap_at = wrap_at_cpy;
3307#endif
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003308#ifndef NANO_SMALL
3309 if (backup_dir_cpy != NULL) {
3310 free(backup_dir);
3311 backup_dir = backup_dir_cpy;
3312 }
3313#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003314#ifndef DISABLE_JUSTIFY
3315 if (quotestr_cpy != NULL) {
3316 free(quotestr);
3317 quotestr = quotestr_cpy;
3318 }
3319#endif
3320#ifndef DISABLE_SPELLER
3321 if (alt_speller_cpy != NULL) {
3322 free(alt_speller);
3323 alt_speller = alt_speller_cpy;
3324 }
3325#endif
David Lawrence Ramsey04419b92004-07-18 18:13:54 +00003326 if (tabsize_cpy != -1)
Chris Allegretta7662c862003-01-13 01:35:15 +00003327 tabsize = tabsize_cpy;
3328 flags |= flags_cpy;
3329 }
3330#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseya619ae62004-03-04 06:33:52 +00003331 else if (geteuid() == NANO_ROOT_UID)
Chris Allegretta7662c862003-01-13 01:35:15 +00003332 SET(NO_WRAP);
3333#endif
3334#endif /* ENABLE_NANORC */
3335
Chris Allegrettad8451932003-03-11 03:50:40 +00003336#ifndef NANO_SMALL
3337 history_init();
3338#ifdef ENABLE_NANORC
3339 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3340 load_history();
3341#endif
3342#endif
3343
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003344#ifndef NANO_SMALL
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003345 /* Set up the backup directory (unless we're using restricted mode,
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003346 * in which case backups are disabled, since they would allow
3347 * reading from or writing to files not specified on the command
3348 * line). This entails making sure it exists and is a directory, so
3349 * that backup files will be saved there. */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003350 if (!ISSET(RESTRICTED))
3351 init_backup_dir();
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003352#endif
3353
Chris Allegretta7662c862003-01-13 01:35:15 +00003354#ifndef DISABLE_OPERATINGDIR
3355 /* Set up the operating directory. This entails chdir()ing there,
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003356 * so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003357 init_operating_dir();
3358#endif
3359
Chris Allegretta7662c862003-01-13 01:35:15 +00003360#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003361 if (punct == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003362 punct = mallocstrcpy(punct, ".?!");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003363
3364 if (brackets == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003365 brackets = mallocstrcpy(brackets, "'\")}]>");
David Lawrence Ramsey2c62b072004-05-29 16:38:57 +00003366
Chris Allegretta7662c862003-01-13 01:35:15 +00003367 if (quotestr == NULL)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003368 quotestr = mallocstrcpy(NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00003369#ifdef HAVE_REGEX_H
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003370 "^([ \t]*[|>:}#])+"
Chris Allegretta7662c862003-01-13 01:35:15 +00003371#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003372 "> "
Chris Allegretta7662c862003-01-13 01:35:15 +00003373#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003374 );
David Lawrence Ramsey819c7f02004-07-30 03:54:34 +00003375#ifdef HAVE_REGEX_H
3376 quoterc = regcomp(&quotereg, quotestr, REG_EXTENDED);
3377
3378 if (quoterc == 0) {
3379 /* We no longer need quotestr, just quotereg. */
3380 free(quotestr);
3381 quotestr = NULL;
3382 } else {
3383 size_t size = regerror(quoterc, &quotereg, NULL, 0);
3384
3385 quoteerr = charalloc(size);
3386 regerror(quoterc, &quotereg, quoteerr, size);
3387 }
3388#else
3389 quotelen = strlen(quotestr);
3390#endif /* !HAVE_REGEX_H */
Chris Allegretta7662c862003-01-13 01:35:15 +00003391#endif /* !DISABLE_JUSTIFY */
David Lawrence Ramsey04e42a62004-02-28 16:24:31 +00003392
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003393#ifndef DISABLE_SPELLER
3394 /* If we don't have an alternative spell checker after reading the
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003395 * command line and/or rcfile(s), check $SPELL for one, as Pico
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003396 * does (unless we're using restricted mode, in which case spell
David Lawrence Ramsey32e3b882004-05-29 01:20:17 +00003397 * checking is disabled, since it would allow reading from or
3398 * writing to files not specified on the command line). */
David Lawrence Ramseydd7cc722004-05-28 23:45:25 +00003399 if (!ISSET(RESTRICTED) && alt_speller == NULL) {
David Lawrence Ramsey3aedb362004-05-28 22:42:41 +00003400 char *spellenv = getenv("SPELL");
3401 if (spellenv != NULL)
3402 alt_speller = mallocstrcpy(NULL, spellenv);
3403 }
3404#endif
3405
David Lawrence Ramsey483ea322004-05-29 16:25:30 +00003406#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
3407 if (whitespace == NULL)
3408 whitespace = mallocstrcpy(NULL, " ");
3409#endif
3410
Chris Allegretta7662c862003-01-13 01:35:15 +00003411 if (tabsize == -1)
3412 tabsize = 8;
3413
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003414 /* Clear the filename we'll be using */
3415 filename = charalloc(1);
3416 filename[0] = '\0';
3417
Chris Allegretta7662c862003-01-13 01:35:15 +00003418 /* If there's a +LINE flag, it is the first non-option argument. */
3419 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3420 startline = atoi(&argv[optind][1]);
3421 optind++;
3422 }
3423 if (0 < optind && optind < argc)
3424 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003425
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003426 /* See if there's a non-option in argv (first non-option is the
3427 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003428 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003429 /* Look for the +line flag... */
3430 if (argv[optind][0] == '+') {
3431 startline = atoi(&argv[optind][1]);
3432 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003433 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003434 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003435 } else
3436 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003437 }
3438
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003439 /* Back up the old terminal settings so that they can be restored. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003440 tcgetattr(0, &oldterm);
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003441
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003442 /* Curses initialization stuff: Start curses and set up the
3443 * terminal state. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003444 initscr();
David Lawrence Ramsey8aaf0302004-07-27 16:46:35 +00003445 terminal_init();
David Lawrence Ramseyc53a92d2004-01-12 03:28:06 +00003446
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003447 /* Set up the global variables and the shortcuts. */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003448 global_init(FALSE);
3449 shortcut_init(FALSE);
David Lawrence Ramsey369732f2004-02-16 20:32:40 +00003450
3451 /* Set up the signal handlers. */
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003452 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003453
3454#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003455 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003456#endif
3457
Chris Allegretta2a42af12000-09-12 23:02:49 +00003458 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003459#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003460 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003461#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003462
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003463#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003464 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003465#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003466 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003467 display_main_list();
3468
3469#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003470 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003471#endif
3472
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003473 open_file(filename, FALSE, FALSE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003474#ifdef ENABLE_MULTIBUFFER
3475 /* If we're using multibuffers and more than one file is specified
3476 on the command line, load them all and switch to the first one
3477 afterward */
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003478 if (optind + 1 < argc) {
3479 int old_multibuffer = ISSET(MULTIBUFFER);
3480 SET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003481 for (optind++; optind < argc; optind++) {
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003482 add_open_file(TRUE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003483 new_file();
3484 filename = mallocstrcpy(filename, argv[optind]);
David Lawrence Ramsey576bf332004-07-12 03:10:30 +00003485 open_file(filename, FALSE, FALSE);
David Lawrence Ramsey72e51ab2004-07-02 14:31:03 +00003486 load_file(FALSE);
Chris Allegretta7662c862003-01-13 01:35:15 +00003487 }
3488 open_nextfile_void();
David Lawrence Ramsey1d43db82004-05-14 17:57:00 +00003489 if (!old_multibuffer)
3490 UNSET(MULTIBUFFER);
Chris Allegretta7662c862003-01-13 01:35:15 +00003491 }
3492#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003493
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003494 titlebar(NULL);
3495
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003496 if (startline > 0)
David Lawrence Ramsey49c3f242004-07-12 16:07:14 +00003497 do_gotoline(startline, FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003498
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003499#ifndef NANO_SMALL
3500 /* Return here after a SIGWINCH. */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003501 sigsetjmp(jmpbuf, 1);
David Lawrence Ramseyd7fd2002004-05-18 01:20:36 +00003502#endif
Chris Allegretta08020882001-01-29 23:37:54 +00003503
Robert Siemborski6967eec2000-07-08 14:23:32 +00003504 edit_refresh();
Robert Siemborski6967eec2000-07-08 14:23:32 +00003505
David Lawrence Ramsey6aec4b82004-03-15 20:26:30 +00003506 while (TRUE) {
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003507 keyhandled = FALSE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003508
David Lawrence Ramseyaea4dab2004-07-13 17:09:24 +00003509 reset_cursor();
Chris Allegrettad26ab912003-01-28 01:16:47 +00003510 if (ISSET(CONSTUPDATE))
David Lawrence Ramsey74912c62004-07-01 19:41:09 +00003511 do_cursorpos(TRUE);
Chris Allegrettad26ab912003-01-28 01:16:47 +00003512
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003513#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003514 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003515#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003516
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003517 kbinput = get_kbinput(edit, &meta_key);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003518#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003519 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003520#endif
David Lawrence Ramsey4d44d2d2004-08-01 22:35:31 +00003521 if (meta_key) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003522 /* Check for the metaval and miscval defs... */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003523 for (s =
3524#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
3525 currshortcut
3526#else
3527 main_list
3528#endif
3529 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey82138502003-12-24 08:03:54 +00003530 if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003531 (s->miscval != NANO_NO_KEY && kbinput == s->miscval)) {
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003532 if (ISSET(VIEW_MODE) && !s->viewok)
3533 print_view_warning();
3534 else {
3535 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003536 cutbuffer_reset();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003537 s->func();
3538 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003539 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003540 }
3541#ifndef NANO_SMALL
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003542 if (!keyhandled) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003543 /* And for toggle switches */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003544 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003545 if (kbinput == t->val) {
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003546 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003547 do_toggle(t);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003548 keyhandled = TRUE;
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003549 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003550 }
3551 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003552#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003553 }
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003554#ifdef DEBUG
David Lawrence Ramsey331e6592004-07-27 19:40:39 +00003555 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput, kbinput);
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003556#endif
3557 }
3558
3559 /* Look through the main shortcut list to see if we've hit a
3560 shortcut key or function key */
3561
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003562 if (!keyhandled) {
3563 for (s =
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003564#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003565 currshortcut
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003566#else
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003567 main_list
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003568#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003569 ; s != NULL && !keyhandled; s = s->next) {
David Lawrence Ramsey1576d532004-03-19 21:46:34 +00003570 if ((s->ctrlval != NANO_NO_KEY && kbinput == s->ctrlval) ||
3571 (s->funcval != NANO_NO_KEY && kbinput == s->funcval)) {
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003572 if (ISSET(VIEW_MODE) && !s->viewok)
3573 print_view_warning();
3574 else {
3575 if (s->func != do_cut_text)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003576 cutbuffer_reset();
David Lawrence Ramseya593f532003-11-28 19:47:42 +00003577 s->func();
3578 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003579 keyhandled = TRUE;
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003580 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003581 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003582 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003583
3584 if (!keyhandled)
David Lawrence Ramseyc833d9e2004-05-29 15:36:58 +00003585 cutbuffer_reset();
Chris Allegrettae42df732002-10-15 00:27:55 +00003586
Chris Allegrettae42df732002-10-15 00:27:55 +00003587 /* Don't even think about changing this string */
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003588 if (kbinput == NANO_XON_KEY)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003589 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003590 if (kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003591 statusbar(_("XOFF ignored, mumble mumble."));
David Lawrence Ramseyebd0d7c2004-07-01 18:59:52 +00003592 if (kbinput == NANO_XON_KEY || kbinput == NANO_XOFF_KEY)
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003593 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003594
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003595 /* Catch ^Z by hand when triggered also */
3596 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003597 if (ISSET(SUSPEND))
3598 do_suspend(0);
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003599 keyhandled = TRUE;
Chris Allegretta9239d742000-09-06 15:19:18 +00003600 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003601
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003602 /* Last gasp, stuff that's not in the main lists */
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003603 if (!keyhandled) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003604 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003605#ifndef DISABLE_MOUSE
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003606 case KEY_MOUSE:
3607 do_mouse();
3608 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003609#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003610 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3611 * have been handled before we
3612 * got here */
3613 case NANO_CONTROL_5: /* Ctrl-] */
3614 break;
3615 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003616#ifdef DEBUG
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003617 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003618#endif
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003619 /* We no longer stop unhandled sequences so that
3620 people with odd character sets can type... */
3621 if (ISSET(VIEW_MODE))
3622 print_view_warning();
3623 else
3624 do_char((char)kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003625 }
David Lawrence Ramsey74af3a72004-06-12 21:03:14 +00003626 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003627 }
David Lawrence Ramseyfd1768a2004-03-19 21:57:56 +00003628 assert(FALSE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003629}