blob: 74949f818780ee7100c6b20fe1fe238c392344f4 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
Chris Allegrettad757e252003-01-15 19:33:27 +00005 * Copyright (C) 1999-2003 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>
Chris Allegretta08020882001-01-29 23:37:54 +000028#include <setjmp.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000029#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000035#include <sys/types.h>
36#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000037#include <errno.h>
38#include <ctype.h>
39#include <locale.h>
40#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000041#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#include "proto.h"
43#include "nano.h"
44
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000045#ifdef HAVE_TERMIOS_H
46#include <termios.h>
47#endif
48
49#ifdef HAVE_TERMIO_H
50#include <termio.h>
51#endif
52
53#ifdef HAVE_GETOPT_H
54#include <getopt.h>
55#endif
56
Chris Allegretta6fe61492001-05-21 12:56:25 +000057#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000058static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#endif
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +000060#ifndef DISABLE_WRAPPING
61static int same_line_wrap = 0; /* Whether wrapped text should be
62 prepended to the next line */
63#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000064
Chris Allegretta6df90f52002-07-19 01:08:59 +000065static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000066static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000067
Chris Allegretta08020882001-01-29 23:37:54 +000068static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
69
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000070/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000071RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000072{
73 if (!ISSET(NO_HELP)) {
74 mvwaddstr(bottomwin, 1, 0, hblank);
75 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000076 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000077 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000078
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000079 wrefresh(bottomwin);
80 endwin();
81
82 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000083 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000084
Chris Allegrettad8451932003-03-11 03:50:40 +000085#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
86 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
87 save_history();
88#endif
89
Chris Allegretta6232d662002-05-12 19:52:15 +000090#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000091 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000092#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000093
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094 exit(sigage);
95}
96
97/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +000098void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099{
100 va_list ap;
101
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000102 endwin();
103 curses_ended = TRUE;
104
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000106 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000107
Chris Allegretta6df90f52002-07-19 01:08:59 +0000108 va_start(ap, msg);
109 vfprintf(stderr, msg, ap);
110 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000111
Chris Allegretta32da4562002-01-02 15:12:21 +0000112 /* save the currently loaded file if it's been modified */
113 if (ISSET(MODIFIED))
114 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000115
Chris Allegretta355fbe52001-07-14 19:32:47 +0000116#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000117 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000118 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000119 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000120
121 tmp = open_files;
122
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000123 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000124 open_files = open_files->prev;
125
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000126 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000127
128 /* if we already saved the file above (i. e. if it was the
129 currently loaded file), don't save it again */
130 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000131 /* make sure open_files->fileage and fileage, and
132 open_files->filebot and filebot, are in sync; they
133 might not be if lines have been cut from the top or
134 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000135 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000136 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000137 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000138 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000139 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000140 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000141 open_files = open_files->next;
142 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143 }
144#endif
145
Chris Allegretta6df90f52002-07-19 01:08:59 +0000146 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147}
148
Chris Allegretta6df90f52002-07-19 01:08:59 +0000149void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000150{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000151 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000152 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153
Chris Allegretta6df90f52002-07-19 01:08:59 +0000154 /* If we can't save, we have REAL bad problems, but we might as well
155 TRY. */
156 if (die_filename[0] == '\0')
157 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000158 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000160
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000161 strcpy(buf, die_filename);
162 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000163 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000164 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000165 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 if (ret[0] != '\0')
167 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000168
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000169 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000170 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000171 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000173
174 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000175}
176
Chris Allegrettae61e8302001-01-14 05:18:27 +0000177/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000179void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000180{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000181 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000182}
183
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000184void print_view_warning(void)
185{
186 statusbar(_("Key illegal in VIEW mode"));
187}
188
Chris Allegretta56214c62001-09-27 02:46:53 +0000189/* Initialize global variables - no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000190 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000191void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000193 current_x = 0;
194 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000195
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000196 editwinrows = LINES - 5 + no_help();
197 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000198 die_too_small();
199
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000200 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000201 if (!save_cutbuffer)
202 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000203 current = NULL;
204 edittop = NULL;
205 editbot = NULL;
206 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000207 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000209
Chris Allegretta6fe61492001-05-21 12:56:25 +0000210#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000211 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000212 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000213 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000214 if (fill < 0)
215 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000216#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000217
Chris Allegretta88b09152001-05-17 11:35:43 +0000218 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000219 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000220 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000221}
222
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000223void window_init(void)
224{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000225 editwinrows = LINES - 5 + no_help();
226 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000227 die_too_small();
228
Chris Allegretta1a128af2003-01-26 04:15:56 +0000229 if (edit != NULL)
230 delwin(edit);
231 if (topwin != NULL)
232 delwin(topwin);
233 if (bottomwin != NULL)
234 delwin(bottomwin);
235
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000236 /* Set up the main text window. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000237 edit = newwin(editwinrows, COLS, 2, 0);
238
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000239 /* And the other windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000240 topwin = newwin(2, COLS, 0, 0);
241 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
242
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000243 /* This is so the keypad still works after a Meta-X, for example. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000244 keypad(edit, TRUE);
245 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000246}
247
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000248#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000249void mouse_init(void)
250{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000251 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252 mousemask(BUTTON1_RELEASED, NULL);
253 mouseinterval(50);
254 } else
255 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000256}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000257#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258
259#ifndef DISABLE_HELP
260/* This function allocates help_text, and stores the help string in it.
261 * help_text should be NULL initially. */
262void help_init(void)
263{
Chris Allegretta908f7702003-01-15 11:18:58 +0000264 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000265 char *ptr = NULL;
266#ifndef NANO_SMALL
267 const toggle *t;
268#endif
269 const shortcut *s;
270
271 /* First set up the initial help text for the current function */
272 if (currshortcut == whereis_list || currshortcut == replace_list
273 || currshortcut == replace_list_2)
274 ptr = _("Search Command Help Text\n\n "
275 "Enter the words or characters you would like to search "
276 "for, then hit enter. If there is a match for the text you "
277 "entered, the screen will be updated to the location of the "
278 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000279 "The previous search string will be shown in brackets after "
280 "the Search: prompt. Hitting Enter without entering any text "
281 "will perform the previous search.\n\n The following function "
282 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000283 else if (currshortcut == goto_list)
284 ptr = _("Go To Line Help Text\n\n "
285 "Enter the line number that you wish to go to and hit "
286 "Enter. If there are fewer lines of text than the "
287 "number you entered, you will be brought to the last line "
288 "of the file.\n\n The following function keys are "
289 "available in Go To Line mode:\n\n");
290 else if (currshortcut == insertfile_list)
291 ptr = _("Insert File Help Text\n\n "
292 "Type in the name of a file to be inserted into the current "
293 "file buffer at the current cursor location.\n\n "
294 "If you have compiled nano with multiple file buffer "
295 "support, and enable multiple buffers with the -F "
296 "or --multibuffer command line flags, the Meta-F toggle, or "
297 "a nanorc file, inserting a file will cause it to be "
298 "loaded into a separate buffer (use Meta-< and > to switch "
299 "between file buffers).\n\n If you need another blank "
300 "buffer, do not enter any filename, or type in a "
301 "nonexistent filename at the prompt and press "
302 "Enter.\n\n The following function keys are "
303 "available in Insert File mode:\n\n");
304 else if (currshortcut == writefile_list)
305 ptr = _("Write File Help Text\n\n "
306 "Type the name that you wish to save the current file "
307 "as and hit Enter to save the file.\n\n If you have "
308 "selected text with Ctrl-^, you will be prompted to "
309 "save only the selected portion to a separate file. To "
310 "reduce the chance of overwriting the current file with "
311 "just a portion of it, the current filename is not the "
312 "default in this mode.\n\n The following function keys "
313 "are available in Write File mode:\n\n");
314#ifndef DISABLE_BROWSER
315 else if (currshortcut == browser_list)
316 ptr = _("File Browser Help Text\n\n "
317 "The file browser is used to visually browse the "
318 "directory structure to select a file for reading "
319 "or writing. You may use the arrow keys or Page Up/"
320 "Down to browse through the files, and S or Enter to "
321 "choose the selected file or enter the selected "
322 "directory. To move up one level, select the directory "
323 "called \"..\" at the top of the file list.\n\n The "
324 "following function keys are available in the file "
325 "browser:\n\n");
326 else if (currshortcut == gotodir_list)
327 ptr = _("Browser Go To Directory Help Text\n\n "
328 "Enter the name of the directory you would like to "
329 "browse to.\n\n If tab completion has not been disabled, "
330 "you can use the TAB key to (attempt to) automatically "
331 "complete the directory name.\n\n The following function "
332 "keys are available in Browser Go To Directory mode:\n\n");
333#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000334#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000335 else if (currshortcut == spell_list)
336 ptr = _("Spell Check Help Text\n\n "
337 "The spell checker checks the spelling of all text "
338 "in the current file. When an unknown word is "
339 "encountered, it is highlighted and a replacement can "
340 "be edited. It will then prompt to replace every "
341 "instance of the given misspelled word in the "
342 "current file.\n\n The following other functions are "
343 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000344#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000345#ifndef NANO_SMALL
346 else if (currshortcut == extcmd_list)
347 ptr = _("External Command Help Text\n\n "
348 "This menu allows you to insert the output of a command "
349 "run by the shell into the current buffer (or a new "
350 "buffer in multibuffer mode).\n\n The following keys are "
351 "available in this mode:\n\n");
352#endif
353 else /* Default to the main help list */
354 ptr = _(" nano help text\n\n "
355 "The nano editor is designed to emulate the functionality and "
356 "ease-of-use of the UW Pico text editor. There are four main "
357 "sections of the editor: The top line shows the program "
358 "version, the current filename being edited, and whether "
359 "or not the file has been modified. Next is the main editor "
360 "window showing the file being edited. The status line is "
361 "the third line from the bottom and shows important messages. "
362 "The bottom two lines show the most commonly used shortcuts "
363 "in the editor.\n\n "
364 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000365 "sequences are notated with a caret (^) symbol and can be "
366 "entered either by using the Control (Ctrl) key or pressing the "
367 "Esc key twice. Escape-key sequences are notated with the Meta "
368 "(M) symbol and can be entered using either the Esc, Alt or "
369 "Meta key depending on your keyboard setup. Also, pressing Esc "
370 "twice and then typing a three-digit number from 000 to 255 "
371 "will enter the character with the corresponding ASCII code. "
372 "The following keystrokes are available in the main editor "
373 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000374
Chris Allegretta908f7702003-01-15 11:18:58 +0000375 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000376
377 /* The space needed for the shortcut lists, at most COLS characters,
378 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000379 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000380
381#ifndef NANO_SMALL
382 /* If we're on the main list, we also count the toggle help text.
383 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
384 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000385 if (currshortcut == main_list) {
386 size_t endislen = strlen(_("enable/disable"));
387
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000388 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000389 allocsize += 8 + strlen(t->desc) + endislen;
390 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000391#endif /* !NANO_SMALL */
392
393 /* help_text has been freed and set to NULL unless the user resized
394 * while in the help screen. */
395 free(help_text);
396
397 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000398 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000399
400 /* Now add the text we want */
401 strcpy(help_text, ptr);
402 ptr = help_text + strlen(help_text);
403
404 /* Now add our shortcut info */
405 for (s = currshortcut; s != NULL; s = s->next) {
406 /* true if the character in s->altval is shown in first column */
407 int meta_shortcut = 0;
408
409 if (s->val > 0 && s->val < 32)
410 ptr += sprintf(ptr, "^%c", s->val + 64);
411#ifndef NANO_SMALL
412 else if (s->val == NANO_CONTROL_SPACE)
413 ptr += sprintf(ptr, "^%.6s", _("Space"));
414 else if (s->altval == NANO_ALT_SPACE) {
415 meta_shortcut = 1;
416 ptr += sprintf(ptr, "M-%.5s", _("Space"));
Chris Allegretta7662c862003-01-13 01:35:15 +0000417 } else if (s->val == KEY_UP)
418 ptr += sprintf(ptr, "%.2s", _("Up"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000419#endif
420 else if (s->altval > 0) {
421 meta_shortcut = 1;
422 ptr += sprintf(ptr, "M-%c", s->altval -
423 (('A' <= s->altval && s->altval <= 'Z') ||
424 'a' <= s->altval ? 32 : 0));
425 }
426 /* Hack */
427 else if (s->val >= 'a') {
428 meta_shortcut = 1;
429 ptr += sprintf(ptr, "M-%c", s->val - 32);
430 }
431
432 *(ptr++) = '\t';
433
434 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
435 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
436
437 *(ptr++) = '\t';
438
439 if (!meta_shortcut && s->altval > 0)
440 ptr += sprintf(ptr, "(M-%c)", s->altval -
441 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
442 ? 32 : 0));
443
444 *(ptr++) = '\t';
445
446 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000447 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000448 }
449
450#ifndef NANO_SMALL
451 /* And the toggles... */
452 if (currshortcut == main_list)
453 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000454 assert(t->desc != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000455 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", t->val - 32, t->desc,
456 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000457 }
458#endif /* !NANO_SMALL */
459
460 /* If all went well, we didn't overwrite the allocated space for
461 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000462 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000463}
464#endif
465
466/* Create a new filestruct node. Note that we specifically do not set
467 * prevnode->next equal to the new line. */
468filestruct *make_new_node(filestruct *prevnode)
469{
470 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
471
472 newnode->data = NULL;
473 newnode->prev = prevnode;
474 newnode->next = NULL;
475 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
476
477 return newnode;
478}
479
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000480/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000481filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000482{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000483 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000484
Chris Allegretta6df90f52002-07-19 01:08:59 +0000485 assert(src != NULL);
486
Chris Allegretta88b09152001-05-17 11:35:43 +0000487 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000488 dst->next = src->next;
489 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000490 strcpy(dst->data, src->data);
491 dst->lineno = src->lineno;
492
493 return dst;
494}
495
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000496/* Splice a node into an existing filestruct. */
497void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
498{
499 if (newnode != NULL) {
500 newnode->next = end;
501 newnode->prev = begin;
502 }
503 if (begin != NULL)
504 begin->next = newnode;
505 if (end != NULL)
506 end->prev = newnode;
507}
508
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000509/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000510void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000511{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000512 assert(fileptr != NULL);
513
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000514 if (fileptr->prev != NULL)
515 fileptr->prev->next = fileptr->next;
516
517 if (fileptr->next != NULL)
518 fileptr->next->prev = fileptr->prev;
519}
520
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000521/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000522void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000524 if (fileptr != NULL) {
525 if (fileptr->data != NULL)
526 free(fileptr->data);
527 free(fileptr);
528 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529}
530
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000531/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000532filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000533{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000534 filestruct *head; /* copy of src, top of the copied list */
535 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000536
Chris Allegretta6df90f52002-07-19 01:08:59 +0000537 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000538
Chris Allegretta6df90f52002-07-19 01:08:59 +0000539 prev = copy_node(src);
540 prev->prev = NULL;
541 head = prev;
542 src = src->next;
543 while (src != NULL) {
544 prev->next = copy_node(src);
545 prev->next->prev = prev;
546 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000549 }
550
Chris Allegretta6df90f52002-07-19 01:08:59 +0000551 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000552 return head;
553}
554
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000555/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000556void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000557{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000558 if (src != NULL) {
559 while (src->next != NULL) {
560 src = src->next;
561 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000563 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000564#endif
565 }
566 delete_node(src);
567#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000568 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000569#endif
570 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571}
572
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574{
575 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000576 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578 assert(fileage == NULL || fileage != fileage->next);
579 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000581}
582
Chris Allegretta6df90f52002-07-19 01:08:59 +0000583void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000584{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000585 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000587 else {
588 int lineno = fileptr->prev->lineno;
589
590 assert(fileptr != fileptr->next);
591 for (; fileptr != NULL; fileptr = fileptr->next)
592 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000593 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000594}
595
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000596/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000597 * strings to translate and takes out the parts that shouldn't be
598 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000599void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000600 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000601{
602 printf(" %s\t", shortflag);
603 if (strlen(shortflag) < 8)
604 printf("\t");
605
606#ifdef HAVE_GETOPT_LONG
607 printf("%s\t", longflag);
608 if (strlen(longflag) < 8)
609 printf("\t\t");
610 else if (strlen(longflag) < 16)
611 printf("\t");
612#endif
613
614 printf("%s\n", desc);
615}
616
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000617void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000618{
619#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000620 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
621 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000622#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000623 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
624 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000625#endif /* HAVE_GETOPT_LONG */
626
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000627 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000628 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000629#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000630 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000631 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000632#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000633#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000634 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000635#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000636#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000637#ifndef NANO_SMALL
Chris Allegretta36fec722003-01-22 01:13:25 +0000638 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +0000639#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000640 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
641#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000642#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000643 print1opt("-M", "--mac", _("Write file in Mac format"));
644 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000645#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000646#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000647 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000648#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000649#ifdef HAVE_REGEX_H
650 print1opt("-R", "--regexp", _("Do regular expression searches"));
651#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000652#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000653 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000654#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000655 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000656 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000657#ifdef ENABLE_COLOR
658 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
659#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000660 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000661#ifndef NANO_SMALL
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000662 print1opt("-d", "--rebinddelete", _("Fix Backspace if it acts like Delete"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000663 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
664 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000665#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000666 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000667#ifndef DISABLE_MOUSE
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000668 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000669#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000670#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000671 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000672#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000673 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000674#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000675 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000676#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000677#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000678 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000679#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000680 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
681 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000682#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000683 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000684#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000685 print1opt("-x", "--nohelp", _("Don't show help window"));
686 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000687
688 /* this is a special case */
689 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000690
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000691 exit(0);
692}
693
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000694void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000695{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000696 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000697 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000698 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000699 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000700 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000701
Chris Allegrettae6600372003-01-17 03:39:41 +0000702#ifndef ENABLE_NLS
703 printf(" --disable-nls");
704#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000705#ifdef DEBUG
706 printf(" --enable-debug");
707#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000708#ifdef NANO_EXTRA
709 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000710#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000711#ifdef NANO_SMALL
712 printf(" --enable-tiny");
713#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000714#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000715 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000716#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000717#ifdef DISABLE_HELP
718 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000719#endif
720#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000721 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000722#endif
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000723#ifdef DISABLE_MOUSE
Chris Allegretta84de5522001-04-12 14:51:48 +0000724 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000725#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000726#ifdef DISABLE_OPERATINGDIR
727 printf(" --disable-operatingdir");
728#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000729#ifdef DISABLE_SPELLER
730 printf(" --disable-speller");
731#endif
732#ifdef DISABLE_TABCOMP
733 printf(" --disable-tabcomp");
734#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000735#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000736#ifdef DISABLE_WRAPPING
737 printf(" --disable-wrapping");
738#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000739#ifdef DISABLE_ROOTWRAP
740 printf(" --disable-wrapping-as-root");
741#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000742#ifdef ENABLE_COLOR
743 printf(" --enable-color");
744#endif
745#ifdef ENABLE_MULTIBUFFER
746 printf(" --enable-multibuffer");
747#endif
748#ifdef ENABLE_NANORC
749 printf(" --enable-nanorc");
750#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000751#ifdef USE_SLANG
752 printf(" --with-slang");
753#endif
754 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000755}
756
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000757/* Stuff we do when we abort from programs and want to clean up the
758 * screen. This doesn't do much right now. */
759void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000760{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000761 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000762}
763
764int no_help(void)
765{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000766 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000767}
768
Chris Allegrettad865da12002-07-29 23:46:38 +0000769#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000770void nano_disabled_msg(void)
771{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000772 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000773}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000774#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000775
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000776#ifndef NANO_SMALL
777static int pid; /* This is the PID of the newly forked process
778 * below. It must be global since the signal
779 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000780RETSIGTYPE cancel_fork(int signal)
781{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000782 if (kill(pid, SIGKILL) == -1)
783 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000784}
785
786int open_pipe(const char *command)
787{
788 int fd[2];
789 FILE *f;
790 struct sigaction oldaction, newaction;
791 /* original and temporary handlers for SIGINT */
792#ifdef _POSIX_VDISABLE
793 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000794#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000795 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000796 /* cancel_sigs == 1 means that sigaction() failed without changing
797 * the signal handlers. cancel_sigs == 2 means the signal handler
798 * was changed, but the tcsetattr didn't succeed.
799 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000800 * I use this variable since it is important to put things back when
801 * we finish, even if we get errors. */
802
803 /* Make our pipes. */
804
805 if (pipe(fd) == -1) {
806 statusbar(_("Could not pipe"));
807 return 1;
808 }
809
810 /* Fork a child. */
811
812 if ((pid = fork()) == 0) {
813 close(fd[0]);
814 dup2(fd[1], fileno(stdout));
815 dup2(fd[1], fileno(stderr));
816 /* If execl() returns at all, there was an error. */
817
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000818 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000819 exit(0);
820 }
821
822 /* Else continue as parent. */
823
824 close(fd[1]);
825
826 if (pid == -1) {
827 close(fd[0]);
828 statusbar(_("Could not fork"));
829 return 1;
830 }
831
832 /* Before we start reading the forked command's output, we set
833 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000834 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000835 cancel_sigs = 1;
836 nperror("sigaction");
837 } else {
838 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000839 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000840 cancel_sigs = 1;
841 nperror("sigaction");
842 }
843 }
844 /* Note that now oldaction is the previous SIGINT signal handler,
845 * to be restored later. */
846
847 /* See if the platform supports disabling individual control
848 * characters. */
849#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000850 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000851 cancel_sigs = 2;
852 nperror("tcgetattr");
853 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000854 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000855 newterm = term;
856 /* Grab oldterm's VINTR key :-) */
857 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
858 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
859 cancel_sigs = 2;
860 nperror("tcsetattr");
861 }
862 }
863#endif /* _POSIX_VDISABLE */
864
865 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000866 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000867 nperror("fdopen");
868
869 read_file(f, "stdin", 0);
870 /* if multibuffer mode is on, we could be here in view mode; if so,
871 don't set the modification flag */
872 if (!ISSET(VIEW_MODE))
873 set_modified();
874
875 if (wait(NULL) == -1)
876 nperror("wait");
877
878#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000879 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000880 nperror("tcsetattr");
881#endif /* _POSIX_VDISABLE */
882
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000883 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000884 nperror("sigaction");
885
886 return 0;
887}
888#endif /* NANO_SMALL */
889
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +0000890#ifndef DISABLE_MOUSE
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000891void do_mouse(void)
892{
893 MEVENT mevent;
894 int currslen;
895 const shortcut *s = currshortcut;
896
897 if (getmouse(&mevent) == ERR)
898 return;
899
900 /* If mouse not in edit or bottom window, return */
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000901 if (wenclose(edit, mevent.y, mevent.x) && currshortcut == main_list) {
902 int sameline;
903 /* Did they click on the line with the cursor? If they
904 clicked on the cursor, we set the mark. */
905 size_t xcur;
906 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000907
908 /* Subtract out size of topwin. Perhaps we need a constant
909 * somewhere? */
910 mevent.y -= 2;
911
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000912 sameline = mevent.y == current_y;
913
914 /* Move to where the click occurred. */
915 for(; current_y < mevent.y && current->next != NULL; current_y++)
916 current = current->next;
917 for(; current_y > mevent.y && current->prev != NULL; current_y--)
918 current = current->prev;
919
David Lawrence Ramsey5ffbec52003-09-16 01:16:49 +0000920 xcur = actual_x(current->data, get_page_start(xplustabs()) + mevent.x);
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000921
922 /* Selecting where the cursor is toggles the mark. As does
923 selecting beyond the line length with the cursor at the end of
924 the line. */
925 if (sameline && xcur == current_x) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000926 if (ISSET(VIEW_MODE)) {
927 print_view_warning();
928 return;
929 }
930 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000931 }
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000932
933 current_x = xcur;
934 placewewant = xplustabs();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000935 edit_refresh();
936 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
937 int i, k;
938
939 if (currshortcut == main_list)
940 currslen = MAIN_VISIBLE;
941 else
942 currslen = length_of_list(currshortcut);
943
944 if (currslen < 2)
945 k = COLS / 6;
946 else
947 k = COLS / ((currslen + (currslen %2)) / 2);
948
949 /* Determine what shortcut list was clicked */
950 mevent.y -= (editwinrows + 3);
951
952 if (mevent.y < 0) /* They clicked on the statusbar */
953 return;
954
955 /* Don't select stuff beyond list length */
956 if (mevent.x / k >= currslen)
957 return;
958
959 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
960 s = s->next;
961
962 /* And ungetch that value */
963 ungetch(s->val);
964
965 /* And if it's an alt-key sequence, we should probably send alt
966 too ;-) */
967 if (s->val >= 'a' && s->val <= 'z')
968 ungetch(27);
969 }
970}
971#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000972
Chris Allegretta6df90f52002-07-19 01:08:59 +0000973/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000974void do_char(char ch)
975{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000976 size_t current_len = strlen(current->data);
977#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
978 int refresh = 0;
979 /* Do we have to run edit_refresh(), or can we get away with
980 * update_line()? */
981#endif
982
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000983 /* magic-line: when a character is inserted on the current magic line,
984 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000985 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000986 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000987 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000988 }
989
Chris Allegretta6df90f52002-07-19 01:08:59 +0000990 /* more dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000991 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000992 assert(current_x <= current_len);
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +0000993 charmove(&current->data[current_x + 1],
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000994 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +0000995 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000996 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000997 totsize++;
998 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000999
Chris Allegretta6df90f52002-07-19 01:08:59 +00001000#ifndef NANO_SMALL
1001 /* note that current_x has not yet been incremented */
1002 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001003 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001004#endif
1005
Chris Allegretta6df90f52002-07-19 01:08:59 +00001006 do_right();
1007
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001008#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001009 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001010 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001011#endif
1012
Chris Allegretta6df90f52002-07-19 01:08:59 +00001013#ifdef ENABLE_COLOR
1014 refresh = 1;
1015#endif
1016
1017#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1018 if (refresh)
1019 edit_refresh();
1020#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001021}
1022
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001023int do_backspace(void)
1024{
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001025 if (current != fileage || current_x > 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001026 do_left();
David Lawrence Ramseyd91ab6e2003-09-07 23:57:24 +00001027 do_delete();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001028 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001029 return 1;
1030}
1031
1032int do_delete(void)
1033{
1034 int refresh = 0;
1035
1036 /* blbf -> blank line before filebot (see below) */
1037 int blbf = 0;
1038
1039 if (current->next == filebot && current->data[0] == '\0')
1040 blbf = 1;
1041
1042 placewewant = xplustabs();
1043
1044 if (current_x != strlen(current->data)) {
1045 /* Let's get dangerous */
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00001046 charmove(&current->data[current_x], &current->data[current_x + 1],
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001047 strlen(current->data) - current_x);
1048
1049 align(&current->data);
1050#ifdef ENABLE_COLOR
1051 refresh = 1;
1052#endif
1053 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1054 /* We can delete the line before filebot only if it is blank: it
1055 becomes the new magic line then. */
1056
1057 filestruct *foo;
1058
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001059 current->data = charealloc(current->data,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001060 strlen(current->data) +
1061 strlen(current->next->data) + 1);
1062 strcat(current->data, current->next->data);
1063
1064 foo = current->next;
1065 if (filebot == foo) {
1066 filebot = current;
1067 editbot = current;
1068 }
1069
1070 unlink_node(foo);
1071 delete_node(foo);
1072 renumber(current);
1073 totlines--;
1074 refresh = 1;
1075 } else
1076 return 0;
1077
1078 totsize--;
1079 set_modified();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001080 update_line(current, current_x);
1081 if (refresh)
1082 edit_refresh();
1083 return 1;
1084}
1085
1086int do_tab(void)
1087{
1088 do_char('\t');
1089 return 1;
1090}
1091
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001092/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001093int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001094{
Chris Allegrettae3167732001-03-18 16:59:34 +00001095 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001096 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001097
Chris Allegretta6df90f52002-07-19 01:08:59 +00001098 newnode = make_new_node(current);
1099 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001100 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001101
Chris Allegrettaff989832001-09-17 13:48:00 +00001102#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001103 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001104 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001105 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001106 const char *spc = current->data;
1107
1108 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001109 extra++;
1110 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001111 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001112 /* If current_x < extra, then we are breaking the line in the
1113 * indentation. Autoindenting should add only current_x
1114 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001115 if (current_x < extra)
1116 extra = current_x;
1117 else
1118 current_x = extra;
1119 totsize += extra;
1120
1121 newnode->data = charalloc(strlen(tmp) + extra + 1);
1122 strncpy(newnode->data, current->data, extra);
1123 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001124 } else
1125#endif
1126 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001127 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001128 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001129 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001130 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001131 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001132
Chris Allegretta6df90f52002-07-19 01:08:59 +00001133 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001134 filebot = newnode;
1135 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001136 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001137 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001138
1139 totsize++;
1140 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001141 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001142 align(&current->data);
1143
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001144 /* The logic here is as follows:
1145 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001146 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001147 * -> otherwise, we want simply to redraw the screen and update
1148 * where we think the cursor is.
1149 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001150 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001151#ifndef NANO_SMALL
1152 if (ISSET(SMOOTHSCROLL))
1153 edit_update(current, NONE);
1154 else
1155#endif
1156 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001157 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001158 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001159 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001160 edit_refresh();
1161 update_cursor();
1162 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001163
1164 totlines++;
1165 set_modified();
1166
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001167 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001168 return 1;
1169}
1170
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001171#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001172int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001173{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001174 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178 /* Skip letters in this word first. */
1179 while (current->data[current_x] != '\0' &&
1180 isalnum((int)current->data[current_x]))
1181 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182
Chris Allegretta6df90f52002-07-19 01:08:59 +00001183 for (; current != NULL; current = current->next) {
1184 while (current->data[current_x] != '\0' &&
1185 !isalnum((int)current->data[current_x]))
1186 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187
Chris Allegretta6df90f52002-07-19 01:08:59 +00001188 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189 break;
1190
Chris Allegretta6df90f52002-07-19 01:08:59 +00001191 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001192 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001193 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001194 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001195
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001196 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001197
Chris Allegrettad865da12002-07-29 23:46:38 +00001198 if (current->lineno >= editbot->lineno) {
1199 /* If we're on the last line, don't center the screen. */
1200 if (current->lineno == filebot->lineno)
1201 edit_refresh();
1202 else
1203 edit_update(current, CENTER);
1204 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001205 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001206 /* If we've jumped lines, refresh the old line. We can't just
1207 use current->prev here, because we may have skipped over some
1208 blank lines, in which case the previous line is the wrong
1209 one. */
1210 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001211 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001212 /* If the mark was set, then the lines between old and
1213 current have to be updated too. */
1214 if (ISSET(MARK_ISSET)) {
1215 while (old->next != current) {
1216 old = old->next;
1217 update_line(old, 0);
1218 }
1219 }
1220 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001221 update_line(current, current_x);
1222 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001223 return 0;
1224}
1225
Chris Allegretta6df90f52002-07-19 01:08:59 +00001226/* The same thing for backwards. */
1227int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001228{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001229 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001230
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001231 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001232
Chris Allegretta6df90f52002-07-19 01:08:59 +00001233 /* Skip letters in this word first. */
1234 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1235 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001236
Chris Allegretta6df90f52002-07-19 01:08:59 +00001237 for (; current != NULL; current = current->prev) {
1238 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1239 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001240
Chris Allegretta6df90f52002-07-19 01:08:59 +00001241 if (current_x >= 0)
1242 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001243
Chris Allegretta6df90f52002-07-19 01:08:59 +00001244 if (current->prev != NULL)
1245 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001246 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001247
Chris Allegretta6df90f52002-07-19 01:08:59 +00001248 if (current != NULL) {
1249 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1250 current_x--;
1251 } else {
1252 current = fileage;
1253 current_x = 0;
1254 }
1255
Chris Allegretta76e291b2001-10-14 19:05:10 +00001256 placewewant = xplustabs();
1257
Chris Allegrettad865da12002-07-29 23:46:38 +00001258 if (current->lineno <= edittop->lineno) {
1259 /* If we're on the first line, don't center the screen. */
1260 if (current->lineno == fileage->lineno)
1261 edit_refresh();
1262 else
1263 edit_update(current, CENTER);
1264 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001265 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001266 /* If we've jumped lines, refresh the old line. We can't just
1267 use current->prev here, because we may have skipped over some
1268 blank lines, in which case the previous line is the wrong
1269 one. */
1270 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001271 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001272 /* If the mark was set, then the lines between old and
1273 current have to be updated too. */
1274 if (ISSET(MARK_ISSET)) {
1275 while (old->prev != current) {
1276 old = old->prev;
1277 update_line(old, 0);
1278 }
1279 }
1280 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001281 update_line(current, current_x);
1282 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001283 return 0;
1284}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001285#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001286
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001287int do_mark(void)
1288{
1289#ifdef NANO_SMALL
1290 nano_disabled_msg();
1291#else
David Lawrence Ramseyf03c78b2003-09-28 21:26:49 +00001292 TOGGLE(MARK_ISSET);
1293 if (ISSET(MARK_ISSET)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001294 statusbar(_("Mark Set"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001295 mark_beginbuf = current;
1296 mark_beginx = current_x;
1297 } else {
1298 statusbar(_("Mark UNset"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001299 edit_refresh();
1300 }
1301#endif
1302 return 1;
1303}
1304
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001305#ifndef DISABLE_WRAPPING
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001306void wrap_reset(void)
1307{
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001308 same_line_wrap = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001309}
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001310#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001311
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001312#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001313/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001314 * moved forward since the last typed character. Return value:
1315 * whether we wrapped. */
1316int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001317{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001318 size_t len = strlen(inptr->data); /* length of the line we wrap */
1319 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001320 int wrap_loc = -1; /* index of inptr->data where we wrap */
1321 int word_back = -1;
1322#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001323 const char *indentation = NULL;
1324 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001325 int indent_len = 0; /* strlen(indentation) */
1326#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001327 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001328 int after_break_len; /* strlen(after_break) */
1329 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001330 const char *wrap_line = NULL;
1331 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001332 int wrap_line_len = 0; /* strlen(wrap_line) */
1333 char *newline = NULL; /* the line we create */
1334 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001335
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001336/* There are three steps. First, we decide where to wrap. Then, we
1337 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001338
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001339/* Step 1, finding where to wrap. We are going to add a new-line
1340 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001341 * location of this replacement.
1342 *
1343 * Where should we break the line? We need the last "legal wrap point"
1344 * such that the last word before it ended at or before fill. If there
1345 * is no such point, we settle for the first legal wrap point.
1346 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001347 * A "legal wrap point" is a white-space character that is not followed by
1348 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001349 *
1350 * If there is no legal wrap point or we found the last character of the
1351 * line, we should return without wrapping.
1352 *
1353 * Note that the initial indentation does not count as a legal wrap
1354 * point if we are going to auto-indent!
1355 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001356 * Note that the code below could be optimised, by not calling strnlenpt()
1357 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001358
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001359#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001360 if (ISSET(AUTOINDENT))
1361 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001362#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001363 wrap_line = inptr->data + i;
1364 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001365 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001366 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001367 word_back = i;
1368 /* if we have found a "legal wrap point" and the current word
1369 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001370 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001371 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001372 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001373 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001374 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001375 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001376 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001377 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001378
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001379/* Step 2, making the new wrap line. It will consist of indentation +
1380 * after_break + " " + wrap_line (although indentation and wrap_line are
1381 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001382
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001383 /* after_break is the text that will be moved to the next line. */
1384 after_break = inptr->data + wrap_loc + 1;
1385 after_break_len = len - wrap_loc - 1;
1386 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001387
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001388 /* new_line_len will later be increased by the lengths of indentation
1389 * and wrap_line. */
1390 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001391
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001392 /* We prepend the wrapped text to the next line, if the flag is set,
1393 * and there is a next line, and prepending would not make the line
1394 * too long. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001395 if (same_line_wrap && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001396 wrap_line = inptr->next->data;
1397 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001398
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001399 /* +1 for the space between after_break and wrap_line */
1400 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1401 wrapping = 1;
1402 new_line_len += (1 + wrap_line_len);
1403 }
1404 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001405
Chris Allegrettaff989832001-09-17 13:48:00 +00001406#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001407 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001408 /* Indentation comes from the next line if wrapping, else from
1409 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001410 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001411 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001412 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001413 /* The wrap_line text should not duplicate indentation.
1414 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001415 wrap_line += indent_len;
1416 else
1417 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001418 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001419#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001420
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001421 /* Now we allocate the new line and copy into it. */
1422 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1423 *newline = '\0';
1424
1425#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001426 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001427 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001428 newline[indent_len] = '\0';
1429 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001430#endif
1431 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001432 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001433 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001434 null_at(&inptr->data, wrap_loc + 1);
1435 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001436 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001437 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001438 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001439 * in a tab or a space, we don't add a space and decrement
1440 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001441 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001442 strcat(newline, " ");
1443 else
1444 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001445 strcat(newline, wrap_line);
1446 free(inptr->next->data);
1447 inptr->next->data = newline;
1448 } else {
1449 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001450
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001451 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001452 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001453#ifndef NANO_SMALL
1454 totsize += indent_len;
1455#endif
1456 totlines++;
1457 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001458 temp->prev = inptr;
1459 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001460 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001461 /* If temp->next is NULL, then temp is the last line of the
1462 * file, so we must set filebot. */
1463 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001464 temp->next->prev = temp;
1465 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001466 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001467 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001468
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001469/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1470 * other sundry things. */
1471
1472 /* later wraps of this line will be prepended to the next line. */
David Lawrence Ramseyc97acfb2003-09-10 20:08:00 +00001473 same_line_wrap = 1;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001474
1475 /* Each line knows its line number. We recalculate these if we
1476 * inserted a new line. */
1477 if (!wrapping)
1478 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001479
Chris Allegretta6df90f52002-07-19 01:08:59 +00001480 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001481 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001482 current = current->next;
1483 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001484#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001485 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001486#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001487 wrap_loc + 1;
1488 wrap_reset();
1489 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001490 }
1491
Chris Allegretta6df90f52002-07-19 01:08:59 +00001492#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001493 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001494 * If it was on the next line and we wrapped, we must move it
1495 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001496 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1497 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001498 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001499 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001500 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001501#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001502
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001503 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001504 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001505
1506 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001507}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001508#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001509
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001510#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001511/* A word is misspelled in the file. Let the user replace it. We
1512 * return False if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001513int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001514{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001515 char *save_search;
1516 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001517 filestruct *current_save = current;
1518 int current_x_save = current_x;
1519 filestruct *edittop_save = edittop;
1520 /* Save where we are. */
1521 int i = 0;
1522 /* The return value. */
1523 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001524#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001525 int case_sens_set = ISSET(CASE_SENSITIVE);
1526 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001527
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001528 SET(CASE_SENSITIVE);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001529 /* Make sure the marking highlight is off during Spell Check */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001530 UNSET(MARK_ISSET);
1531#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001532 /* Make sure Spell Check goes forward only */
1533 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001534
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001535 /* save the current search/replace strings */
1536 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001537 save_search = last_search;
1538 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001539
1540 /* set search/replace strings to mis-spelt word */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001541 last_search = mallocstrcpy(NULL, word);
1542 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001543
1544 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001545 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001546 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001547
1548 search_last_line = FALSE;
1549
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001550 /* We find the first whole-word occurrence of word. */
1551 while (findnextstr(TRUE, TRUE, fileage, -1, word))
1552 if (is_whole_word(current_x, current->data, word)) {
1553 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001554
Chris Allegretta6df90f52002-07-19 01:08:59 +00001555 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001556
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001557 /* allow replace word to be corrected */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001558 i = statusq(0, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001559#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001560 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001561#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001562 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001563
Chris Allegretta6df90f52002-07-19 01:08:59 +00001564 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001565
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001566 if (i != -1 && strcmp(word, answer)) {
1567 int j = 0;
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001568
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001569 search_last_line = FALSE;
1570 current_x--;
1571 do_replace_loop(word, current_save, &current_x_save, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001572 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001573
1574 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001575 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001576
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001577 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001578 free(last_search); last_search=save_search;
1579 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001580
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001581 /* restore where we were */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001582 current = current_save;
1583 current_x = current_x_save;
1584 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001585
Chris Allegretta23b74b22002-01-21 20:32:22 +00001586 /* restore Search/Replace direction */
1587 if (reverse_search_set)
1588 SET(REVERSE_SEARCH);
1589
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001590#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001591 if (!case_sens_set)
1592 UNSET(CASE_SENSITIVE);
1593
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001594 /* restore marking highlight */
1595 if (mark_set)
1596 SET(MARK_ISSET);
1597#endif
1598
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001599 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001600}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001601
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001602/* Integrated spell checking using 'spell' program. Return value: NULL
1603 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001604char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001605{
Chris Allegretta271e9722000-11-10 18:15:43 +00001606 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001607 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001608 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001609 pid_t pid_spell, pid_sort, pid_uniq;
1610 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001611
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001612 /* Create all three pipes up front */
Chris Allegretta271e9722000-11-10 18:15:43 +00001613
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001614 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1615 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001616
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001617 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001618 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001619
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001620 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001621
1622 /* Child continues, (i.e. future spell process) */
1623
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001624 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001625
Chris Allegretta271e9722000-11-10 18:15:43 +00001626 /* replace the standard in with the tempfile */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001627 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1628 goto close_pipes_and_exit;
1629
1630 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1631 goto close_pipes_and_exit;
1632
Chris Allegretta271e9722000-11-10 18:15:43 +00001633 close(tempfile_fd);
1634
1635 /* send spell's standard out to the pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001636 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1637 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001638
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001639 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001640
1641 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001642 execlp("spell", "spell", NULL);
1643
Chris Allegretta271e9722000-11-10 18:15:43 +00001644 /* Should not be reached, if spell is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001645 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001646 }
1647
1648 /* Parent continues here */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001649 close(spell_fd[1]);
1650
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001651 /* A new process to run sort in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001652 if ((pid_sort = fork()) == 0) {
1653
1654 /* Child continues, (i.e. future spell process) */
1655 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001656 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1657 goto close_pipes_and_exit;
1658
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001659 close(spell_fd[0]);
1660
1661 /* send sort's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001662 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1663 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001664
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001665 close(sort_fd[1]);
1666
1667 /* Start sort program. Use -f to remove mixed case without having
1668 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1669 execlp("sort", "sort", "-f", NULL);
1670
1671 /* Should not be reached, if sort is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001672 exit(1);
1673 }
1674
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001675 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001676 close(sort_fd[1]);
1677
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001678 /* A new process to run uniq in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001679 if ((pid_uniq = fork()) == 0) {
1680
1681 /* Child continues, (i.e. future uniq process) */
1682 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001683 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1684 goto close_pipes_and_exit;
1685
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001686 close(sort_fd[0]);
1687
1688 /* send uniq's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001689 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1690 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001691
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001692 close(uniq_fd[1]);
1693
1694 /* Start uniq program, we are using PATH */
1695 execlp("uniq", "uniq", NULL);
1696
1697 /* Should not be reached, if uniq is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001698 exit(1);
1699 }
1700
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001701 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001702 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001703
1704 /* Child process was not forked successfully */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001705 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1706 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001707 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001708 }
1709
Chris Allegretta271e9722000-11-10 18:15:43 +00001710 /* Get system pipe buffer size */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001711 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1712 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001713 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001714 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001715
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001716 /* Read-in the returned spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001717 read_buff_read = 0;
1718 read_buff_size = pipe_buff_size + 1;
1719 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001720
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001721 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001722 read_buff_read += bytesread;
1723 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001724 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001725 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001726
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001727 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001728
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001729 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001730 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001731
1732 /* Process the spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001733 read_buff_word = read_buff_ptr = read_buff;
1734
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001735 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001736
1737 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001738 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001739 if (read_buff_word != read_buff_ptr) {
1740 if (!do_int_spell_fix(read_buff_word)) {
1741 read_buff_word = read_buff_ptr;
1742 break;
1743 }
1744 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001745 read_buff_word = read_buff_ptr + 1;
1746 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001747 read_buff_ptr++;
1748 }
1749
1750 /* special case where last word doesn't end with \n or \r */
1751 if (read_buff_word != read_buff_ptr)
1752 do_int_spell_fix(read_buff_word);
1753
Chris Allegretta271e9722000-11-10 18:15:43 +00001754 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001755 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001756 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001757
Chris Allegretta271e9722000-11-10 18:15:43 +00001758 /* Process end of spell process */
1759
Chris Allegretta334a9402002-12-16 04:25:53 +00001760 waitpid(pid_spell, &spell_status, 0);
1761 waitpid(pid_sort, &sort_status, 0);
1762 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001763
Chris Allegretta334a9402002-12-16 04:25:53 +00001764 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1765 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001766
Chris Allegretta334a9402002-12-16 04:25:53 +00001767 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1768 return _("Error invoking \"sort -f\"");
1769
1770 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1771 return _("Error invoking \"uniq\"");
1772
1773 /* Otherwise... */
1774 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001775
1776close_pipes_and_exit:
1777
1778 /* Don't leak any handles */
1779 close(tempfile_fd);
1780 close(spell_fd[0]);
1781 close(spell_fd[1]);
1782 close(sort_fd[0]);
1783 close(sort_fd[1]);
1784 close(uniq_fd[0]);
1785 close(uniq_fd[1]);
1786 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001787}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001788
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001789/* External spell checking. Return value: NULL for normal termination,
1790 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001791char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001792{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001793 int alt_spell_status, lineno_cur = current->lineno;
1794 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001795 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001796 char *ptr;
1797 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001798 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001799#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001800 int mark_set = ISSET(MARK_ISSET);
1801 int mbb_lineno_cur = 0;
1802 /* We're going to close the current file, and open the output of
1803 the alternate spell command. The line that mark_beginbuf
1804 points to will be freed, so we save the line number and restore
1805 afterwards. */
1806
1807 if (mark_set) {
1808 mbb_lineno_cur = mark_beginbuf->lineno;
1809 UNSET(MARK_ISSET);
1810 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001811#endif
1812
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001813 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001814
Chris Allegrettae434b452001-01-27 19:25:00 +00001815 /* Set up an argument list to pass the execvp function */
1816 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001817 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001818
Chris Allegrettae434b452001-01-27 19:25:00 +00001819 spellargs[0] = strtok(alt_speller, " ");
1820 while ((ptr = strtok(NULL, " ")) != NULL) {
1821 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001822 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001823 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001824 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001825 spellargs[arglen - 1] = NULL;
1826 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001827 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001828
1829 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001830 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001831 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001832 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001833
1834 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001835 exit(1);
1836 }
1837
1838 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001839 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001840 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001841
1842 /* Wait for alternate speller to complete */
1843
1844 wait(&alt_spell_status);
Chris Allegretta334a9402002-12-16 04:25:53 +00001845 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1846 char *altspell_error = NULL;
1847 char *invoke_error = _("Could not invoke \"%s\"");
1848 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1849
1850 altspell_error = charalloc(msglen);
1851 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1852 return altspell_error;
1853 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001854
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001855 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001856 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001857 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001858 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001859
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001860#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001861 if (mark_set) {
1862 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1863 mark_beginbuf = current;
1864 mark_beginx = current_x;
1865 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001866 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001867 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001868#endif
1869
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001870 /* go back to the old position, mark the file as modified, and make
1871 sure that the titlebar is refreshed */
1872 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001873 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001874 clearok(topwin, FALSE);
1875 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001876
Chris Allegretta334a9402002-12-16 04:25:53 +00001877 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001878}
1879#endif
1880
1881int do_spell(void)
1882{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001883#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001884 nano_disabled_msg();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001885 return TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001886#else
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001887 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001888
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001889 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001890 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001891 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001892 return 0;
1893 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001894
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001895 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001896 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001897 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001898 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001899 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001900
Chris Allegrettae1f14522001-09-19 03:19:43 +00001901#ifdef ENABLE_MULTIBUFFER
1902 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001903 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00001904 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001905#endif
1906
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001907 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001908 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001909 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001910 spell_msg = do_int_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001911 remove(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001912 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001913
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001914 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001915 statusbar(_("Spell checking failed: %s"), spell_msg);
1916 return 0;
1917 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001918
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001919 statusbar(_("Finished checking spelling"));
1920 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001921#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001922}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001923
Chris Allegrettad865da12002-07-29 23:46:38 +00001924#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001925/* The "indentation" of a line is the white-space between the quote part
1926 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001927size_t indent_length(const char *line)
1928{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001929 size_t len = 0;
1930
1931 assert(line != NULL);
1932 while (*line == ' ' || *line == '\t') {
1933 line++;
1934 len++;
1935 }
1936 return len;
1937}
Chris Allegrettadffa2072002-07-24 01:02:26 +00001938#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001939
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001940#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00001941/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
1942 * it maintains 2 after a . ! or ?). Note the terminating \0
1943 * counts as a space.
1944 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001945 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00001946 * returns 1, otherwise returns 0.
1947 *
1948 * If changes_allowed, justify_format() might make line->data
1949 * shorter, and change the actual pointer with null_at().
1950 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00001951 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001952 * skip should be at most strlen(line->data). The skip+1st character must
1953 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001954int justify_format(int changes_allowed, filestruct *line, size_t skip)
1955{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001956 const char *punct = ".?!";
1957 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00001958 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001959
Chris Allegretta6df90f52002-07-19 01:08:59 +00001960 /* These four asserts are assumptions about the input data. */
1961 assert(line != NULL);
1962 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00001963 assert(skip < strlen(line->data));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001964 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001965
Chris Allegretta6df90f52002-07-19 01:08:59 +00001966 back = line->data + skip;
1967 front = back;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001968 for (front = back; ; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001969 int remove_space = 0;
1970 /* Do we want to remove this space? */
1971
Chris Allegretta6df90f52002-07-19 01:08:59 +00001972 if (*front == '\t') {
1973 if (!changes_allowed)
1974 return 1;
1975 *front = ' ';
1976 }
1977 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001978 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001979 const char *bob = front - 2;
1980
1981 remove_space = 1;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00001982 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001983 if (strchr(punct, *bob) != NULL) {
1984 remove_space = 0;
1985 break;
1986 }
1987 if (strchr(brackets, *bob) == NULL)
1988 break;
1989 }
1990 }
1991
1992 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001993 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00001994 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001995 if (!changes_allowed)
1996 return 1;
1997#ifndef NANO_SMALL
1998 if (mark_beginbuf == line && back - line->data < mark_beginx)
1999 mark_beginx--;
2000#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002001 if (*front == '\0')
2002 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002003 } else {
2004 *back = *front;
2005 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002006 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002007 if (*front == '\0')
2008 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002009 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002010
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002011 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00002012 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00002013
2014 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002015 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002016
2017 /* Now back is the new end of line->data. */
2018 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00002019 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002020 null_at(&line->data, back - line->data);
2021#ifndef NANO_SMALL
2022 if (mark_beginbuf == line && back - line->data < mark_beginx)
2023 mark_beginx = back - line->data;
2024#endif
2025 }
2026 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002027}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002028
2029/* The "quote part" of a line is the largest initial substring matching
2030 * the quote string. This function returns the length of the quote part
2031 * of the given line.
2032 *
2033 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2034 * quotestr. */
2035#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002036size_t quote_length(const char *line, const regex_t *qreg)
2037{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002038 regmatch_t matches;
2039 int rc = regexec(qreg, line, 1, &matches, 0);
2040
2041 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2042 return 0;
2043 /* matches.rm_so should be 0, since the quote string should start with
2044 * the caret ^. */
2045 return matches.rm_eo;
2046}
2047#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002048size_t quote_length(const char *line)
2049{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002050 size_t qdepth = 0;
2051 size_t qlen = strlen(quotestr);
2052
2053 /* Compute quote depth level */
2054 while (!strcmp(line + qdepth, quotestr))
2055 qdepth += qlen;
2056 return qdepth;
2057}
2058#endif /* !HAVE_REGEX_H */
2059
Chris Allegretta6df90f52002-07-19 01:08:59 +00002060/* a_line and b_line are lines of text. The quotation part of a_line is
2061 * the first a_quote characters. Check that the quotation part of
2062 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002063int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002064 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002065{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002066 /* Here is the assumption about a_quote: */
2067 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002068 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002069 !strncmp(a_line, b_line, a_quote);
2070}
2071
2072/* We assume a_line and b_line have no quote part. Then, we return whether
2073 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002074size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002075 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002076{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002077 assert(a_indent == indent_length(a_line));
2078 assert(b_indent == indent_length(b_line));
2079
2080 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2081}
2082
2083/* Put the next par_len lines, starting with first_line, in the cut
2084 * buffer. We assume there are enough lines after first_line. We leave
2085 * copies of the lines in place, too. We return the new copy of
2086 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002087filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002088 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002089{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002090 /* We put the original lines, not copies, into the cut buffer, just
2091 * out of a misguided sense of consistency, so if you un-cut, you
2092 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002093 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002094
2095 set_modified();
2096 cutbuffer = NULL;
2097 for(; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002098 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002099
Chris Allegretta908f7702003-01-15 11:18:58 +00002100 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002101 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002102 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002103 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002104 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002105 edittop = bob;
2106#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002107 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002108 mark_beginbuf = bob;
2109#endif
2110 justify_format(1, bob,
2111 quote_len + indent_length(bob->data + quote_len));
2112
Chris Allegretta908f7702003-01-15 11:18:58 +00002113 assert(alice != NULL && bob != NULL);
2114 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002115 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002116 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002117 }
2118 return first_line;
2119}
2120
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002121/* Is it possible to break line at or before goal? */
2122int breakable(const char *line, int goal)
2123{
2124 for(; *line != '\0' && goal >= 0; line++) {
2125 if (*line == ' ' || *line == '\t')
2126 return TRUE;
2127
2128 if (is_cntrl_char(*line) != 0)
2129 goal -= 2;
2130 else
2131 goal -= 1;
2132 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002133 /* If goal is not negative, the whole line (one word) was short
2134 * enough. */
2135 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002136}
2137
Chris Allegretta6df90f52002-07-19 01:08:59 +00002138/* We are trying to break a chunk off line. We find the last space such
2139 * that the display length to there is at most goal + 1. If there is
2140 * no such space, and force is not 0, then we find the first space.
2141 * Anyway, we then take the last space in that group of spaces. The
2142 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002143int break_line(const char *line, int goal, int force)
2144{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002145 /* Note that we use int instead of size_t, since goal is at most COLS,
2146 * the screen width, which will always be reasonably small. */
2147 int space_loc = -1;
2148 /* Current tentative return value. Index of the last space we
2149 * found with short enough display width. */
2150 int cur_loc = 0;
2151 /* Current index in line */
2152
2153 assert(line != NULL);
2154 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2155 if (*line == ' ')
2156 space_loc = cur_loc;
2157 assert(*line != '\t');
2158
Chris Allegrettacf287c82002-07-20 13:57:41 +00002159 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002160 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002161 else
2162 goal--;
2163 }
2164 if (goal >= 0)
2165 /* In fact, the whole line displays shorter than goal. */
2166 return cur_loc;
2167 if (space_loc == -1) {
2168 /* No space found short enough. */
2169 if (force)
2170 for(; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002171 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002172 return cur_loc;
2173 return -1;
2174 }
2175 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002176 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002177 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2178 *(line - cur_loc + space_loc + 1) == '\0')
2179 space_loc++;
2180 return space_loc;
2181}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002182
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002183/* This function performs operations on paragraphs: justify, go to
2184 * beginning, and go to end. */
2185int do_para_operation(int operation)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002186{
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002187/* operation == 0 means we're justifying the paragraph, operation == 1
2188 * means we're moving to the beginning line of the paragraph, and
2189 * operation == 2 means we're moving to the ending line of the
2190 * paragraph.
2191 *
2192 * To explain the justifying algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002193 * phrases about paragraphs and quotation:
2194 * A line of text consists of a "quote part", followed by an
2195 * "indentation part", followed by text. The functions quote_length()
2196 * and indent_length() calculate these parts.
2197 *
2198 * A line is "part of a paragraph" if it has a part not in the quote
2199 * part or the indentation.
2200 *
2201 * A line is "the beginning of a paragraph" if it is part of a paragraph
2202 * and
2203 * 1) it is the top line of the file, or
2204 * 2) the line above it is not part of a paragraph, or
2205 * 3) the line above it does not have precisely the same quote
2206 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002207 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002208 * indentation of the previous line, or
2209 * 5) this line has no quote part and some indentation, and
2210 * AUTOINDENT is not set.
2211 * The reason for number 5) is that if AUTOINDENT is not set, then an
2212 * indented line is expected to start a paragraph, like in books. Thus,
2213 * nano can justify an indented paragraph only if AUTOINDENT is turned
2214 * on.
2215 *
2216 * A contiguous set of lines is a "paragraph" if each line is part of
2217 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002218 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002219
Chris Allegretta6df90f52002-07-19 01:08:59 +00002220 size_t quote_len;
2221 /* Length of the initial quotation of the paragraph we justify. */
2222 size_t par_len;
2223 /* Number of lines in that paragraph. */
2224 filestruct *first_mod_line = NULL;
2225 /* Will be the first line of the resulting justified paragraph
2226 * that differs from the original. For restoring after uncut. */
2227 filestruct *last_par_line = current;
2228 /* Will be the last line of the result, also for uncut. */
2229 filestruct *cutbuffer_save = cutbuffer;
2230 /* When the paragraph gets modified, all lines from the changed
2231 * one down are stored in the cut buffer. We back up the original
2232 * to restore it later. */
2233
2234 /* We save these global variables to be restored if the user
2235 * unjustifies. Note we don't need to save totlines. */
2236 int current_x_save = current_x;
2237 int current_y_save = current_y;
2238 filestruct *current_save = current;
2239 int flags_save = flags;
2240 long totsize_save = totsize;
2241 filestruct *edittop_save = edittop;
2242 filestruct *editbot_save = editbot;
2243#ifndef NANO_SMALL
2244 filestruct *mark_beginbuf_save = mark_beginbuf;
2245 int mark_beginx_save = mark_beginx;
2246#endif
2247
2248 size_t indent_len; /* generic indentation length */
2249 filestruct *line; /* generic line of text */
2250 size_t i; /* generic loop variable */
2251
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002252 static int no_restart = 0;
2253 /* whether we're blocking restarting when searching for the
2254 * beginning line of the paragraph */
2255
Chris Allegretta6df90f52002-07-19 01:08:59 +00002256#ifdef HAVE_REGEX_H
2257 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002258 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002259 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2260
2261 if (rc) {
2262 size_t size = regerror(rc, &qreg, NULL, 0);
2263 char *strerror = charalloc(size);
2264
2265 regerror(rc, &qreg, strerror, size);
2266 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2267 free(strerror);
2268 return -1;
2269 }
2270#endif
2271
2272 /* Here is an assumption that is always true anyway. */
2273 assert(current != NULL);
2274
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002275 current_x = 0;
2276
2277 restart_bps:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002278/* Here we find the first line of the paragraph to justify. If the
2279 * current line is in a paragraph, then we move back to the first line.
2280 * Otherwise we move down to the first line that is in a paragraph. */
2281 quote_len = quote_length(IFREG(current->data, &qreg));
2282 indent_len = indent_length(current->data + quote_len);
2283
2284 if (current->data[quote_len + indent_len] != '\0') {
2285 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002286 * the first line of this paragraph. First we check items 1) and
2287 * 3) above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002288 while (current->prev != NULL && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002289 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002290 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002291 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002292 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002293
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002294 /* Is this line the beginning of a paragraph, according to
2295 items 2), 5), or 4) above? If so, stop. */
2296 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2297 (quote_len == 0 && indent_len > 0
2298#ifndef NANO_SMALL
2299 && !ISSET(AUTOINDENT)
2300#endif
2301 ) ||
2302 !indents_match(current->prev->data + quote_len,
2303 temp_id_len, current->data + quote_len, indent_len))
2304 break;
2305 indent_len = temp_id_len;
2306 current = current->prev;
2307 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002308 }
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002309 } else if (operation == 1) {
2310 /* This line is not part of a paragraph. Move up until we get
2311 * to a non "blank" line, and then move down once. */
2312 do {
2313 /* There is no previous paragraph, so nothing to move to. */
2314 if (current->prev == NULL) {
2315 placewewant = 0;
2316 if (current_y < 0)
2317 edit_update(current, CENTER);
2318 else
2319 edit_refresh();
2320 return 0;
2321 }
2322 current = current->prev;
2323 current_y--;
2324 quote_len = quote_length(IFREG(current->data, &qreg));
2325 indent_len = indent_length(current->data + quote_len);
2326 } while (current->data[quote_len + indent_len] == '\0');
2327 current = current->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002328 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002329 /* This line is not part of a paragraph. Move down until we get
2330 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002331 do {
2332 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002333 if (current->next == NULL) {
2334 placewewant = 0;
Chris Allegretta428f6202003-02-12 03:21:45 +00002335 edit_refresh();
2336#ifdef HAVE_REGEX_H
2337 regfree(&qreg);
2338#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002339 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002340 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002341 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002342 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002343 quote_len = quote_length(IFREG(current->data, &qreg));
2344 indent_len = indent_length(current->data + quote_len);
2345 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002346 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002347/* Now current is the first line of the paragraph, and quote_len
2348 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002349
Chris Allegretta6df90f52002-07-19 01:08:59 +00002350/* Next step, compute par_len, the number of lines in this paragraph. */
2351 line = current;
2352 par_len = 1;
2353 indent_len = indent_length(line->data + quote_len);
2354
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002355 while (line->next != NULL && quotes_match(current->data, quote_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002356 IFREG(line->next->data, &qreg))) {
2357 size_t temp_id_len = indent_length(line->next->data + quote_len);
2358
2359 if (!indents_match(line->data + quote_len, indent_len,
2360 line->next->data + quote_len, temp_id_len) ||
2361 line->next->data[quote_len + temp_id_len] == '\0' ||
2362 (quote_len == 0 && temp_id_len > 0
2363#ifndef NANO_SMALL
2364 && !ISSET(AUTOINDENT)
2365#endif
2366 ))
2367 break;
2368 indent_len = temp_id_len;
2369 line = line->next;
2370 par_len++;
2371 }
2372#ifdef HAVE_REGEX_H
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002373 /* We no longer need to check quotation, unless we're searching for
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002374 * the beginning of the paragraph. */
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002375 if (operation != 1)
2376 regfree(&qreg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002377#endif
2378/* Now par_len is the number of lines in this paragraph. Should never
2379 * call quotes_match() or quote_length() again. */
2380
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002381 /* If we're searching for the beginning of the paragraph, skip the
2382 * justification. If we're searching for the end of the paragraph,
2383 * move down the number of lines in the paragraph and skip the
2384 * justification. */
2385 if (operation == 1)
2386 goto skip_justify;
2387 else if (operation == 2) {
2388 while (par_len > 0) {
2389 current = current->next;
2390 current_y++;
2391 par_len--;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002392 }
2393 goto skip_justify;
2394 }
2395
Chris Allegretta6df90f52002-07-19 01:08:59 +00002396/* Next step, we loop through the lines of this paragraph, justifying
2397 * each one individually. */
Chris Allegretta8151ba52003-04-19 19:34:05 +00002398 SET(JUSTIFY_MODE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002399 for(; par_len > 0; current_y++, par_len--) {
2400 size_t line_len;
2401 size_t display_len;
2402 /* The width of current in screen columns. */
2403 int break_pos;
2404 /* Where we will break the line. */
2405
2406 indent_len = indent_length(current->data + quote_len) +
2407 quote_len;
2408 /* justify_format() removes excess spaces from the line, and
2409 * changes tabs to spaces. The first argument, 0, means don't
2410 * change the line, just say whether there are changes to be
2411 * made. If there are, we do backup_lines(), which copies the
2412 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002413 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002414 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002415 first_mod_line = backup_lines(current, par_len, quote_len);
2416
2417 line_len = strlen(current->data);
2418 display_len = strlenpt(current->data);
2419
2420 if (display_len > fill) {
2421 /* The line is too long. Try to wrap it to the next. */
2422 break_pos = break_line(current->data + indent_len,
2423 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002424 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002425 if (break_pos == -1 || break_pos + indent_len == line_len)
2426 /* We can't break the line, or don't need to, so just go
2427 * on to the next. */
2428 goto continue_loc;
2429 break_pos += indent_len;
2430 assert(break_pos < line_len);
2431 /* If we haven't backed up the paragraph, do it now. */
2432 if (first_mod_line == NULL)
2433 first_mod_line = backup_lines(current, par_len, quote_len);
2434 if (par_len == 1) {
2435 /* There is no next line in this paragraph. We make a new
2436 * line and copy text after break_pos into it. */
2437 splice_node(current, make_new_node(current),
2438 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002439 /* In a non-quoted paragraph, we copy the indent only if
2440 AUTOINDENT is turned on. */
2441 if (quote_len == 0)
2442#ifndef NANO_SMALL
2443 if (!ISSET(AUTOINDENT))
2444#endif
2445 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002446 current->next->data = charalloc(indent_len + line_len -
2447 break_pos);
2448 strncpy(current->next->data, current->data,
2449 indent_len);
2450 strcpy(current->next->data + indent_len,
2451 current->data + break_pos + 1);
2452 assert(strlen(current->next->data) ==
2453 indent_len + line_len - break_pos - 1);
2454 totlines++;
2455 totsize += indent_len;
2456 par_len++;
2457 } else {
2458 size_t next_line_len = strlen(current->next->data);
2459
2460 indent_len = quote_len +
2461 indent_length(current->next->data + quote_len);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002462 current->next->data = charealloc(current->next->data,
2463 next_line_len + line_len - break_pos + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002464
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002465 charmove(current->next->data + indent_len + line_len - break_pos,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002466 current->next->data + indent_len,
2467 next_line_len - indent_len + 1);
2468 strcpy(current->next->data + indent_len,
2469 current->data + break_pos + 1);
2470 current->next->data[indent_len + line_len - break_pos - 1]
2471 = ' ';
2472#ifndef NANO_SMALL
2473 if (mark_beginbuf == current->next) {
2474 if (mark_beginx < indent_len)
2475 mark_beginx = indent_len;
2476 mark_beginx += line_len - break_pos;
2477 }
2478#endif
2479 }
2480#ifndef NANO_SMALL
2481 if (mark_beginbuf == current && mark_beginx > break_pos) {
2482 mark_beginbuf = current->next;
2483 mark_beginx -= break_pos + 1 - indent_len;
2484 }
2485#endif
2486 null_at(&current->data, break_pos);
2487 current = current->next;
2488 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002489 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002490
2491 indent_len = quote_len +
2492 indent_length(current->next->data + quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002493 /* If we can't pull a word from the next line up to this one,
2494 * just go on. */
2495 if (!breakable(current->next->data + indent_len,
2496 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002497 goto continue_loc;
2498
2499 /* If we haven't backed up the paragraph, do it now. */
2500 if (first_mod_line == NULL)
2501 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002502
2503 break_pos = break_line(current->next->data + indent_len,
2504 fill - display_len - 1, FALSE);
2505 assert(break_pos != -1);
2506
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002507 current->data = charealloc(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002508 line_len + break_pos + 2);
2509 current->data[line_len] = ' ';
2510 strncpy(current->data + line_len + 1,
2511 current->next->data + indent_len, break_pos);
2512 current->data[line_len + break_pos + 1] = '\0';
2513#ifndef NANO_SMALL
2514 if (mark_beginbuf == current->next) {
2515 if (mark_beginx < indent_len + break_pos) {
2516 mark_beginbuf = current;
2517 if (mark_beginx <= indent_len)
2518 mark_beginx = line_len + 1;
2519 else
2520 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2521 } else
2522 mark_beginx -= break_pos + 1;
2523 }
2524#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002525 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002526 if (indent_len + break_pos == next_line_len) {
2527 line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002528
2529 /* Don't destroy edittop! */
2530 if (line == edittop)
2531 edittop = current;
2532
Chris Allegretta6df90f52002-07-19 01:08:59 +00002533 unlink_node(line);
2534 delete_node(line);
2535 totlines--;
2536 totsize -= indent_len;
2537 current_y--;
2538 } else {
David Lawrence Ramsey9eff7462003-09-16 02:04:00 +00002539 charmove(current->next->data + indent_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002540 current->next->data + indent_len + break_pos + 1,
2541 next_line_len - break_pos - indent_len);
2542 null_at(&current->next->data,
2543 next_line_len - break_pos);
2544 current = current->next;
2545 }
2546 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002547 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002548 current = current->next;
2549 }
Chris Allegretta8151ba52003-04-19 19:34:05 +00002550 UNSET(JUSTIFY_MODE);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002551
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002552/* We are now done justifying the paragraph. There are cleanup things
2553 * to do, and we check for unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002554
2555 /* totlines, totsize, and current_y have been maintained above. We
2556 * now set last_par_line to the new end of the paragraph, update
2557 * fileage, set current_x. Also, edit_refresh() needs the line
2558 * numbers to be right, so we renumber(). */
2559 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002560 if (first_mod_line != NULL) {
2561 if (first_mod_line->prev == NULL)
2562 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002563 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002564 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002565
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002566 skip_justify:
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002567 if (operation == 1) {
2568 /* We're on the same line we started on. Search for the first
2569 * non-"blank" line before the line we're on (if there is one),
2570 * continually restart that search from the current position
2571 * until we find a line that's part of a paragraph, and then
2572 * search once more from there, so that we end up on the first
2573 * line of that paragraph. In the process, skip over lines
2574 * consisting only of spacing characters, as searching for the
2575 * end of the paragraph does. Then update the screen. */
2576 if (current != fileage && current == current_save && !no_restart) {
2577 while (current->prev != NULL) {
2578 int j, j_space = 0;
2579 current = current->prev;
2580 current_y--;
2581 for (j = 0; j < strlen(current->data); j++) {
2582 if (isspace(current->data[j]))
2583 j_space++;
2584 else {
2585 j = -1;
2586 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002587 }
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002588 }
2589 if (j != j_space && strlen(current->data) >=
2590 (quote_len + indent_len) &&
2591 current->data[quote_len + indent_len] != '\0') {
2592 no_restart = 1;
2593 break;
2594 }
2595 }
2596 goto restart_bps;
2597 } else
2598 no_restart = 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002599#ifdef HAVE_REGEX_H
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002600 /* We no longer need to check quotation, if we were
2601 * searching for the beginning of the paragraph. */
2602 regfree(&qreg);
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002603#endif
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002604 if (current_y < 0)
2605 edit_update(current, CENTER);
2606 else
2607 edit_refresh();
2608 return 0;
2609 } else if (operation == 2) {
2610 /* We've already moved to the end of the paragraph. Update the
2611 * screen. */
2612 if (current_y > editwinrows - 1)
2613 edit_update(current, CENTER);
2614 else
2615 edit_refresh();
2616 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002617 }
2618
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002619 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002620 edit_update(current, CENTER);
2621 else
2622 edit_refresh();
2623
Chris Allegretta9149e612000-11-27 00:23:41 +00002624 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002625 /* Change the shortcut list to display the unjustify code */
2626 shortcut_init(1);
2627 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002628 reset_cursor();
2629
Chris Allegretta6df90f52002-07-19 01:08:59 +00002630 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002631 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002632
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002633#ifndef DISABLE_MOUSE
Chris Allegretta6df90f52002-07-19 01:08:59 +00002634 /* If it was a mouse click, parse it with do_mouse() and it might
2635 * become the unjustify key. Else give it back to the input stream. */
2636 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002637 do_mouse();
2638 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002639 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002640#endif
Chris Allegretta5f071802001-05-06 02:34:31 +00002641
Chris Allegretta6df90f52002-07-19 01:08:59 +00002642 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2643 ungetch(i);
2644 /* Did we back up anything at all? */
2645 if (cutbuffer != cutbuffer_save)
2646 free_filestruct(cutbuffer);
2647 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002648 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002649 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002650 current = current_save;
2651 current_x = current_x_save;
2652 current_y = current_y_save;
2653 edittop = edittop_save;
2654 editbot = editbot_save;
2655 if (first_mod_line != NULL) {
2656 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002657
Chris Allegretta6df90f52002-07-19 01:08:59 +00002658 /* Splice the cutbuffer back into the file. */
2659 cutbottom->next = last_par_line->next;
2660 cutbottom->next->prev = cutbottom;
2661 /* The line numbers after the end of the paragraph have
2662 * been changed, so we change them back. */
2663 renumber(cutbottom->next);
2664 if (first_mod_line->prev != NULL) {
2665 cutbuffer->prev = first_mod_line->prev;
2666 cutbuffer->prev->next = cutbuffer;
2667 } else
2668 fileage = cutbuffer;
2669 cutbuffer = NULL;
2670
2671 last_par_line->next = NULL;
2672 free_filestruct(first_mod_line);
2673
2674 /* Restore global variables from before justify */
2675 totsize = totsize_save;
2676 totlines = filebot->lineno;
2677#ifndef NANO_SMALL
2678 mark_beginbuf = mark_beginbuf_save;
2679 mark_beginx = mark_beginx_save;
2680#endif
2681 flags = flags_save;
2682 if (!ISSET(MODIFIED)) {
2683 titlebar(NULL);
2684 wrefresh(topwin);
2685 }
2686 }
2687 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002688 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002689 cutbuffer = cutbuffer_save;
2690 blank_statusbar_refresh();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002691 /* display shortcut list with UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002692 shortcut_init(0);
2693 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002694
Chris Allegretta6df90f52002-07-19 01:08:59 +00002695 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002696}
2697#endif /* !DISABLE_JUSTIFY */
2698
2699int do_justify(void)
2700{
2701#ifdef DISABLE_JUSTIFY
2702 nano_disabled_msg();
2703 return 1;
2704#else
2705 return do_para_operation(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002706#endif
2707}
2708
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002709#ifndef DISABLE_JUSTIFY
2710int do_para_begin(void)
2711{
2712 return do_para_operation(1);
2713}
2714
2715int do_para_end(void)
2716{
2717 return do_para_operation(2);
2718}
2719#endif
2720
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002721int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002722{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002723 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002724
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002725 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002726
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002727#ifdef ENABLE_MULTIBUFFER
2728 if (!close_open_file()) {
2729 display_main_list();
2730 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002731 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002732 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002733#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002734 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002735 }
2736
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002737 if (ISSET(TEMP_OPT)) {
2738 i = 1;
2739 } else {
2740 i = do_yesno(0, 0,
2741 _
2742 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2743 }
2744
2745#ifdef DEBUG
2746 dump_buffer(fileage);
2747#endif
2748
2749 if (i == 1) {
2750 if (do_writeout(filename, 1, 0) > 0) {
2751
2752#ifdef ENABLE_MULTIBUFFER
2753 if (!close_open_file()) {
2754 display_main_list();
2755 return 1;
2756 }
2757 else
2758#endif
2759 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002760 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002761 } else if (i == 0) {
2762
2763#ifdef ENABLE_MULTIBUFFER
2764 if (!close_open_file()) {
2765 display_main_list();
2766 return 1;
2767 }
2768 else
2769#endif
2770 finish(0);
2771 } else
2772 statusbar(_("Cancelled"));
2773
2774 display_main_list();
2775 return 1;
2776}
2777
2778void signal_init(void)
2779{
2780#ifdef _POSIX_VDISABLE
2781 struct termios term;
2782#endif
2783
2784 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2785 memset(&act, 0, sizeof(struct sigaction));
2786 act.sa_handler = SIG_IGN;
2787 sigaction(SIGINT, &act, NULL);
2788
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002789 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2790 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002791 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002792 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002793
2794#ifndef NANO_SMALL
2795 act.sa_handler = handle_sigwinch;
2796 sigaction(SIGWINCH, &act, NULL);
2797#endif
2798
2799#ifdef _POSIX_VDISABLE
2800 tcgetattr(0, &term);
2801
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002802 if (!ISSET(PRESERVE)) {
2803 /* Ignore ^S and ^Q, much to Chris' chagrin */
2804 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2805 term.c_cc[VSTART] = _POSIX_VDISABLE;
2806 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002807#ifdef VDSUSP
2808 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2809#endif /* VDSUSP */
2810
2811#endif /* _POSIX_VDISABLE */
2812
2813 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002814 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002815#ifdef _POSIX_VDISABLE
2816 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2817#else
2818 act.sa_handler = SIG_IGN;
2819 sigaction(SIGTSTP, &act, NULL);
2820#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002821 } else {
2822 /* If we don't do this, it seems other stuff interrupts the
2823 suspend handler! Try using nano with mutt without this
2824 line. */
2825 sigfillset(&act.sa_mask);
2826
2827 act.sa_handler = do_suspend;
2828 sigaction(SIGTSTP, &act, NULL);
2829
2830 act.sa_handler = do_cont;
2831 sigaction(SIGCONT, &act, NULL);
2832 }
2833
2834#ifdef _POSIX_VDISABLE
2835 tcsetattr(0, TCSANOW, &term);
2836#endif
2837}
2838
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002839/* Handler for SIGHUP and SIGTERM */
2840RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002841{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002842 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002843}
2844
2845/* What do we do when we catch the suspend signal */
2846RETSIGTYPE do_suspend(int signal)
2847{
2848 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002849 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002850 fflush(stdout);
2851
2852 /* Restore the terminal settings for the disabled keys */
2853 tcsetattr(0, TCSANOW, &oldterm);
2854
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002855 /* Trap SIGHUP and SIGTERM so we can properly deal with them while
2856 suspended */
2857 act.sa_handler = handle_hupterm;
2858 sigaction(SIGHUP, &act, NULL);
2859 sigaction(SIGTERM, &act, NULL);
2860
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002861 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002862 then we could be (and were) interrupted in the middle of the call.
2863 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002864 kill(0, SIGSTOP);
2865}
2866
2867/* Restore the suspend handler when we come back into the prog */
2868RETSIGTYPE do_cont(int signal)
2869{
2870 /* Now we just update the screen instead of having to reenable the
2871 SIGTSTP handler. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002872 doupdate();
David Lawrence Ramsey99bede32003-09-29 07:21:11 +00002873
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002874 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2875 start suspending again. */
2876 signal_init();
2877
2878#ifndef NANO_SMALL
2879 /* Perhaps the user resized the window while we slept. */
2880 handle_sigwinch(0);
2881#endif
2882}
2883
2884#ifndef NANO_SMALL
2885void handle_sigwinch(int s)
2886{
2887 const char *tty = ttyname(0);
2888 int fd;
2889 int result = 0;
2890 struct winsize win;
2891
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002892 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002893 return;
2894 fd = open(tty, O_RDWR);
2895 if (fd == -1)
2896 return;
2897 result = ioctl(fd, TIOCGWINSZ, &win);
2898 close(fd);
2899 if (result == -1)
2900 return;
2901
2902 /* Could check whether the COLS or LINES changed, and return
2903 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2904 * variables, and in some cases ncurses has already updated them.
2905 * But not in all cases, argh. */
2906 COLS = win.ws_col;
2907 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002908 editwinrows = LINES - 5 + no_help();
2909 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002910 die_too_small();
2911
2912#ifndef DISABLE_WRAPJUSTIFY
2913 fill = wrap_at;
2914 if (fill <= 0)
2915 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002916 if (fill < 0)
2917 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002918#endif
2919
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002920 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002921 memset(hblank, ' ', COLS);
2922 hblank[COLS] = '\0';
2923
2924#ifdef HAVE_RESIZETERM
2925 resizeterm(LINES, COLS);
2926#ifdef HAVE_WRESIZE
2927 if (wresize(topwin, 2, COLS) == ERR)
2928 die(_("Cannot resize top win"));
2929 if (mvwin(topwin, 0, 0) == ERR)
2930 die(_("Cannot move top win"));
2931 if (wresize(edit, editwinrows, COLS) == ERR)
2932 die(_("Cannot resize edit win"));
2933 if (mvwin(edit, 2, 0) == ERR)
2934 die(_("Cannot move edit win"));
2935 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2936 die(_("Cannot resize bottom win"));
2937 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2938 die(_("Cannot move bottom win"));
2939#endif /* HAVE_WRESIZE */
2940#endif /* HAVE_RESIZETERM */
2941
2942 fix_editbot();
2943
2944 if (current_y > editwinrows - 1)
2945 edit_update(editbot, CENTER);
2946 erase();
2947
2948 /* Do these b/c width may have changed... */
2949 refresh();
2950 titlebar(NULL);
2951 edit_refresh();
2952 display_main_list();
2953 blank_statusbar();
2954 total_refresh();
2955
2956 /* Turn cursor back on for sure */
2957 curs_set(1);
2958
2959 /* Jump back to main loop */
2960 siglongjmp(jmpbuf, 1);
2961}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002962#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002963
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002964/* If the NumLock key has made the keypad go awry, print an error
2965 message; hopefully we can address it later. */
2966void print_numlock_warning(void)
2967{
2968 static int didmsg = 0;
2969 if (!didmsg) {
2970 statusbar(_
2971 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2972 didmsg = 1;
2973 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002974}
2975
Chris Allegrettadab017e2002-04-23 10:56:06 +00002976#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002977void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002978{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002979 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002980
Chris Allegretta658399a2001-06-14 02:54:22 +00002981 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002982 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002983
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002984 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002985 case TOGGLE_SUSPEND_KEY:
2986 signal_init();
2987 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00002988#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00002989 case TOGGLE_MOUSE_KEY:
2990 mouse_init();
2991 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002992#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002993 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002994 wclear(bottomwin);
2995 wrefresh(bottomwin);
2996 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002997 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002998 edit_refresh();
2999 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00003000 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00003001 case TOGGLE_DOS_KEY:
3002 UNSET(MAC_FILE);
3003 break;
3004 case TOGGLE_MAC_KEY:
3005 UNSET(DOS_FILE);
3006 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003007#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003008 case TOGGLE_SYNTAX_KEY:
3009 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003010 break;
3011#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003012 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003013
Chris Allegretta6df90f52002-07-19 01:08:59 +00003014 /* We are assuming here that shortcut_init() above didn't free and
3015 * reallocate the toggles. */
3016 enabled = ISSET(which->flag);
3017 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3018 enabled = !enabled;
3019 statusbar("%s %s", which->desc,
3020 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003021}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003022#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003023
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003024int main(int argc, char *argv[])
3025{
3026 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003027 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003028 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003029 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003030 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003031 int keyhandled = 0; /* Have we handled the keystroke yet? */
3032 int kbinput = -1; /* Input from keyboard */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003033 int meta;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003034
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003035#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003036 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003037#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003038#ifdef _POSIX_VDISABLE
3039 struct termios term;
3040#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003041#ifdef HAVE_GETOPT_LONG
3042 int option_index = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003043 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003044 {"help", 0, 0, 'h'},
3045#ifdef ENABLE_MULTIBUFFER
3046 {"multibuffer", 0, 0, 'F'},
3047#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003048#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003049#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003050 {"historylog", 0, 0, 'H'},
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003051#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003052 {"ignorercfiles", 0, 0, 'I'},
3053#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054#ifndef DISABLE_JUSTIFY
3055 {"quotestr", 1, 0, 'Q'},
3056#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003057#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003058 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003059#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003060 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003061 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062#ifdef ENABLE_COLOR
3063 {"syntax", 1, 0, 'Y'},
3064#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003065 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003066 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003067 {"nofollow", 0, 0, 'l'},
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003068#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003069 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003070#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003071#ifndef DISABLE_OPERATINGDIR
3072 {"operatingdir", 1, 0, 'o'},
3073#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003074 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003075#ifndef DISABLE_WRAPJUSTIFY
3076 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003077#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003078#ifndef DISABLE_SPELLER
3079 {"speller", 1, 0, 's'},
3080#endif
3081 {"tempfile", 0, 0, 't'},
3082 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003083#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003084 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003085#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003086 {"nohelp", 0, 0, 'x'},
3087 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003088#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003089 {"backup", 0, 0, 'B'},
3090 {"dos", 0, 0, 'D'},
3091 {"mac", 0, 0, 'M'},
3092 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003093 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003094 {"autoindent", 0, 0, 'i'},
3095 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003096#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003097 {0, 0, 0, 0}
3098 };
3099#endif
3100
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003101#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003102 setlocale(LC_ALL, "");
3103 bindtextdomain(PACKAGE, LOCALEDIR);
3104 textdomain(PACKAGE);
3105#endif
3106
Chris Allegretta7662c862003-01-13 01:35:15 +00003107#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003108 /* if we don't have rcfile support, we're root, and
3109 --disable-wrapping-as-root is used, turn wrapping off */
3110 if (geteuid() == 0)
3111 SET(NO_WRAP);
3112#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003113
3114#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003115 while ((optchr = getopt_long(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
Chris Allegretta7662c862003-01-13 01:35:15 +00003116 long_options, &option_index)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003117#else
3118 while ((optchr =
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003119 getopt(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003120#endif
3121
3122 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003123
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003124 case 'a':
3125 case 'b':
3126 case 'e':
3127 case 'f':
3128 case 'g':
3129 case 'j':
3130 /* Pico compatibility flags */
3131 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003132#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003133 case 'B':
3134 SET(BACKUP_FILE);
3135 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003136 case 'D':
3137 SET(DOS_FILE);
3138 break;
3139#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003140#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003141 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003142 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003143 break;
3144#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003145#ifdef ENABLE_NANORC
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003146#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003147 case 'H':
3148 SET(HISTORYLOG);
3149 break;
David Lawrence Ramsey417b03a2003-09-06 21:44:37 +00003150#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003151 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003152 SET(NO_RCFILE);
3153 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003154#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003155#ifndef NANO_SMALL
3156 case 'M':
3157 SET(MAC_FILE);
3158 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003159 case 'N':
3160 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003161 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003162#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003163#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003164 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003165 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003166 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003167#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003168#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003169 case 'R':
3170 SET(USE_REGEXP);
3171 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003172#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003173#ifndef NANO_SMALL
3174 case 'S':
3175 SET(SMOOTHSCROLL);
3176 break;
3177#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003178 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003179 {
3180 int i;
3181 char *first_error;
3182
Chris Allegretta7662c862003-01-13 01:35:15 +00003183 /* Using strtol() instead of atoi() lets us accept 0
3184 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003185 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003186 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003187 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003188 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003189 tabsize = i;
3190 if (tabsize <= 0) {
3191 fprintf(stderr, _("Tab size is too small for nano...\n"));
3192 exit(1);
3193 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003194 }
3195 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003196 case 'V':
3197 version();
3198 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003199#ifdef ENABLE_COLOR
3200 case 'Y':
3201 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3202 break;
3203#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003204 case 'c':
3205 SET(CONSTUPDATE);
3206 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003207 case 'd':
3208 SET(REBIND_DELETE);
3209 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003210#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003211 case 'i':
3212 SET(AUTOINDENT);
3213 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003214 case 'k':
3215 SET(CUT_TO_END);
3216 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003217#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003218 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003219 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003220 break;
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003221#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003222 case 'm':
3223 SET(USE_MOUSE);
3224 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003225#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003226#ifndef DISABLE_OPERATINGDIR
3227 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003228 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003229 break;
3230#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003231 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003232 SET(PRESERVE);
3233#ifdef HAVE_GETOPT_LONG
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003234#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003235 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003236#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003237 case 'r':
3238 {
3239 int i;
3240 char *first_error;
3241
Chris Allegretta7662c862003-01-13 01:35:15 +00003242 /* Using strtol() instead of atoi() lets us accept 0
3243 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003244 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003245 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003246 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003247 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003248 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003249 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003250 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003251 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003252#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003253#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003254 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003255 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003256 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003257#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003258 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003259 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003260 break;
3261 case 'v':
3262 SET(VIEW_MODE);
3263 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003264#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003265 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003266 SET(NO_WRAP);
3267 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003268#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003269 case 'x':
3270 SET(NO_HELP);
3271 break;
3272 case 'z':
3273 SET(SUSPEND);
3274 break;
3275 default:
3276 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003277 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003278 }
3279
Chris Allegretta7662c862003-01-13 01:35:15 +00003280/* We've read through the command line options. Now back up the flags
3281 and values that are set, and read the rcfile(s). If the values
3282 haven't changed afterward, restore the backed-up values. */
3283#ifdef ENABLE_NANORC
3284 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003285#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003286 char *operating_dir_cpy = operating_dir;
3287#endif
3288#ifndef DISABLE_WRAPPING
3289 int wrap_at_cpy = wrap_at;
3290#endif
3291#ifndef DISABLE_JUSTIFY
3292 char *quotestr_cpy = quotestr;
3293#endif
3294#ifndef DISABLE_SPELLER
3295 char *alt_speller_cpy = alt_speller;
3296#endif
3297 int tabsize_cpy = tabsize;
3298 long flags_cpy = flags;
3299
Chris Allegretta5ec68622003-02-05 02:39:34 +00003300#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003301 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003302#endif
3303#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003304 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003305#endif
3306#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003307 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003308#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003309
3310 do_rcfile();
3311
3312#ifndef DISABLE_OPERATINGDIR
3313 if (operating_dir_cpy != NULL) {
3314 free(operating_dir);
3315 operating_dir = operating_dir_cpy;
3316 }
3317#endif
3318#ifndef DISABLE_WRAPPING
3319 if (fill_flag_used)
3320 wrap_at = wrap_at_cpy;
3321#endif
3322#ifndef DISABLE_JUSTIFY
3323 if (quotestr_cpy != NULL) {
3324 free(quotestr);
3325 quotestr = quotestr_cpy;
3326 }
3327#endif
3328#ifndef DISABLE_SPELLER
3329 if (alt_speller_cpy != NULL) {
3330 free(alt_speller);
3331 alt_speller = alt_speller_cpy;
3332 }
3333#endif
3334 if (tabsize_cpy > 0)
3335 tabsize = tabsize_cpy;
3336 flags |= flags_cpy;
3337 }
3338#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3339 else if (geteuid() == 0)
3340 SET(NO_WRAP);
3341#endif
3342#endif /* ENABLE_NANORC */
3343
Chris Allegrettad8451932003-03-11 03:50:40 +00003344#ifndef NANO_SMALL
3345 history_init();
3346#ifdef ENABLE_NANORC
3347 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3348 load_history();
3349#endif
3350#endif
3351
Chris Allegretta7662c862003-01-13 01:35:15 +00003352#ifndef DISABLE_OPERATINGDIR
3353 /* Set up the operating directory. This entails chdir()ing there,
3354 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003355 init_operating_dir();
3356#endif
3357
Chris Allegretta7662c862003-01-13 01:35:15 +00003358#ifndef DISABLE_JUSTIFY
3359 if (quotestr == NULL)
3360#ifdef HAVE_REGEX_H
3361 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3362#else
3363 quotestr = mallocstrcpy(NULL, "> ");
3364#endif
3365#endif /* !DISABLE_JUSTIFY */
3366 if (tabsize == -1)
3367 tabsize = 8;
3368
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003369 /* Clear the filename we'll be using */
3370 filename = charalloc(1);
3371 filename[0] = '\0';
3372
Chris Allegretta7662c862003-01-13 01:35:15 +00003373 /* If there's a +LINE flag, it is the first non-option argument. */
3374 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3375 startline = atoi(&argv[optind][1]);
3376 optind++;
3377 }
3378 if (0 < optind && optind < argc)
3379 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003380
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003381 /* See if there's a non-option in argv (first non-option is the
3382 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003383 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003384 /* Look for the +line flag... */
3385 if (argv[optind][0] == '+') {
3386 startline = atoi(&argv[optind][1]);
3387 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003388 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003389 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003390 } else
3391 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003392 }
3393
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003394 /* First back up the old settings so they can be restored, duh */
3395 tcgetattr(0, &oldterm);
3396
3397#ifdef _POSIX_VDISABLE
3398 term = oldterm;
3399 term.c_cc[VINTR] = _POSIX_VDISABLE;
3400 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3401 term.c_lflag &= ~IEXTEN;
3402 tcsetattr(0, TCSANOW, &term);
3403#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003404
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003405 /* now ncurses init stuff... */
3406 initscr();
3407 savetty();
3408 nonl();
3409 cbreak();
3410 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003411
3412 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003413 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003414 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003415 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003416
3417#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003418 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003419#endif
3420
Chris Allegretta2a42af12000-09-12 23:02:49 +00003421 window_init();
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003422#ifndef DISABLE_MOUSE
Chris Allegretta756f2202000-09-01 13:32:47 +00003423 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003424#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003425
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003426 keypad(edit, TRUE);
3427 keypad(bottomwin, TRUE);
Chris Allegretta48bd3782002-01-03 21:26:34 +00003428
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003429#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003430 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003431#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003432 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003433 display_main_list();
3434
3435#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003436 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003437#endif
3438
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003439 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003440#ifdef ENABLE_MULTIBUFFER
3441 /* If we're using multibuffers and more than one file is specified
3442 on the command line, load them all and switch to the first one
3443 afterward */
3444 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3445 for (optind++; optind < argc; optind++) {
3446 add_open_file(1);
3447 new_file();
3448 filename = mallocstrcpy(filename, argv[optind]);
3449 open_file(filename, 0, 0);
3450 load_file(0);
3451 }
3452 open_nextfile_void();
3453 }
3454#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003455
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003456 titlebar(NULL);
3457
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003458 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003459 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003460
Chris Allegretta7662c862003-01-13 01:35:15 +00003461 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003462 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003463
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003464 /* SHUT UP GCC! */
3465 startline = 0;
3466 fill_flag_used = 0;
3467 keyhandled = 0;
3468
Chris Allegretta7662c862003-01-13 01:35:15 +00003469 /* This variable should be initialized after the sigsetjmp(), so we
3470 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003471 modify_control_seq = 0;
3472
Robert Siemborski6967eec2000-07-08 14:23:32 +00003473 edit_refresh();
3474 reset_cursor();
3475
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003476 while (1) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003477 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003478
Chris Allegrettad26ab912003-01-28 01:16:47 +00003479 if (ISSET(CONSTUPDATE))
3480 do_cursorpos(1);
3481
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003482#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003483 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003484#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003485
Chris Allegretta9239d742000-09-06 15:19:18 +00003486#ifndef _POSIX_VDISABLE
3487 /* We're going to have to do it the old way, i.e. on cygwin */
3488 raw();
3489#endif
3490
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003491 kbinput = get_kbinput(edit, &meta, ISSET(REBIND_DELETE));
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003492#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003493 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003494#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003495 if (meta == 1) {
Chris Allegretta7662c862003-01-13 01:35:15 +00003496 switch (kbinput) {
Chris Allegretta355fbe52001-07-14 19:32:47 +00003497#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003498 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003499 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003500 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003501 keyhandled = 1;
3502 break;
3503 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003504 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003505 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003506 keyhandled = 1;
3507 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003508#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003509 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003510 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003511 for (s = main_list; s != NULL; s = s->next)
Chris Allegretta7662c862003-01-13 01:35:15 +00003512 if (kbinput == s->altval || (kbinput >= 'A' &&
3513 kbinput <= 'Z' && kbinput == s->altval - 32)) {
Chris Allegretta6232d662002-05-12 19:52:15 +00003514 if (ISSET(VIEW_MODE) && !s->viewok)
3515 print_view_warning();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003516 else {
3517 if (s->func != do_cut_text)
3518 UNSET(KEEP_CUTBUFFER);
Chris Allegretta6232d662002-05-12 19:52:15 +00003519 s->func();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003520 }
Chris Allegretta6232d662002-05-12 19:52:15 +00003521 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003522 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003523 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003524#ifndef NANO_SMALL
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003525 if (!keyhandled)
3526 /* And for toggle switches */
3527 for (t = toggles; t != NULL; t = t->next)
3528 if (kbinput == t->val || (t->val >= 'a' &&
3529 t->val <= 'z' && kbinput == t->val - 32)) {
3530 UNSET(KEEP_CUTBUFFER);
3531 do_toggle(t);
3532 keyhandled = 1;
3533 break;
3534 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003535#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003536#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003537 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003538 kbinput);
3539#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003540 }
3541 }
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003542
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003543 /* Look through the main shortcut list to see if we've hit a
3544 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003545
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003546 if (!keyhandled)
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003547#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || !defined(DISABLE_MOUSE)
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003548 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003549#else
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003550 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003551#endif
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003552 if (kbinput == s->val ||
3553 (s->misc1 && kbinput == s->misc1) ||
3554 (s->misc2 && kbinput == s->misc2)) {
3555 if (ISSET(VIEW_MODE) && !s->viewok)
3556 print_view_warning();
3557 else {
3558 if (s->func != do_cut_text)
3559 UNSET(KEEP_CUTBUFFER);
3560 s->func();
3561 }
3562 keyhandled = 1;
3563 /* Rarely, the value of s can change after
3564 s->func(), leading to problems; get around this
3565 by breaking out explicitly once we successfully
3566 handle a shortcut */
3567 break;
3568 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003569 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003570
3571 if (!keyhandled)
3572 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003573
3574#ifdef _POSIX_VDISABLE
3575 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003576 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003577 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003578 if (kbinput == NANO_CONTROL_S)
3579 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003580#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003581 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3582 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003583 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003584 keyhandled = 1;
3585
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003586 /* Catch ^Z by hand when triggered also */
3587 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003588 if (ISSET(SUSPEND))
3589 do_suspend(0);
3590 keyhandled = 1;
3591 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003592
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003593 /* Last gasp, stuff that's not in the main lists */
3594 if (!keyhandled)
3595 switch (kbinput) {
David Lawrence Ramseyf5b256b2003-10-03 20:26:25 +00003596#ifndef DISABLE_MOUSE
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003597 case KEY_MOUSE:
3598 do_mouse();
3599 break;
3600#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003601
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003602 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3603 * have been handled before we
3604 * got here */
3605 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003606 break;
3607 default:
3608#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003609 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003610#endif
3611 /* We no longer stop unhandled sequences so that people with
3612 odd character sets can type... */
3613
Chris Allegretta7662c862003-01-13 01:35:15 +00003614 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003615 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003616 else
3617 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003618 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003619
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003620 reset_cursor();
3621 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003622 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003623 assert(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003624}