blob: cba0ef6fc2abe9af48a59c24c704a3315dca0370 [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
Rocco Corsiaf5c3022001-01-12 07:51:05 +000060
Chris Allegretta6df90f52002-07-19 01:08:59 +000061static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000062static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000063
Chris Allegretta08020882001-01-29 23:37:54 +000064static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
65
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000066/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000067RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000068{
69 if (!ISSET(NO_HELP)) {
70 mvwaddstr(bottomwin, 1, 0, hblank);
71 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000072 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000073 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000074
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000075 wrefresh(bottomwin);
76 endwin();
77
78 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000079 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000080
Chris Allegrettad8451932003-03-11 03:50:40 +000081#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
82 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
83 save_history();
84#endif
85
Chris Allegretta6232d662002-05-12 19:52:15 +000086#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000087 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000088#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000089
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000090 exit(sigage);
91}
92
93/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +000094void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000095{
96 va_list ap;
97
Chris Allegrettaa0d89972003-02-03 03:32:08 +000098 endwin();
99 curses_ended = TRUE;
100
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000101 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000102 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000103
Chris Allegretta6df90f52002-07-19 01:08:59 +0000104 va_start(ap, msg);
105 vfprintf(stderr, msg, ap);
106 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000107
Chris Allegretta32da4562002-01-02 15:12:21 +0000108 /* save the currently loaded file if it's been modified */
109 if (ISSET(MODIFIED))
110 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000111
Chris Allegretta355fbe52001-07-14 19:32:47 +0000112#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000113 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000114 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000115 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000116
117 tmp = open_files;
118
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000119 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000120 open_files = open_files->prev;
121
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000122 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000123
124 /* if we already saved the file above (i. e. if it was the
125 currently loaded file), don't save it again */
126 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000127 /* make sure open_files->fileage and fileage, and
128 open_files->filebot and filebot, are in sync; they
129 might not be if lines have been cut from the top or
130 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000131 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000132 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000133 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000134 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000135 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000136 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000137 open_files = open_files->next;
138 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000139 }
140#endif
141
Chris Allegretta6df90f52002-07-19 01:08:59 +0000142 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143}
144
Chris Allegretta6df90f52002-07-19 01:08:59 +0000145void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000146{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000147 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000148 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149
Chris Allegretta6df90f52002-07-19 01:08:59 +0000150 /* If we can't save, we have REAL bad problems, but we might as well
151 TRY. */
152 if (die_filename[0] == '\0')
153 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000154 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000155 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000156
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000157 strcpy(buf, die_filename);
158 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000159 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000160 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000161 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000162 if (ret[0] != '\0')
163 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000164
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000165 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000167 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000169
170 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000171}
172
Chris Allegrettae61e8302001-01-14 05:18:27 +0000173/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000175void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000176{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000177 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000178}
179
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000180void print_view_warning(void)
181{
182 statusbar(_("Key illegal in VIEW mode"));
183}
184
Chris Allegretta56214c62001-09-27 02:46:53 +0000185/* Initialize global variables - no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000186 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000187void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000188{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000189 current_x = 0;
190 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000191
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000192 editwinrows = LINES - 5 + no_help();
193 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000194 die_too_small();
195
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000196 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000197 if (!save_cutbuffer)
198 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000199 current = NULL;
200 edittop = NULL;
201 editbot = NULL;
202 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000203 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000204 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000205
Chris Allegretta6fe61492001-05-21 12:56:25 +0000206#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000207 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000208 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000209 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000210 if (fill < 0)
211 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000212#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000213
Chris Allegretta88b09152001-05-17 11:35:43 +0000214 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000215 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000216 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000217}
218
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000219void window_init(void)
220{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000221 editwinrows = LINES - 5 + no_help();
222 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000223 die_too_small();
224
Chris Allegretta1a128af2003-01-26 04:15:56 +0000225 if (edit != NULL)
226 delwin(edit);
227 if (topwin != NULL)
228 delwin(topwin);
229 if (bottomwin != NULL)
230 delwin(bottomwin);
231
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000232 /* Set up the main text window. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000233 edit = newwin(editwinrows, COLS, 2, 0);
234
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000235 /* And the other windows. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000236 topwin = newwin(2, COLS, 0, 0);
237 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
238
David Lawrence Ramsey27863662003-08-29 21:31:37 +0000239 /* This is so the keypad still works after a Meta-X, for example. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000240 keypad(edit, TRUE);
241 keypad(bottomwin, TRUE);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000242}
243
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000244#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000245void mouse_init(void)
246{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000247 if (ISSET(USE_MOUSE)) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000248 mousemask(BUTTON1_RELEASED, NULL);
249 mouseinterval(50);
250 } else
251 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000253#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000254
255#ifndef DISABLE_HELP
256/* This function allocates help_text, and stores the help string in it.
257 * help_text should be NULL initially. */
258void help_init(void)
259{
Chris Allegretta908f7702003-01-15 11:18:58 +0000260 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000261 char *ptr = NULL;
262#ifndef NANO_SMALL
263 const toggle *t;
264#endif
265 const shortcut *s;
266
267 /* First set up the initial help text for the current function */
268 if (currshortcut == whereis_list || currshortcut == replace_list
269 || currshortcut == replace_list_2)
270 ptr = _("Search Command Help Text\n\n "
271 "Enter the words or characters you would like to search "
272 "for, then hit enter. If there is a match for the text you "
273 "entered, the screen will be updated to the location of the "
274 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000275 "The previous search string will be shown in brackets after "
276 "the Search: prompt. Hitting Enter without entering any text "
277 "will perform the previous search.\n\n The following function "
278 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000279 else if (currshortcut == goto_list)
280 ptr = _("Go To Line Help Text\n\n "
281 "Enter the line number that you wish to go to and hit "
282 "Enter. If there are fewer lines of text than the "
283 "number you entered, you will be brought to the last line "
284 "of the file.\n\n The following function keys are "
285 "available in Go To Line mode:\n\n");
286 else if (currshortcut == insertfile_list)
287 ptr = _("Insert File Help Text\n\n "
288 "Type in the name of a file to be inserted into the current "
289 "file buffer at the current cursor location.\n\n "
290 "If you have compiled nano with multiple file buffer "
291 "support, and enable multiple buffers with the -F "
292 "or --multibuffer command line flags, the Meta-F toggle, or "
293 "a nanorc file, inserting a file will cause it to be "
294 "loaded into a separate buffer (use Meta-< and > to switch "
295 "between file buffers).\n\n If you need another blank "
296 "buffer, do not enter any filename, or type in a "
297 "nonexistent filename at the prompt and press "
298 "Enter.\n\n The following function keys are "
299 "available in Insert File mode:\n\n");
300 else if (currshortcut == writefile_list)
301 ptr = _("Write File Help Text\n\n "
302 "Type the name that you wish to save the current file "
303 "as and hit Enter to save the file.\n\n If you have "
304 "selected text with Ctrl-^, you will be prompted to "
305 "save only the selected portion to a separate file. To "
306 "reduce the chance of overwriting the current file with "
307 "just a portion of it, the current filename is not the "
308 "default in this mode.\n\n The following function keys "
309 "are available in Write File mode:\n\n");
310#ifndef DISABLE_BROWSER
311 else if (currshortcut == browser_list)
312 ptr = _("File Browser Help Text\n\n "
313 "The file browser is used to visually browse the "
314 "directory structure to select a file for reading "
315 "or writing. You may use the arrow keys or Page Up/"
316 "Down to browse through the files, and S or Enter to "
317 "choose the selected file or enter the selected "
318 "directory. To move up one level, select the directory "
319 "called \"..\" at the top of the file list.\n\n The "
320 "following function keys are available in the file "
321 "browser:\n\n");
322 else if (currshortcut == gotodir_list)
323 ptr = _("Browser Go To Directory Help Text\n\n "
324 "Enter the name of the directory you would like to "
325 "browse to.\n\n If tab completion has not been disabled, "
326 "you can use the TAB key to (attempt to) automatically "
327 "complete the directory name.\n\n The following function "
328 "keys are available in Browser Go To Directory mode:\n\n");
329#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000330#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000331 else if (currshortcut == spell_list)
332 ptr = _("Spell Check Help Text\n\n "
333 "The spell checker checks the spelling of all text "
334 "in the current file. When an unknown word is "
335 "encountered, it is highlighted and a replacement can "
336 "be edited. It will then prompt to replace every "
337 "instance of the given misspelled word in the "
338 "current file.\n\n The following other functions are "
339 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000340#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000341#ifndef NANO_SMALL
342 else if (currshortcut == extcmd_list)
343 ptr = _("External Command Help Text\n\n "
344 "This menu allows you to insert the output of a command "
345 "run by the shell into the current buffer (or a new "
346 "buffer in multibuffer mode).\n\n The following keys are "
347 "available in this mode:\n\n");
348#endif
349 else /* Default to the main help list */
350 ptr = _(" nano help text\n\n "
351 "The nano editor is designed to emulate the functionality and "
352 "ease-of-use of the UW Pico text editor. There are four main "
353 "sections of the editor: The top line shows the program "
354 "version, the current filename being edited, and whether "
355 "or not the file has been modified. Next is the main editor "
356 "window showing the file being edited. The status line is "
357 "the third line from the bottom and shows important messages. "
358 "The bottom two lines show the most commonly used shortcuts "
359 "in the editor.\n\n "
360 "The notation for shortcuts is as follows: Control-key "
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +0000361 "sequences are notated with a caret (^) symbol and can be "
362 "entered either by using the Control (Ctrl) key or pressing the "
363 "Esc key twice. Escape-key sequences are notated with the Meta "
364 "(M) symbol and can be entered using either the Esc, Alt or "
365 "Meta key depending on your keyboard setup. Also, pressing Esc "
366 "twice and then typing a three-digit number from 000 to 255 "
367 "will enter the character with the corresponding ASCII code. "
368 "The following keystrokes are available in the main editor "
369 "window. Alternative keys are shown in parentheses:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000370
Chris Allegretta908f7702003-01-15 11:18:58 +0000371 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000372
373 /* The space needed for the shortcut lists, at most COLS characters,
374 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000375 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000376
377#ifndef NANO_SMALL
378 /* If we're on the main list, we also count the toggle help text.
379 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
380 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000381 if (currshortcut == main_list) {
382 size_t endislen = strlen(_("enable/disable"));
383
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000384 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000385 allocsize += 8 + strlen(t->desc) + endislen;
386 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000387#endif /* !NANO_SMALL */
388
389 /* help_text has been freed and set to NULL unless the user resized
390 * while in the help screen. */
391 free(help_text);
392
393 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000394 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000395
396 /* Now add the text we want */
397 strcpy(help_text, ptr);
398 ptr = help_text + strlen(help_text);
399
400 /* Now add our shortcut info */
401 for (s = currshortcut; s != NULL; s = s->next) {
402 /* true if the character in s->altval is shown in first column */
403 int meta_shortcut = 0;
404
405 if (s->val > 0 && s->val < 32)
406 ptr += sprintf(ptr, "^%c", s->val + 64);
407#ifndef NANO_SMALL
408 else if (s->val == NANO_CONTROL_SPACE)
409 ptr += sprintf(ptr, "^%.6s", _("Space"));
410 else if (s->altval == NANO_ALT_SPACE) {
411 meta_shortcut = 1;
412 ptr += sprintf(ptr, "M-%.5s", _("Space"));
Chris Allegretta7662c862003-01-13 01:35:15 +0000413 } else if (s->val == KEY_UP)
414 ptr += sprintf(ptr, "%.2s", _("Up"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000415#endif
416 else if (s->altval > 0) {
417 meta_shortcut = 1;
418 ptr += sprintf(ptr, "M-%c", s->altval -
419 (('A' <= s->altval && s->altval <= 'Z') ||
420 'a' <= s->altval ? 32 : 0));
421 }
422 /* Hack */
423 else if (s->val >= 'a') {
424 meta_shortcut = 1;
425 ptr += sprintf(ptr, "M-%c", s->val - 32);
426 }
427
428 *(ptr++) = '\t';
429
430 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
431 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
432
433 *(ptr++) = '\t';
434
435 if (!meta_shortcut && s->altval > 0)
436 ptr += sprintf(ptr, "(M-%c)", s->altval -
437 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
438 ? 32 : 0));
439
440 *(ptr++) = '\t';
441
442 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000443 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000444 }
445
446#ifndef NANO_SMALL
447 /* And the toggles... */
448 if (currshortcut == main_list)
449 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000450 assert(t->desc != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000451 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", t->val - 32, t->desc,
452 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000453 }
454#endif /* !NANO_SMALL */
455
456 /* If all went well, we didn't overwrite the allocated space for
457 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000458 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000459}
460#endif
461
462/* Create a new filestruct node. Note that we specifically do not set
463 * prevnode->next equal to the new line. */
464filestruct *make_new_node(filestruct *prevnode)
465{
466 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
467
468 newnode->data = NULL;
469 newnode->prev = prevnode;
470 newnode->next = NULL;
471 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
472
473 return newnode;
474}
475
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000476/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000477filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000478{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000479 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000480
Chris Allegretta6df90f52002-07-19 01:08:59 +0000481 assert(src != NULL);
482
Chris Allegretta88b09152001-05-17 11:35:43 +0000483 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000484 dst->next = src->next;
485 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000486 strcpy(dst->data, src->data);
487 dst->lineno = src->lineno;
488
489 return dst;
490}
491
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000492/* Splice a node into an existing filestruct. */
493void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
494{
495 if (newnode != NULL) {
496 newnode->next = end;
497 newnode->prev = begin;
498 }
499 if (begin != NULL)
500 begin->next = newnode;
501 if (end != NULL)
502 end->prev = newnode;
503}
504
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000505/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000506void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000507{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000508 assert(fileptr != NULL);
509
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000510 if (fileptr->prev != NULL)
511 fileptr->prev->next = fileptr->next;
512
513 if (fileptr->next != NULL)
514 fileptr->next->prev = fileptr->prev;
515}
516
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000517/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000518void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000519{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000520 if (fileptr != NULL) {
521 if (fileptr->data != NULL)
522 free(fileptr->data);
523 free(fileptr);
524 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000525}
526
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000527/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000528filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530 filestruct *head; /* copy of src, top of the copied list */
531 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000532
Chris Allegretta6df90f52002-07-19 01:08:59 +0000533 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000534
Chris Allegretta6df90f52002-07-19 01:08:59 +0000535 prev = copy_node(src);
536 prev->prev = NULL;
537 head = prev;
538 src = src->next;
539 while (src != NULL) {
540 prev->next = copy_node(src);
541 prev->next->prev = prev;
542 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543
Chris Allegretta6df90f52002-07-19 01:08:59 +0000544 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000545 }
546
Chris Allegretta6df90f52002-07-19 01:08:59 +0000547 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000548 return head;
549}
550
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000551/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000552void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000553{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000554 if (src != NULL) {
555 while (src->next != NULL) {
556 src = src->next;
557 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000558#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000559 fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000560#endif
561 }
562 delete_node(src);
563#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +0000564 fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000565#endif
566 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000567}
568
Chris Allegretta6df90f52002-07-19 01:08:59 +0000569void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000570{
571 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000572 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000573
Chris Allegretta6df90f52002-07-19 01:08:59 +0000574 assert(fileage == NULL || fileage != fileage->next);
575 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000576 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577}
578
Chris Allegretta6df90f52002-07-19 01:08:59 +0000579void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000581 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000582 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000583 else {
584 int lineno = fileptr->prev->lineno;
585
586 assert(fileptr != fileptr->next);
587 for (; fileptr != NULL; fileptr = fileptr->next)
588 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000589 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590}
591
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000592/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000593 * strings to translate and takes out the parts that shouldn't be
594 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000595void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000596 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000597{
598 printf(" %s\t", shortflag);
599 if (strlen(shortflag) < 8)
600 printf("\t");
601
602#ifdef HAVE_GETOPT_LONG
603 printf("%s\t", longflag);
604 if (strlen(longflag) < 8)
605 printf("\t\t");
606 else if (strlen(longflag) < 16)
607 printf("\t");
608#endif
609
610 printf("%s\n", desc);
611}
612
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000613void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000614{
615#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000616 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
617 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000618#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000619 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
620 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000621#endif /* HAVE_GETOPT_LONG */
622
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000623 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000624 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000625#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000626 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000627 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000628#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000629#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000630 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000631#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000632#ifdef ENABLE_NANORC
Chris Allegretta36fec722003-01-22 01:13:25 +0000633 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000634 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
635#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000636#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000637 print1opt("-M", "--mac", _("Write file in Mac format"));
638 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000639#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000640#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000641 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000642#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000643#ifdef HAVE_REGEX_H
644 print1opt("-R", "--regexp", _("Do regular expression searches"));
645#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000646#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000647 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000648#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000649 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000650 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000651#ifdef ENABLE_COLOR
652 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
653#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000654 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000655#ifndef NANO_SMALL
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +0000656 print1opt("-d", "--rebinddelete", _("Fix Backspace if it acts like Delete"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000657 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
658 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000659#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000660 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000661#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000662 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000663#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000664#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000665 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000666#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000667 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000668#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000669 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000670#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000671#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000672 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000673#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000674 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
675 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000676#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000677 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000678#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000679 print1opt("-x", "--nohelp", _("Don't show help window"));
680 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000681
682 /* this is a special case */
683 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000684
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000685 exit(0);
686}
687
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000688void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000689{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000690 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000691 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000692 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000693 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000694 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000695
Chris Allegrettae6600372003-01-17 03:39:41 +0000696#ifndef ENABLE_NLS
697 printf(" --disable-nls");
698#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000699#ifdef DEBUG
700 printf(" --enable-debug");
701#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000702#ifdef NANO_EXTRA
703 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000704#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000705#ifdef NANO_SMALL
706 printf(" --enable-tiny");
707#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000708#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000709 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000710#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000711#ifdef DISABLE_HELP
712 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000713#endif
714#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000715 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000716#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000717#if defined(DISABLE_MOUSE) || !defined(NCURSES_MOUSE_VERSION)
Chris Allegretta84de5522001-04-12 14:51:48 +0000718 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000719#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000720#ifdef DISABLE_OPERATINGDIR
721 printf(" --disable-operatingdir");
722#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000723#ifdef DISABLE_SPELLER
724 printf(" --disable-speller");
725#endif
726#ifdef DISABLE_TABCOMP
727 printf(" --disable-tabcomp");
728#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000729#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000730#ifdef DISABLE_WRAPPING
731 printf(" --disable-wrapping");
732#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000733#ifdef DISABLE_ROOTWRAP
734 printf(" --disable-wrapping-as-root");
735#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000736#ifdef ENABLE_COLOR
737 printf(" --enable-color");
738#endif
739#ifdef ENABLE_MULTIBUFFER
740 printf(" --enable-multibuffer");
741#endif
742#ifdef ENABLE_NANORC
743 printf(" --enable-nanorc");
744#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000745#ifdef USE_SLANG
746 printf(" --with-slang");
747#endif
748 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000749}
750
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000751/* Stuff we do when we abort from programs and want to clean up the
752 * screen. This doesn't do much right now. */
753void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000754{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000755 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000756}
757
758int no_help(void)
759{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000760 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000761}
762
Chris Allegrettad865da12002-07-29 23:46:38 +0000763#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000764void nano_disabled_msg(void)
765{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000766 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000767}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000768#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000769
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000770#ifndef NANO_SMALL
771static int pid; /* This is the PID of the newly forked process
772 * below. It must be global since the signal
773 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000774RETSIGTYPE cancel_fork(int signal)
775{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000776 if (kill(pid, SIGKILL) == -1)
777 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000778}
779
780int open_pipe(const char *command)
781{
782 int fd[2];
783 FILE *f;
784 struct sigaction oldaction, newaction;
785 /* original and temporary handlers for SIGINT */
786#ifdef _POSIX_VDISABLE
787 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000788#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000789 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000790 /* cancel_sigs == 1 means that sigaction() failed without changing
791 * the signal handlers. cancel_sigs == 2 means the signal handler
792 * was changed, but the tcsetattr didn't succeed.
793 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000794 * I use this variable since it is important to put things back when
795 * we finish, even if we get errors. */
796
797 /* Make our pipes. */
798
799 if (pipe(fd) == -1) {
800 statusbar(_("Could not pipe"));
801 return 1;
802 }
803
804 /* Fork a child. */
805
806 if ((pid = fork()) == 0) {
807 close(fd[0]);
808 dup2(fd[1], fileno(stdout));
809 dup2(fd[1], fileno(stderr));
810 /* If execl() returns at all, there was an error. */
811
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000812 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000813 exit(0);
814 }
815
816 /* Else continue as parent. */
817
818 close(fd[1]);
819
820 if (pid == -1) {
821 close(fd[0]);
822 statusbar(_("Could not fork"));
823 return 1;
824 }
825
826 /* Before we start reading the forked command's output, we set
827 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000828 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000829 cancel_sigs = 1;
830 nperror("sigaction");
831 } else {
832 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000833 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000834 cancel_sigs = 1;
835 nperror("sigaction");
836 }
837 }
838 /* Note that now oldaction is the previous SIGINT signal handler,
839 * to be restored later. */
840
841 /* See if the platform supports disabling individual control
842 * characters. */
843#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000844 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000845 cancel_sigs = 2;
846 nperror("tcgetattr");
847 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000848 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000849 newterm = term;
850 /* Grab oldterm's VINTR key :-) */
851 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
852 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
853 cancel_sigs = 2;
854 nperror("tcsetattr");
855 }
856 }
857#endif /* _POSIX_VDISABLE */
858
859 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000860 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000861 nperror("fdopen");
862
863 read_file(f, "stdin", 0);
864 /* if multibuffer mode is on, we could be here in view mode; if so,
865 don't set the modification flag */
866 if (!ISSET(VIEW_MODE))
867 set_modified();
868
869 if (wait(NULL) == -1)
870 nperror("wait");
871
872#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000873 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000874 nperror("tcsetattr");
875#endif /* _POSIX_VDISABLE */
876
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000877 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000878 nperror("sigaction");
879
880 return 0;
881}
882#endif /* NANO_SMALL */
883
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000884#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000885void do_mouse(void)
886{
887 MEVENT mevent;
888 int currslen;
889 const shortcut *s = currshortcut;
890
891 if (getmouse(&mevent) == ERR)
892 return;
893
894 /* If mouse not in edit or bottom window, return */
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000895 if (wenclose(edit, mevent.y, mevent.x) && currshortcut == main_list) {
896 int sameline;
897 /* Did they click on the line with the cursor? If they
898 clicked on the cursor, we set the mark. */
899 size_t xcur;
900 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000901
902 /* Subtract out size of topwin. Perhaps we need a constant
903 * somewhere? */
904 mevent.y -= 2;
905
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000906 sameline = mevent.y == current_y;
907
908 /* Move to where the click occurred. */
909 for(; current_y < mevent.y && current->next != NULL; current_y++)
910 current = current->next;
911 for(; current_y > mevent.y && current->prev != NULL; current_y--)
912 current = current->prev;
913
914 xcur = actual_x(current, get_page_start(xplustabs()) + mevent.x);
915
916 /* Selecting where the cursor is toggles the mark. As does
917 selecting beyond the line length with the cursor at the end of
918 the line. */
919 if (sameline && xcur == current_x) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000920 if (ISSET(VIEW_MODE)) {
921 print_view_warning();
922 return;
923 }
924 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000925 }
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000926
927 current_x = xcur;
928 placewewant = xplustabs();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000929 edit_refresh();
930 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
931 int i, k;
932
933 if (currshortcut == main_list)
934 currslen = MAIN_VISIBLE;
935 else
936 currslen = length_of_list(currshortcut);
937
938 if (currslen < 2)
939 k = COLS / 6;
940 else
941 k = COLS / ((currslen + (currslen %2)) / 2);
942
943 /* Determine what shortcut list was clicked */
944 mevent.y -= (editwinrows + 3);
945
946 if (mevent.y < 0) /* They clicked on the statusbar */
947 return;
948
949 /* Don't select stuff beyond list length */
950 if (mevent.x / k >= currslen)
951 return;
952
953 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
954 s = s->next;
955
956 /* And ungetch that value */
957 ungetch(s->val);
958
959 /* And if it's an alt-key sequence, we should probably send alt
960 too ;-) */
961 if (s->val >= 'a' && s->val <= 'z')
962 ungetch(27);
963 }
964}
965#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000966
Chris Allegretta6df90f52002-07-19 01:08:59 +0000967/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000968void do_char(char ch)
969{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000970 size_t current_len = strlen(current->data);
971#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
972 int refresh = 0;
973 /* Do we have to run edit_refresh(), or can we get away with
974 * update_line()? */
975#endif
976
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000977 /* magic-line: when a character is inserted on the current magic line,
978 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000979 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000980 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000981 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000982 }
983
Chris Allegretta6df90f52002-07-19 01:08:59 +0000984 /* more dangerousness fun =) */
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +0000985 current->data = charealloc(current->data, current_len + 2);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000986 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000987 memmove(&current->data[current_x + 1],
988 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +0000989 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000990 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000991 totsize++;
992 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000993
Chris Allegretta6df90f52002-07-19 01:08:59 +0000994#ifndef NANO_SMALL
995 /* note that current_x has not yet been incremented */
996 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000997 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +0000998#endif
999
Chris Allegretta6df90f52002-07-19 01:08:59 +00001000 do_right();
1001
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001002#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001003 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001004 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001005#endif
1006
Chris Allegretta6df90f52002-07-19 01:08:59 +00001007#ifdef ENABLE_COLOR
1008 refresh = 1;
1009#endif
1010
1011#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1012 if (refresh)
1013 edit_refresh();
1014#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001015}
1016
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001017int do_backspace(void)
1018{
1019 int refresh = 0;
1020 if (current_x > 0) {
1021 assert(current_x <= strlen(current->data));
1022 /* Let's get dangerous */
1023 memmove(&current->data[current_x - 1], &current->data[current_x],
1024 strlen(current->data) - current_x + 1);
1025#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001026 fprintf(stderr, "current->data now = \"%s\"\n", current->data);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001027#endif
1028 align(&current->data);
1029#ifndef NANO_SMALL
1030 if (current_x <= mark_beginx && mark_beginbuf == current)
1031 mark_beginx--;
1032#endif
1033 do_left();
1034#ifdef ENABLE_COLOR
1035 refresh = 1;
1036#endif
1037 } else {
1038 filestruct *previous;
1039 const filestruct *tmp;
1040
1041 if (current == fileage)
1042 return 0; /* Can't delete past top of file */
1043
1044 previous = current->prev;
1045 current_x = strlen(previous->data);
1046 placewewant = strlenpt(previous->data);
1047#ifndef NANO_SMALL
1048 if (current == mark_beginbuf) {
1049 mark_beginx += current_x;
1050 mark_beginbuf = previous;
1051 }
1052#endif
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001053 previous->data = charealloc(previous->data,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001054 current_x + strlen(current->data) + 1);
1055 strcpy(previous->data + current_x, current->data);
1056
1057 unlink_node(current);
1058 delete_node(current);
1059 tmp = current;
1060 current = (previous->next ? previous->next : previous);
1061 renumber(current);
1062 /* We had to renumber before doing update_line. */
1063 if (tmp == edittop)
1064 page_up();
1065
1066 /* Ooops, sanity check */
1067 if (tmp == filebot) {
1068 filebot = current;
1069 editbot = current;
1070
1071 /* Recreate the magic line if we're deleting it AND if the
1072 line we're on now is NOT blank. if it is blank we
1073 can just use IT for the magic line. This is how Pico
1074 appears to do it, in any case. */
1075 if (current->data[0] != '\0') {
1076 new_magicline();
1077 fix_editbot();
1078 }
1079 }
1080
1081 current = previous;
1082 if (current_y > 0)
1083 current_y--;
1084 totlines--;
1085#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00001086 fprintf(stderr, "After, data = \"%s\"\n", current->data);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001087#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001088 refresh = 1;
1089 }
1090
1091 totsize--;
1092 set_modified();
1093 if (refresh)
1094 edit_refresh();
1095 return 1;
1096}
1097
1098int do_delete(void)
1099{
1100 int refresh = 0;
1101
1102 /* blbf -> blank line before filebot (see below) */
1103 int blbf = 0;
1104
1105 if (current->next == filebot && current->data[0] == '\0')
1106 blbf = 1;
1107
1108 placewewant = xplustabs();
1109
1110 if (current_x != strlen(current->data)) {
1111 /* Let's get dangerous */
1112 memmove(&current->data[current_x], &current->data[current_x + 1],
1113 strlen(current->data) - current_x);
1114
1115 align(&current->data);
1116#ifdef ENABLE_COLOR
1117 refresh = 1;
1118#endif
1119 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1120 /* We can delete the line before filebot only if it is blank: it
1121 becomes the new magic line then. */
1122
1123 filestruct *foo;
1124
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001125 current->data = charealloc(current->data,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001126 strlen(current->data) +
1127 strlen(current->next->data) + 1);
1128 strcat(current->data, current->next->data);
1129
1130 foo = current->next;
1131 if (filebot == foo) {
1132 filebot = current;
1133 editbot = current;
1134 }
1135
1136 unlink_node(foo);
1137 delete_node(foo);
1138 renumber(current);
1139 totlines--;
1140 refresh = 1;
1141 } else
1142 return 0;
1143
1144 totsize--;
1145 set_modified();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001146 update_line(current, current_x);
1147 if (refresh)
1148 edit_refresh();
1149 return 1;
1150}
1151
1152int do_tab(void)
1153{
1154 do_char('\t');
1155 return 1;
1156}
1157
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001158/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001159int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001160{
Chris Allegrettae3167732001-03-18 16:59:34 +00001161 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001162 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001163
Chris Allegretta6df90f52002-07-19 01:08:59 +00001164 newnode = make_new_node(current);
1165 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001166 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001167
Chris Allegrettaff989832001-09-17 13:48:00 +00001168#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001169 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001170 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001171 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001172 const char *spc = current->data;
1173
1174 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001175 extra++;
1176 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001178 /* If current_x < extra, then we are breaking the line in the
1179 * indentation. Autoindenting should add only current_x
1180 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001181 if (current_x < extra)
1182 extra = current_x;
1183 else
1184 current_x = extra;
1185 totsize += extra;
1186
1187 newnode->data = charalloc(strlen(tmp) + extra + 1);
1188 strncpy(newnode->data, current->data, extra);
1189 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001190 } else
1191#endif
1192 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001193 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001194 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001195 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001196 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001197 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001198
Chris Allegretta6df90f52002-07-19 01:08:59 +00001199 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001200 filebot = newnode;
1201 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001202 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001203 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001204
1205 totsize++;
1206 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001207 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001208 align(&current->data);
1209
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001210 /* The logic here is as follows:
1211 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001212 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001213 * -> otherwise, we want simply to redraw the screen and update
1214 * where we think the cursor is.
1215 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001216 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001217#ifndef NANO_SMALL
1218 if (ISSET(SMOOTHSCROLL))
1219 edit_update(current, NONE);
1220 else
1221#endif
1222 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001223 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001224 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001225 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001226 edit_refresh();
1227 update_cursor();
1228 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001229
1230 totlines++;
1231 set_modified();
1232
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001233 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001234 return 1;
1235}
1236
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001237#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001238int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001239{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001240 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001241
Chris Allegretta6df90f52002-07-19 01:08:59 +00001242 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001243
Chris Allegretta6df90f52002-07-19 01:08:59 +00001244 /* Skip letters in this word first. */
1245 while (current->data[current_x] != '\0' &&
1246 isalnum((int)current->data[current_x]))
1247 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001248
Chris Allegretta6df90f52002-07-19 01:08:59 +00001249 for (; current != NULL; current = current->next) {
1250 while (current->data[current_x] != '\0' &&
1251 !isalnum((int)current->data[current_x]))
1252 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001253
Chris Allegretta6df90f52002-07-19 01:08:59 +00001254 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001255 break;
1256
Chris Allegretta6df90f52002-07-19 01:08:59 +00001257 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001258 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001259 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001260 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001261
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001262 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001263
Chris Allegrettad865da12002-07-29 23:46:38 +00001264 if (current->lineno >= editbot->lineno) {
1265 /* If we're on the last line, don't center the screen. */
1266 if (current->lineno == filebot->lineno)
1267 edit_refresh();
1268 else
1269 edit_update(current, CENTER);
1270 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001271 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001272 /* If we've jumped lines, refresh the old line. We can't just
1273 use current->prev here, because we may have skipped over some
1274 blank lines, in which case the previous line is the wrong
1275 one. */
1276 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001277 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001278 /* If the mark was set, then the lines between old and
1279 current have to be updated too. */
1280 if (ISSET(MARK_ISSET)) {
1281 while (old->next != current) {
1282 old = old->next;
1283 update_line(old, 0);
1284 }
1285 }
1286 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001287 update_line(current, current_x);
1288 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001289 return 0;
1290}
1291
Chris Allegretta6df90f52002-07-19 01:08:59 +00001292/* The same thing for backwards. */
1293int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001294{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001295 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001296
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001297 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001298
Chris Allegretta6df90f52002-07-19 01:08:59 +00001299 /* Skip letters in this word first. */
1300 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1301 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001302
Chris Allegretta6df90f52002-07-19 01:08:59 +00001303 for (; current != NULL; current = current->prev) {
1304 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1305 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001306
Chris Allegretta6df90f52002-07-19 01:08:59 +00001307 if (current_x >= 0)
1308 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001309
Chris Allegretta6df90f52002-07-19 01:08:59 +00001310 if (current->prev != NULL)
1311 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001312 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001313
Chris Allegretta6df90f52002-07-19 01:08:59 +00001314 if (current != NULL) {
1315 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1316 current_x--;
1317 } else {
1318 current = fileage;
1319 current_x = 0;
1320 }
1321
Chris Allegretta76e291b2001-10-14 19:05:10 +00001322 placewewant = xplustabs();
1323
Chris Allegrettad865da12002-07-29 23:46:38 +00001324 if (current->lineno <= edittop->lineno) {
1325 /* If we're on the first line, don't center the screen. */
1326 if (current->lineno == fileage->lineno)
1327 edit_refresh();
1328 else
1329 edit_update(current, CENTER);
1330 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001331 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001332 /* If we've jumped lines, refresh the old line. We can't just
1333 use current->prev here, because we may have skipped over some
1334 blank lines, in which case the previous line is the wrong
1335 one. */
1336 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001337 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001338 /* If the mark was set, then the lines between old and
1339 current have to be updated too. */
1340 if (ISSET(MARK_ISSET)) {
1341 while (old->prev != current) {
1342 old = old->prev;
1343 update_line(old, 0);
1344 }
1345 }
1346 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001347 update_line(current, current_x);
1348 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001349 return 0;
1350}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001351#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001352
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001353int do_mark(void)
1354{
1355#ifdef NANO_SMALL
1356 nano_disabled_msg();
1357#else
1358 if (!ISSET(MARK_ISSET)) {
1359 statusbar(_("Mark Set"));
1360 SET(MARK_ISSET);
1361 mark_beginbuf = current;
1362 mark_beginx = current_x;
1363 } else {
1364 statusbar(_("Mark UNset"));
1365 UNSET(MARK_ISSET);
1366 edit_refresh();
1367 }
1368#endif
1369 return 1;
1370}
1371
1372void wrap_reset(void)
1373{
1374 UNSET(SAMELINEWRAP);
1375}
1376
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001377#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001378/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001379 * moved forward since the last typed character. Return value:
1380 * whether we wrapped. */
1381int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001382{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001383 size_t len = strlen(inptr->data); /* length of the line we wrap */
1384 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001385 int wrap_loc = -1; /* index of inptr->data where we wrap */
1386 int word_back = -1;
1387#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001388 const char *indentation = NULL;
1389 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001390 int indent_len = 0; /* strlen(indentation) */
1391#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001392 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001393 int after_break_len; /* strlen(after_break) */
1394 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001395 const char *wrap_line = NULL;
1396 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001397 int wrap_line_len = 0; /* strlen(wrap_line) */
1398 char *newline = NULL; /* the line we create */
1399 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001400
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001401/* There are three steps. First, we decide where to wrap. Then, we
1402 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001403
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001404/* Step 1, finding where to wrap. We are going to add a new-line
1405 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001406 * location of this replacement.
1407 *
1408 * Where should we break the line? We need the last "legal wrap point"
1409 * such that the last word before it ended at or before fill. If there
1410 * is no such point, we settle for the first legal wrap point.
1411 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001412 * A "legal wrap point" is a white-space character that is not followed by
1413 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001414 *
1415 * If there is no legal wrap point or we found the last character of the
1416 * line, we should return without wrapping.
1417 *
1418 * Note that the initial indentation does not count as a legal wrap
1419 * point if we are going to auto-indent!
1420 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001421 * Note that the code below could be optimised, by not calling strnlenpt()
1422 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001423
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001424#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001425 if (ISSET(AUTOINDENT))
1426 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001427#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001428 wrap_line = inptr->data + i;
1429 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001430 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001431 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001432 word_back = i;
1433 /* if we have found a "legal wrap point" and the current word
1434 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001435 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001436 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001437 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001438 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001439 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001440 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001441 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001442 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001443
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001444/* Step 2, making the new wrap line. It will consist of indentation +
1445 * after_break + " " + wrap_line (although indentation and wrap_line are
1446 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001447
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001448 /* after_break is the text that will be moved to the next line. */
1449 after_break = inptr->data + wrap_loc + 1;
1450 after_break_len = len - wrap_loc - 1;
1451 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001452
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001453 /* new_line_len will later be increased by the lengths of indentation
1454 * and wrap_line. */
1455 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001456
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001457 /* We prepend the wrapped text to the next line, if the flag is set,
1458 * and there is a next line, and prepending would not make the line
1459 * too long. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +00001460 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001461 wrap_line = inptr->next->data;
1462 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001463
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001464 /* +1 for the space between after_break and wrap_line */
1465 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1466 wrapping = 1;
1467 new_line_len += (1 + wrap_line_len);
1468 }
1469 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001470
Chris Allegrettaff989832001-09-17 13:48:00 +00001471#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001472 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001473 /* Indentation comes from the next line if wrapping, else from
1474 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001475 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001476 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001477 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001478 /* The wrap_line text should not duplicate indentation.
1479 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001480 wrap_line += indent_len;
1481 else
1482 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001483 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001484#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001485
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001486 /* Now we allocate the new line and copy into it. */
1487 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1488 *newline = '\0';
1489
1490#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001491 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001492 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001493 newline[indent_len] = '\0';
1494 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001495#endif
1496 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001497 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001498 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001499 null_at(&inptr->data, wrap_loc + 1);
1500 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001501 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001502 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001503 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001504 * in a tab or a space, we don't add a space and decrement
1505 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001506 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001507 strcat(newline, " ");
1508 else
1509 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001510 strcat(newline, wrap_line);
1511 free(inptr->next->data);
1512 inptr->next->data = newline;
1513 } else {
1514 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001515
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001516 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001517 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001518#ifndef NANO_SMALL
1519 totsize += indent_len;
1520#endif
1521 totlines++;
1522 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001523 temp->prev = inptr;
1524 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001525 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001526 /* If temp->next is NULL, then temp is the last line of the
1527 * file, so we must set filebot. */
1528 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001529 temp->next->prev = temp;
1530 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001531 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001532 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001533
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001534/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1535 * other sundry things. */
1536
1537 /* later wraps of this line will be prepended to the next line. */
1538 SET(SAMELINEWRAP);
1539
1540 /* Each line knows its line number. We recalculate these if we
1541 * inserted a new line. */
1542 if (!wrapping)
1543 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001544
Chris Allegretta6df90f52002-07-19 01:08:59 +00001545 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001546 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001547 current = current->next;
1548 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001549#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001550 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001551#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001552 wrap_loc + 1;
1553 wrap_reset();
1554 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001555 }
1556
Chris Allegretta6df90f52002-07-19 01:08:59 +00001557#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001558 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001559 * If it was on the next line and we wrapped, we must move it
1560 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001561 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1562 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001563 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001564 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001565 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001566#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001567
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001568 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001569 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001570
1571 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001572}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001573#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001574
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001575#ifndef DISABLE_SPELLER
David Lawrence Ramseyaaad3af2003-08-31 16:44:10 +00001576/* A word is misspelled in the file. Let the user replace it. We
1577 * return False if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001578int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001579{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001580 char *save_search;
1581 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001582 filestruct *current_save = current;
1583 int current_x_save = current_x;
1584 filestruct *edittop_save = edittop;
1585 /* Save where we are. */
1586 int i = 0;
1587 /* The return value. */
1588 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001589#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001590 int case_sens_set = ISSET(CASE_SENSITIVE);
1591 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001592
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001593 SET(CASE_SENSITIVE);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001594 /* Make sure the marking highlight is off during Spell Check */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001595 UNSET(MARK_ISSET);
1596#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001597 /* Make sure Spell Check goes forward only */
1598 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001599
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001600 /* save the current search/replace strings */
1601 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001602 save_search = last_search;
1603 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001604
1605 /* set search/replace strings to mis-spelt word */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001606 last_search = mallocstrcpy(NULL, word);
1607 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001608
1609 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001610 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001611 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001612
1613 search_last_line = FALSE;
1614
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001615 /* We find the first whole-word occurrence of word. */
1616 while (findnextstr(TRUE, TRUE, fileage, -1, word))
1617 if (is_whole_word(current_x, current->data, word)) {
1618 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001619
Chris Allegretta6df90f52002-07-19 01:08:59 +00001620 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001621
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001622 /* allow replace word to be corrected */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001623 i = statusq(0, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001624#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001625 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001626#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001627 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001628
Chris Allegretta6df90f52002-07-19 01:08:59 +00001629 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001630
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001631 if (i != -1 && strcmp(word, answer)) {
1632 int j = 0;
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001633
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001634 search_last_line = FALSE;
1635 current_x--;
1636 do_replace_loop(word, current_save, &current_x_save, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001637 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001638
1639 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001640 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001641
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001642 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001643 free(last_search); last_search=save_search;
1644 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001645
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001646 /* restore where we were */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001647 current = current_save;
1648 current_x = current_x_save;
1649 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001650
Chris Allegretta23b74b22002-01-21 20:32:22 +00001651 /* restore Search/Replace direction */
1652 if (reverse_search_set)
1653 SET(REVERSE_SEARCH);
1654
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001655#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001656 if (!case_sens_set)
1657 UNSET(CASE_SENSITIVE);
1658
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001659 /* restore marking highlight */
1660 if (mark_set)
1661 SET(MARK_ISSET);
1662#endif
1663
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001664 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001665}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001666
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001667/* Integrated spell checking using 'spell' program. Return value: NULL
1668 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001669char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001670{
Chris Allegretta271e9722000-11-10 18:15:43 +00001671 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001672 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001673 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001674 pid_t pid_spell, pid_sort, pid_uniq;
1675 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001676
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001677 /* Create all three pipes up front */
Chris Allegretta271e9722000-11-10 18:15:43 +00001678
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001679 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1680 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001681
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001682 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001683 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001684
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001685 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001686
1687 /* Child continues, (i.e. future spell process) */
1688
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001689 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001690
Chris Allegretta271e9722000-11-10 18:15:43 +00001691 /* replace the standard in with the tempfile */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001692 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1693 goto close_pipes_and_exit;
1694
1695 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1696 goto close_pipes_and_exit;
1697
Chris Allegretta271e9722000-11-10 18:15:43 +00001698 close(tempfile_fd);
1699
1700 /* send spell's standard out to the pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001701 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1702 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001703
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001704 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001705
1706 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001707 execlp("spell", "spell", NULL);
1708
Chris Allegretta271e9722000-11-10 18:15:43 +00001709 /* Should not be reached, if spell is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001710 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001711 }
1712
1713 /* Parent continues here */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001714 close(spell_fd[1]);
1715
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001716 /* A new process to run sort in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001717 if ((pid_sort = fork()) == 0) {
1718
1719 /* Child continues, (i.e. future spell process) */
1720 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001721 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1722 goto close_pipes_and_exit;
1723
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001724 close(spell_fd[0]);
1725
1726 /* send sort's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001727 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1728 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001729
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001730 close(sort_fd[1]);
1731
1732 /* Start sort program. Use -f to remove mixed case without having
1733 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1734 execlp("sort", "sort", "-f", NULL);
1735
1736 /* Should not be reached, if sort is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001737 exit(1);
1738 }
1739
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001740 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001741 close(sort_fd[1]);
1742
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001743 /* A new process to run uniq in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001744 if ((pid_uniq = fork()) == 0) {
1745
1746 /* Child continues, (i.e. future uniq process) */
1747 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001748 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1749 goto close_pipes_and_exit;
1750
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001751 close(sort_fd[0]);
1752
1753 /* send uniq's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001754 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1755 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001756
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001757 close(uniq_fd[1]);
1758
1759 /* Start uniq program, we are using PATH */
1760 execlp("uniq", "uniq", NULL);
1761
1762 /* Should not be reached, if uniq is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001763 exit(1);
1764 }
1765
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001766 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001767 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001768
1769 /* Child process was not forked successfully */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001770 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1771 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001772 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001773 }
1774
Chris Allegretta271e9722000-11-10 18:15:43 +00001775 /* Get system pipe buffer size */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001776 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1777 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001778 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001779 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001780
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001781 /* Read-in the returned spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001782 read_buff_read = 0;
1783 read_buff_size = pipe_buff_size + 1;
1784 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001785
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001786 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001787 read_buff_read += bytesread;
1788 read_buff_size += pipe_buff_size;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001789 read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001790 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001791
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001792 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001793
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001794 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001795 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001796
1797 /* Process the spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001798 read_buff_word = read_buff_ptr = read_buff;
1799
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001800 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001801
1802 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001803 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001804 if (read_buff_word != read_buff_ptr) {
1805 if (!do_int_spell_fix(read_buff_word)) {
1806 read_buff_word = read_buff_ptr;
1807 break;
1808 }
1809 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001810 read_buff_word = read_buff_ptr + 1;
1811 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001812 read_buff_ptr++;
1813 }
1814
1815 /* special case where last word doesn't end with \n or \r */
1816 if (read_buff_word != read_buff_ptr)
1817 do_int_spell_fix(read_buff_word);
1818
Chris Allegretta271e9722000-11-10 18:15:43 +00001819 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001820 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001821 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001822
Chris Allegretta271e9722000-11-10 18:15:43 +00001823 /* Process end of spell process */
1824
Chris Allegretta334a9402002-12-16 04:25:53 +00001825 waitpid(pid_spell, &spell_status, 0);
1826 waitpid(pid_sort, &sort_status, 0);
1827 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001828
Chris Allegretta334a9402002-12-16 04:25:53 +00001829 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1830 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001831
Chris Allegretta334a9402002-12-16 04:25:53 +00001832 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1833 return _("Error invoking \"sort -f\"");
1834
1835 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1836 return _("Error invoking \"uniq\"");
1837
1838 /* Otherwise... */
1839 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001840
1841close_pipes_and_exit:
1842
1843 /* Don't leak any handles */
1844 close(tempfile_fd);
1845 close(spell_fd[0]);
1846 close(spell_fd[1]);
1847 close(sort_fd[0]);
1848 close(sort_fd[1]);
1849 close(uniq_fd[0]);
1850 close(uniq_fd[1]);
1851 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001852}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001853
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001854/* External spell checking. Return value: NULL for normal termination,
1855 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001856char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001857{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001858 int alt_spell_status, lineno_cur = current->lineno;
1859 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001860 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001861 char *ptr;
1862 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001863 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001864#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001865 int mark_set = ISSET(MARK_ISSET);
1866 int mbb_lineno_cur = 0;
1867 /* We're going to close the current file, and open the output of
1868 the alternate spell command. The line that mark_beginbuf
1869 points to will be freed, so we save the line number and restore
1870 afterwards. */
1871
1872 if (mark_set) {
1873 mbb_lineno_cur = mark_beginbuf->lineno;
1874 UNSET(MARK_ISSET);
1875 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001876#endif
1877
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001878 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001879
Chris Allegrettae434b452001-01-27 19:25:00 +00001880 /* Set up an argument list to pass the execvp function */
1881 if (spellargs == NULL) {
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001882 spellargs = (char **)nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001883
Chris Allegrettae434b452001-01-27 19:25:00 +00001884 spellargs[0] = strtok(alt_speller, " ");
1885 while ((ptr = strtok(NULL, " ")) != NULL) {
1886 arglen++;
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00001887 spellargs = (char **)nrealloc(spellargs, arglen * sizeof(char *));
Chris Allegrettae434b452001-01-27 19:25:00 +00001888 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001889 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001890 spellargs[arglen - 1] = NULL;
1891 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001892 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001893
1894 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001895 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001896 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001897 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001898
1899 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001900 exit(1);
1901 }
1902
1903 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001904 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001905 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001906
1907 /* Wait for alternate speller to complete */
1908
1909 wait(&alt_spell_status);
Chris Allegretta334a9402002-12-16 04:25:53 +00001910 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1911 char *altspell_error = NULL;
1912 char *invoke_error = _("Could not invoke \"%s\"");
1913 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1914
1915 altspell_error = charalloc(msglen);
1916 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1917 return altspell_error;
1918 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001919
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001920 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001921 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001922 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001923 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001924
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001925#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001926 if (mark_set) {
1927 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1928 mark_beginbuf = current;
1929 mark_beginx = current_x;
1930 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001931 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001932 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001933#endif
1934
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001935 /* go back to the old position, mark the file as modified, and make
1936 sure that the titlebar is refreshed */
1937 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001938 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001939 clearok(topwin, FALSE);
1940 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001941
Chris Allegretta334a9402002-12-16 04:25:53 +00001942 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001943}
1944#endif
1945
1946int do_spell(void)
1947{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001948#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001949 nano_disabled_msg();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001950 return TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001951#else
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001952 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001953
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001954 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001955 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001956 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001957 return 0;
1958 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001959
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001960 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001961 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001962 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001963 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001964 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001965
Chris Allegrettae1f14522001-09-19 03:19:43 +00001966#ifdef ENABLE_MULTIBUFFER
1967 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001968 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00001969 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001970#endif
1971
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001972 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00001973 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001974 else
Chris Allegretta334a9402002-12-16 04:25:53 +00001975 spell_msg = do_int_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001976 remove(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001977 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001978
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001979 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00001980 statusbar(_("Spell checking failed: %s"), spell_msg);
1981 return 0;
1982 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001983
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001984 statusbar(_("Finished checking spelling"));
1985 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00001986#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00001987}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001988
Chris Allegrettad865da12002-07-29 23:46:38 +00001989#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001990/* The "indentation" of a line is the white-space between the quote part
1991 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001992size_t indent_length(const char *line)
1993{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001994 size_t len = 0;
1995
1996 assert(line != NULL);
1997 while (*line == ' ' || *line == '\t') {
1998 line++;
1999 len++;
2000 }
2001 return len;
2002}
Chris Allegrettadffa2072002-07-24 01:02:26 +00002003#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002004
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002005#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00002006/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
2007 * it maintains 2 after a . ! or ?). Note the terminating \0
2008 * counts as a space.
2009 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002010 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00002011 * returns 1, otherwise returns 0.
2012 *
2013 * If changes_allowed, justify_format() might make line->data
2014 * shorter, and change the actual pointer with null_at().
2015 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002016 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002017 * skip should be at most strlen(line->data). The skip+1st character must
2018 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002019int justify_format(int changes_allowed, filestruct *line, size_t skip)
2020{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002021 const char *punct = ".?!";
2022 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00002023 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002024
Chris Allegretta6df90f52002-07-19 01:08:59 +00002025 /* These four asserts are assumptions about the input data. */
2026 assert(line != NULL);
2027 assert(line->data != NULL);
Chris Allegrettad8451932003-03-11 03:50:40 +00002028 assert(skip < strlen(line->data));
Chris Allegretta6df90f52002-07-19 01:08:59 +00002029 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002030
Chris Allegretta6df90f52002-07-19 01:08:59 +00002031 back = line->data + skip;
2032 front = back;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002033 for (front = back; ; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002034 int remove_space = 0;
2035 /* Do we want to remove this space? */
2036
Chris Allegretta6df90f52002-07-19 01:08:59 +00002037 if (*front == '\t') {
2038 if (!changes_allowed)
2039 return 1;
2040 *front = ' ';
2041 }
2042 /* these tests are safe since line->data + skip is not a space */
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002043 if ((*front == '\0' || *front == ' ') && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002044 const char *bob = front - 2;
2045
2046 remove_space = 1;
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002047 for (bob = back - 2; bob >= line->data + skip; bob--) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002048 if (strchr(punct, *bob) != NULL) {
2049 remove_space = 0;
2050 break;
2051 }
2052 if (strchr(brackets, *bob) == NULL)
2053 break;
2054 }
2055 }
2056
2057 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002058 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002059 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002060 if (!changes_allowed)
2061 return 1;
2062#ifndef NANO_SMALL
2063 if (mark_beginbuf == line && back - line->data < mark_beginx)
2064 mark_beginx--;
2065#endif
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002066 if (*front == '\0')
2067 *(back - 1) = '\0';
Chris Allegretta6df90f52002-07-19 01:08:59 +00002068 } else {
2069 *back = *front;
2070 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002071 }
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002072 if (*front == '\0')
2073 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002074 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002075
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002076 back--;
Chris Allegrettad8451932003-03-11 03:50:40 +00002077 assert(*back == '\0' && *front == '\0');
Chris Allegretta6df90f52002-07-19 01:08:59 +00002078
2079 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002080 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002081
2082 /* Now back is the new end of line->data. */
2083 if (back != front) {
Chris Allegrettad8451932003-03-11 03:50:40 +00002084 totsize -= front - back;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002085 null_at(&line->data, back - line->data);
2086#ifndef NANO_SMALL
2087 if (mark_beginbuf == line && back - line->data < mark_beginx)
2088 mark_beginx = back - line->data;
2089#endif
2090 }
2091 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002092}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002093
2094/* The "quote part" of a line is the largest initial substring matching
2095 * the quote string. This function returns the length of the quote part
2096 * of the given line.
2097 *
2098 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2099 * quotestr. */
2100#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002101size_t quote_length(const char *line, const regex_t *qreg)
2102{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002103 regmatch_t matches;
2104 int rc = regexec(qreg, line, 1, &matches, 0);
2105
2106 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2107 return 0;
2108 /* matches.rm_so should be 0, since the quote string should start with
2109 * the caret ^. */
2110 return matches.rm_eo;
2111}
2112#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002113size_t quote_length(const char *line)
2114{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002115 size_t qdepth = 0;
2116 size_t qlen = strlen(quotestr);
2117
2118 /* Compute quote depth level */
2119 while (!strcmp(line + qdepth, quotestr))
2120 qdepth += qlen;
2121 return qdepth;
2122}
2123#endif /* !HAVE_REGEX_H */
2124
Chris Allegretta6df90f52002-07-19 01:08:59 +00002125/* a_line and b_line are lines of text. The quotation part of a_line is
2126 * the first a_quote characters. Check that the quotation part of
2127 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002128int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002129 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002130{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002131 /* Here is the assumption about a_quote: */
2132 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002133 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002134 !strncmp(a_line, b_line, a_quote);
2135}
2136
2137/* We assume a_line and b_line have no quote part. Then, we return whether
2138 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002139size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002140 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002141{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002142 assert(a_indent == indent_length(a_line));
2143 assert(b_indent == indent_length(b_line));
2144
2145 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2146}
2147
2148/* Put the next par_len lines, starting with first_line, in the cut
2149 * buffer. We assume there are enough lines after first_line. We leave
2150 * copies of the lines in place, too. We return the new copy of
2151 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002152filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002153 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002154{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002155 /* We put the original lines, not copies, into the cut buffer, just
2156 * out of a misguided sense of consistency, so if you un-cut, you
2157 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002158 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002159
2160 set_modified();
2161 cutbuffer = NULL;
2162 for(; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002163 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002164
Chris Allegretta908f7702003-01-15 11:18:58 +00002165 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002166 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002167 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002168 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002169 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002170 edittop = bob;
2171#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002172 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002173 mark_beginbuf = bob;
2174#endif
2175 justify_format(1, bob,
2176 quote_len + indent_length(bob->data + quote_len));
2177
Chris Allegretta908f7702003-01-15 11:18:58 +00002178 assert(alice != NULL && bob != NULL);
2179 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002180 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002181 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002182 }
2183 return first_line;
2184}
2185
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002186/* Is it possible to break line at or before goal? */
2187int breakable(const char *line, int goal)
2188{
2189 for(; *line != '\0' && goal >= 0; line++) {
2190 if (*line == ' ' || *line == '\t')
2191 return TRUE;
2192
2193 if (is_cntrl_char(*line) != 0)
2194 goal -= 2;
2195 else
2196 goal -= 1;
2197 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002198 /* If goal is not negative, the whole line (one word) was short
2199 * enough. */
2200 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002201}
2202
Chris Allegretta6df90f52002-07-19 01:08:59 +00002203/* We are trying to break a chunk off line. We find the last space such
2204 * that the display length to there is at most goal + 1. If there is
2205 * no such space, and force is not 0, then we find the first space.
2206 * Anyway, we then take the last space in that group of spaces. The
2207 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002208int break_line(const char *line, int goal, int force)
2209{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002210 /* Note that we use int instead of size_t, since goal is at most COLS,
2211 * the screen width, which will always be reasonably small. */
2212 int space_loc = -1;
2213 /* Current tentative return value. Index of the last space we
2214 * found with short enough display width. */
2215 int cur_loc = 0;
2216 /* Current index in line */
2217
2218 assert(line != NULL);
2219 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2220 if (*line == ' ')
2221 space_loc = cur_loc;
2222 assert(*line != '\t');
2223
Chris Allegrettacf287c82002-07-20 13:57:41 +00002224 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002225 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002226 else
2227 goal--;
2228 }
2229 if (goal >= 0)
2230 /* In fact, the whole line displays shorter than goal. */
2231 return cur_loc;
2232 if (space_loc == -1) {
2233 /* No space found short enough. */
2234 if (force)
2235 for(; *line != '\0'; line++, cur_loc++)
Chris Allegrettaa7a78de2003-02-19 22:27:53 +00002236 if (*line == ' ' && *(line + 1) != ' ' && *(line + 1) != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002237 return cur_loc;
2238 return -1;
2239 }
2240 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002241 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002242 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2243 *(line - cur_loc + space_loc + 1) == '\0')
2244 space_loc++;
2245 return space_loc;
2246}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002247
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002248/* This function performs operations on paragraphs: justify, go to
2249 * beginning, and go to end. */
2250int do_para_operation(int operation)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002251{
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002252/* operation == 0 means we're justifying the paragraph, operation == 1
2253 * means we're moving to the beginning line of the paragraph, and
2254 * operation == 2 means we're moving to the ending line of the
2255 * paragraph.
2256 *
2257 * To explain the justifying algorithm, I first need to define some
Chris Allegretta6df90f52002-07-19 01:08:59 +00002258 * phrases about paragraphs and quotation:
2259 * A line of text consists of a "quote part", followed by an
2260 * "indentation part", followed by text. The functions quote_length()
2261 * and indent_length() calculate these parts.
2262 *
2263 * A line is "part of a paragraph" if it has a part not in the quote
2264 * part or the indentation.
2265 *
2266 * A line is "the beginning of a paragraph" if it is part of a paragraph
2267 * and
2268 * 1) it is the top line of the file, or
2269 * 2) the line above it is not part of a paragraph, or
2270 * 3) the line above it does not have precisely the same quote
2271 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002272 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002273 * indentation of the previous line, or
2274 * 5) this line has no quote part and some indentation, and
2275 * AUTOINDENT is not set.
2276 * The reason for number 5) is that if AUTOINDENT is not set, then an
2277 * indented line is expected to start a paragraph, like in books. Thus,
2278 * nano can justify an indented paragraph only if AUTOINDENT is turned
2279 * on.
2280 *
2281 * A contiguous set of lines is a "paragraph" if each line is part of
2282 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002283 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002284
Chris Allegretta6df90f52002-07-19 01:08:59 +00002285 size_t quote_len;
2286 /* Length of the initial quotation of the paragraph we justify. */
2287 size_t par_len;
2288 /* Number of lines in that paragraph. */
2289 filestruct *first_mod_line = NULL;
2290 /* Will be the first line of the resulting justified paragraph
2291 * that differs from the original. For restoring after uncut. */
2292 filestruct *last_par_line = current;
2293 /* Will be the last line of the result, also for uncut. */
2294 filestruct *cutbuffer_save = cutbuffer;
2295 /* When the paragraph gets modified, all lines from the changed
2296 * one down are stored in the cut buffer. We back up the original
2297 * to restore it later. */
2298
2299 /* We save these global variables to be restored if the user
2300 * unjustifies. Note we don't need to save totlines. */
2301 int current_x_save = current_x;
2302 int current_y_save = current_y;
2303 filestruct *current_save = current;
2304 int flags_save = flags;
2305 long totsize_save = totsize;
2306 filestruct *edittop_save = edittop;
2307 filestruct *editbot_save = editbot;
2308#ifndef NANO_SMALL
2309 filestruct *mark_beginbuf_save = mark_beginbuf;
2310 int mark_beginx_save = mark_beginx;
2311#endif
2312
2313 size_t indent_len; /* generic indentation length */
2314 filestruct *line; /* generic line of text */
2315 size_t i; /* generic loop variable */
2316
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002317 static int no_restart = 0;
2318 /* whether we're blocking restarting when searching for the
2319 * beginning line of the paragraph */
2320
Chris Allegretta6df90f52002-07-19 01:08:59 +00002321#ifdef HAVE_REGEX_H
2322 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002323 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002324 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2325
2326 if (rc) {
2327 size_t size = regerror(rc, &qreg, NULL, 0);
2328 char *strerror = charalloc(size);
2329
2330 regerror(rc, &qreg, strerror, size);
2331 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2332 free(strerror);
2333 return -1;
2334 }
2335#endif
2336
2337 /* Here is an assumption that is always true anyway. */
2338 assert(current != NULL);
2339
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002340 current_x = 0;
2341
2342 restart_bps:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002343/* Here we find the first line of the paragraph to justify. If the
2344 * current line is in a paragraph, then we move back to the first line.
2345 * Otherwise we move down to the first line that is in a paragraph. */
2346 quote_len = quote_length(IFREG(current->data, &qreg));
2347 indent_len = indent_length(current->data + quote_len);
2348
2349 if (current->data[quote_len + indent_len] != '\0') {
2350 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002351 * the first line of this paragraph. First we check items 1) and
2352 * 3) above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002353 while (current->prev != NULL && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002354 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002355 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002356 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002357 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002358
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002359 /* Is this line the beginning of a paragraph, according to
2360 items 2), 5), or 4) above? If so, stop. */
2361 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2362 (quote_len == 0 && indent_len > 0
2363#ifndef NANO_SMALL
2364 && !ISSET(AUTOINDENT)
2365#endif
2366 ) ||
2367 !indents_match(current->prev->data + quote_len,
2368 temp_id_len, current->data + quote_len, indent_len))
2369 break;
2370 indent_len = temp_id_len;
2371 current = current->prev;
2372 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002373 }
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002374 } else if (operation == 1) {
2375 /* This line is not part of a paragraph. Move up until we get
2376 * to a non "blank" line, and then move down once. */
2377 do {
2378 /* There is no previous paragraph, so nothing to move to. */
2379 if (current->prev == NULL) {
2380 placewewant = 0;
2381 if (current_y < 0)
2382 edit_update(current, CENTER);
2383 else
2384 edit_refresh();
2385 return 0;
2386 }
2387 current = current->prev;
2388 current_y--;
2389 quote_len = quote_length(IFREG(current->data, &qreg));
2390 indent_len = indent_length(current->data + quote_len);
2391 } while (current->data[quote_len + indent_len] == '\0');
2392 current = current->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002393 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002394 /* This line is not part of a paragraph. Move down until we get
2395 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002396 do {
2397 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002398 if (current->next == NULL) {
2399 placewewant = 0;
Chris Allegretta428f6202003-02-12 03:21:45 +00002400 edit_refresh();
2401#ifdef HAVE_REGEX_H
2402 regfree(&qreg);
2403#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002404 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002405 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002406 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002407 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002408 quote_len = quote_length(IFREG(current->data, &qreg));
2409 indent_len = indent_length(current->data + quote_len);
2410 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002411 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002412/* Now current is the first line of the paragraph, and quote_len
2413 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002414
Chris Allegretta6df90f52002-07-19 01:08:59 +00002415/* Next step, compute par_len, the number of lines in this paragraph. */
2416 line = current;
2417 par_len = 1;
2418 indent_len = indent_length(line->data + quote_len);
2419
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002420 while (line->next != NULL && quotes_match(current->data, quote_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002421 IFREG(line->next->data, &qreg))) {
2422 size_t temp_id_len = indent_length(line->next->data + quote_len);
2423
2424 if (!indents_match(line->data + quote_len, indent_len,
2425 line->next->data + quote_len, temp_id_len) ||
2426 line->next->data[quote_len + temp_id_len] == '\0' ||
2427 (quote_len == 0 && temp_id_len > 0
2428#ifndef NANO_SMALL
2429 && !ISSET(AUTOINDENT)
2430#endif
2431 ))
2432 break;
2433 indent_len = temp_id_len;
2434 line = line->next;
2435 par_len++;
2436 }
2437#ifdef HAVE_REGEX_H
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002438 /* We no longer need to check quotation, unless we're searching for
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002439 * the beginning of the paragraph. */
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002440 if (operation != 1)
2441 regfree(&qreg);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002442#endif
2443/* Now par_len is the number of lines in this paragraph. Should never
2444 * call quotes_match() or quote_length() again. */
2445
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002446 /* If we're searching for the beginning of the paragraph, skip the
2447 * justification. If we're searching for the end of the paragraph,
2448 * move down the number of lines in the paragraph and skip the
2449 * justification. */
2450 if (operation == 1)
2451 goto skip_justify;
2452 else if (operation == 2) {
2453 while (par_len > 0) {
2454 current = current->next;
2455 current_y++;
2456 par_len--;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002457 }
2458 goto skip_justify;
2459 }
2460
Chris Allegretta6df90f52002-07-19 01:08:59 +00002461/* Next step, we loop through the lines of this paragraph, justifying
2462 * each one individually. */
Chris Allegretta8151ba52003-04-19 19:34:05 +00002463 SET(JUSTIFY_MODE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002464 for(; par_len > 0; current_y++, par_len--) {
2465 size_t line_len;
2466 size_t display_len;
2467 /* The width of current in screen columns. */
2468 int break_pos;
2469 /* Where we will break the line. */
2470
2471 indent_len = indent_length(current->data + quote_len) +
2472 quote_len;
2473 /* justify_format() removes excess spaces from the line, and
2474 * changes tabs to spaces. The first argument, 0, means don't
2475 * change the line, just say whether there are changes to be
2476 * made. If there are, we do backup_lines(), which copies the
2477 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002478 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002479 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002480 first_mod_line = backup_lines(current, par_len, quote_len);
2481
2482 line_len = strlen(current->data);
2483 display_len = strlenpt(current->data);
2484
2485 if (display_len > fill) {
2486 /* The line is too long. Try to wrap it to the next. */
2487 break_pos = break_line(current->data + indent_len,
2488 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002489 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002490 if (break_pos == -1 || break_pos + indent_len == line_len)
2491 /* We can't break the line, or don't need to, so just go
2492 * on to the next. */
2493 goto continue_loc;
2494 break_pos += indent_len;
2495 assert(break_pos < line_len);
2496 /* If we haven't backed up the paragraph, do it now. */
2497 if (first_mod_line == NULL)
2498 first_mod_line = backup_lines(current, par_len, quote_len);
2499 if (par_len == 1) {
2500 /* There is no next line in this paragraph. We make a new
2501 * line and copy text after break_pos into it. */
2502 splice_node(current, make_new_node(current),
2503 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002504 /* In a non-quoted paragraph, we copy the indent only if
2505 AUTOINDENT is turned on. */
2506 if (quote_len == 0)
2507#ifndef NANO_SMALL
2508 if (!ISSET(AUTOINDENT))
2509#endif
2510 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002511 current->next->data = charalloc(indent_len + line_len -
2512 break_pos);
2513 strncpy(current->next->data, current->data,
2514 indent_len);
2515 strcpy(current->next->data + indent_len,
2516 current->data + break_pos + 1);
2517 assert(strlen(current->next->data) ==
2518 indent_len + line_len - break_pos - 1);
2519 totlines++;
2520 totsize += indent_len;
2521 par_len++;
2522 } else {
2523 size_t next_line_len = strlen(current->next->data);
2524
2525 indent_len = quote_len +
2526 indent_length(current->next->data + quote_len);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002527 current->next->data = charealloc(current->next->data,
2528 next_line_len + line_len - break_pos + 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002529
2530 memmove(current->next->data + indent_len + line_len - break_pos,
2531 current->next->data + indent_len,
2532 next_line_len - indent_len + 1);
2533 strcpy(current->next->data + indent_len,
2534 current->data + break_pos + 1);
2535 current->next->data[indent_len + line_len - break_pos - 1]
2536 = ' ';
2537#ifndef NANO_SMALL
2538 if (mark_beginbuf == current->next) {
2539 if (mark_beginx < indent_len)
2540 mark_beginx = indent_len;
2541 mark_beginx += line_len - break_pos;
2542 }
2543#endif
2544 }
2545#ifndef NANO_SMALL
2546 if (mark_beginbuf == current && mark_beginx > break_pos) {
2547 mark_beginbuf = current->next;
2548 mark_beginx -= break_pos + 1 - indent_len;
2549 }
2550#endif
2551 null_at(&current->data, break_pos);
2552 current = current->next;
2553 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002554 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002555
2556 indent_len = quote_len +
2557 indent_length(current->next->data + quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002558 /* If we can't pull a word from the next line up to this one,
2559 * just go on. */
2560 if (!breakable(current->next->data + indent_len,
2561 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002562 goto continue_loc;
2563
2564 /* If we haven't backed up the paragraph, do it now. */
2565 if (first_mod_line == NULL)
2566 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002567
2568 break_pos = break_line(current->next->data + indent_len,
2569 fill - display_len - 1, FALSE);
2570 assert(break_pos != -1);
2571
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002572 current->data = charealloc(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002573 line_len + break_pos + 2);
2574 current->data[line_len] = ' ';
2575 strncpy(current->data + line_len + 1,
2576 current->next->data + indent_len, break_pos);
2577 current->data[line_len + break_pos + 1] = '\0';
2578#ifndef NANO_SMALL
2579 if (mark_beginbuf == current->next) {
2580 if (mark_beginx < indent_len + break_pos) {
2581 mark_beginbuf = current;
2582 if (mark_beginx <= indent_len)
2583 mark_beginx = line_len + 1;
2584 else
2585 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2586 } else
2587 mark_beginx -= break_pos + 1;
2588 }
2589#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002590 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002591 if (indent_len + break_pos == next_line_len) {
2592 line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002593
2594 /* Don't destroy edittop! */
2595 if (line == edittop)
2596 edittop = current;
2597
Chris Allegretta6df90f52002-07-19 01:08:59 +00002598 unlink_node(line);
2599 delete_node(line);
2600 totlines--;
2601 totsize -= indent_len;
2602 current_y--;
2603 } else {
2604 memmove(current->next->data + indent_len,
2605 current->next->data + indent_len + break_pos + 1,
2606 next_line_len - break_pos - indent_len);
2607 null_at(&current->next->data,
2608 next_line_len - break_pos);
2609 current = current->next;
2610 }
2611 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002612 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002613 current = current->next;
2614 }
Chris Allegretta8151ba52003-04-19 19:34:05 +00002615 UNSET(JUSTIFY_MODE);
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002616
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002617/* We are now done justifying the paragraph. There are cleanup things
2618 * to do, and we check for unjustify. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002619
2620 /* totlines, totsize, and current_y have been maintained above. We
2621 * now set last_par_line to the new end of the paragraph, update
2622 * fileage, set current_x. Also, edit_refresh() needs the line
2623 * numbers to be right, so we renumber(). */
2624 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002625 if (first_mod_line != NULL) {
2626 if (first_mod_line->prev == NULL)
2627 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002628 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002629 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002630
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002631 skip_justify:
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002632 if (operation == 1) {
2633 /* We're on the same line we started on. Search for the first
2634 * non-"blank" line before the line we're on (if there is one),
2635 * continually restart that search from the current position
2636 * until we find a line that's part of a paragraph, and then
2637 * search once more from there, so that we end up on the first
2638 * line of that paragraph. In the process, skip over lines
2639 * consisting only of spacing characters, as searching for the
2640 * end of the paragraph does. Then update the screen. */
2641 if (current != fileage && current == current_save && !no_restart) {
2642 while (current->prev != NULL) {
2643 int j, j_space = 0;
2644 current = current->prev;
2645 current_y--;
2646 for (j = 0; j < strlen(current->data); j++) {
2647 if (isspace(current->data[j]))
2648 j_space++;
2649 else {
2650 j = -1;
2651 break;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002652 }
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002653 }
2654 if (j != j_space && strlen(current->data) >=
2655 (quote_len + indent_len) &&
2656 current->data[quote_len + indent_len] != '\0') {
2657 no_restart = 1;
2658 break;
2659 }
2660 }
2661 goto restart_bps;
2662 } else
2663 no_restart = 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002664#ifdef HAVE_REGEX_H
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002665 /* We no longer need to check quotation, if we were
2666 * searching for the beginning of the paragraph. */
2667 regfree(&qreg);
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002668#endif
David Lawrence Ramsey74ea8362003-09-04 23:22:47 +00002669 if (current_y < 0)
2670 edit_update(current, CENTER);
2671 else
2672 edit_refresh();
2673 return 0;
2674 } else if (operation == 2) {
2675 /* We've already moved to the end of the paragraph. Update the
2676 * screen. */
2677 if (current_y > editwinrows - 1)
2678 edit_update(current, CENTER);
2679 else
2680 edit_refresh();
2681 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002682 }
2683
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002684 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002685 edit_update(current, CENTER);
2686 else
2687 edit_refresh();
2688
Chris Allegretta9149e612000-11-27 00:23:41 +00002689 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002690 /* Change the shortcut list to display the unjustify code */
2691 shortcut_init(1);
2692 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002693 reset_cursor();
2694
Chris Allegretta6df90f52002-07-19 01:08:59 +00002695 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002696 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002697
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002698#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002699 /* If it was a mouse click, parse it with do_mouse() and it might
2700 * become the unjustify key. Else give it back to the input stream. */
2701 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002702 do_mouse();
2703 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002704 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002705#endif
Chris Allegretta5f071802001-05-06 02:34:31 +00002706
Chris Allegretta6df90f52002-07-19 01:08:59 +00002707 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2708 ungetch(i);
2709 /* Did we back up anything at all? */
2710 if (cutbuffer != cutbuffer_save)
2711 free_filestruct(cutbuffer);
2712 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002713 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002714 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002715 current = current_save;
2716 current_x = current_x_save;
2717 current_y = current_y_save;
2718 edittop = edittop_save;
2719 editbot = editbot_save;
2720 if (first_mod_line != NULL) {
2721 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002722
Chris Allegretta6df90f52002-07-19 01:08:59 +00002723 /* Splice the cutbuffer back into the file. */
2724 cutbottom->next = last_par_line->next;
2725 cutbottom->next->prev = cutbottom;
2726 /* The line numbers after the end of the paragraph have
2727 * been changed, so we change them back. */
2728 renumber(cutbottom->next);
2729 if (first_mod_line->prev != NULL) {
2730 cutbuffer->prev = first_mod_line->prev;
2731 cutbuffer->prev->next = cutbuffer;
2732 } else
2733 fileage = cutbuffer;
2734 cutbuffer = NULL;
2735
2736 last_par_line->next = NULL;
2737 free_filestruct(first_mod_line);
2738
2739 /* Restore global variables from before justify */
2740 totsize = totsize_save;
2741 totlines = filebot->lineno;
2742#ifndef NANO_SMALL
2743 mark_beginbuf = mark_beginbuf_save;
2744 mark_beginx = mark_beginx_save;
2745#endif
2746 flags = flags_save;
2747 if (!ISSET(MODIFIED)) {
2748 titlebar(NULL);
2749 wrefresh(topwin);
2750 }
2751 }
2752 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002753 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002754 cutbuffer = cutbuffer_save;
2755 blank_statusbar_refresh();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00002756 /* display shortcut list with UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002757 shortcut_init(0);
2758 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002759
Chris Allegretta6df90f52002-07-19 01:08:59 +00002760 return 0;
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002761}
2762#endif /* !DISABLE_JUSTIFY */
2763
2764int do_justify(void)
2765{
2766#ifdef DISABLE_JUSTIFY
2767 nano_disabled_msg();
2768 return 1;
2769#else
2770 return do_para_operation(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002771#endif
2772}
2773
David Lawrence Ramsey8faf3052003-09-04 20:25:29 +00002774#ifndef DISABLE_JUSTIFY
2775int do_para_begin(void)
2776{
2777 return do_para_operation(1);
2778}
2779
2780int do_para_end(void)
2781{
2782 return do_para_operation(2);
2783}
2784#endif
2785
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002786int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002787{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002788 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002789
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002790 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002791
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002792#ifdef ENABLE_MULTIBUFFER
2793 if (!close_open_file()) {
2794 display_main_list();
2795 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002796 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002797 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002798#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002799 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002800 }
2801
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002802 if (ISSET(TEMP_OPT)) {
2803 i = 1;
2804 } else {
2805 i = do_yesno(0, 0,
2806 _
2807 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2808 }
2809
2810#ifdef DEBUG
2811 dump_buffer(fileage);
2812#endif
2813
2814 if (i == 1) {
2815 if (do_writeout(filename, 1, 0) > 0) {
2816
2817#ifdef ENABLE_MULTIBUFFER
2818 if (!close_open_file()) {
2819 display_main_list();
2820 return 1;
2821 }
2822 else
2823#endif
2824 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002825 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002826 } else if (i == 0) {
2827
2828#ifdef ENABLE_MULTIBUFFER
2829 if (!close_open_file()) {
2830 display_main_list();
2831 return 1;
2832 }
2833 else
2834#endif
2835 finish(0);
2836 } else
2837 statusbar(_("Cancelled"));
2838
2839 display_main_list();
2840 return 1;
2841}
2842
2843void signal_init(void)
2844{
2845#ifdef _POSIX_VDISABLE
2846 struct termios term;
2847#endif
2848
2849 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2850 memset(&act, 0, sizeof(struct sigaction));
2851 act.sa_handler = SIG_IGN;
2852 sigaction(SIGINT, &act, NULL);
2853
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002854 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2855 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002856 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002857 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002858
2859#ifndef NANO_SMALL
2860 act.sa_handler = handle_sigwinch;
2861 sigaction(SIGWINCH, &act, NULL);
2862#endif
2863
2864#ifdef _POSIX_VDISABLE
2865 tcgetattr(0, &term);
2866
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002867 if (!ISSET(PRESERVE)) {
2868 /* Ignore ^S and ^Q, much to Chris' chagrin */
2869 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2870 term.c_cc[VSTART] = _POSIX_VDISABLE;
2871 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002872#ifdef VDSUSP
2873 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2874#endif /* VDSUSP */
2875
2876#endif /* _POSIX_VDISABLE */
2877
2878 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002879 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002880#ifdef _POSIX_VDISABLE
2881 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2882#else
2883 act.sa_handler = SIG_IGN;
2884 sigaction(SIGTSTP, &act, NULL);
2885#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002886 } else {
2887 /* If we don't do this, it seems other stuff interrupts the
2888 suspend handler! Try using nano with mutt without this
2889 line. */
2890 sigfillset(&act.sa_mask);
2891
2892 act.sa_handler = do_suspend;
2893 sigaction(SIGTSTP, &act, NULL);
2894
2895 act.sa_handler = do_cont;
2896 sigaction(SIGCONT, &act, NULL);
2897 }
2898
2899#ifdef _POSIX_VDISABLE
2900 tcsetattr(0, TCSANOW, &term);
2901#endif
2902}
2903
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002904/* Handler for SIGHUP and SIGTERM */
2905RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002906{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002907 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002908}
2909
2910/* What do we do when we catch the suspend signal */
2911RETSIGTYPE do_suspend(int signal)
2912{
2913 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002914 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002915 fflush(stdout);
2916
2917 /* Restore the terminal settings for the disabled keys */
2918 tcsetattr(0, TCSANOW, &oldterm);
2919
2920 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002921 then we could be (and were) interrupted in the middle of the call.
2922 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002923 kill(0, SIGSTOP);
2924}
2925
2926/* Restore the suspend handler when we come back into the prog */
2927RETSIGTYPE do_cont(int signal)
2928{
2929 /* Now we just update the screen instead of having to reenable the
2930 SIGTSTP handler. */
2931
2932 doupdate();
2933 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2934 start suspending again. */
2935 signal_init();
2936
2937#ifndef NANO_SMALL
2938 /* Perhaps the user resized the window while we slept. */
2939 handle_sigwinch(0);
2940#endif
2941}
2942
2943#ifndef NANO_SMALL
2944void handle_sigwinch(int s)
2945{
2946 const char *tty = ttyname(0);
2947 int fd;
2948 int result = 0;
2949 struct winsize win;
2950
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002951 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002952 return;
2953 fd = open(tty, O_RDWR);
2954 if (fd == -1)
2955 return;
2956 result = ioctl(fd, TIOCGWINSZ, &win);
2957 close(fd);
2958 if (result == -1)
2959 return;
2960
2961 /* Could check whether the COLS or LINES changed, and return
2962 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2963 * variables, and in some cases ncurses has already updated them.
2964 * But not in all cases, argh. */
2965 COLS = win.ws_col;
2966 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002967 editwinrows = LINES - 5 + no_help();
2968 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002969 die_too_small();
2970
2971#ifndef DISABLE_WRAPJUSTIFY
2972 fill = wrap_at;
2973 if (fill <= 0)
2974 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002975 if (fill < 0)
2976 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002977#endif
2978
David Lawrence Ramsey70047ee2003-06-14 20:41:34 +00002979 hblank = charealloc(hblank, COLS + 1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002980 memset(hblank, ' ', COLS);
2981 hblank[COLS] = '\0';
2982
2983#ifdef HAVE_RESIZETERM
2984 resizeterm(LINES, COLS);
2985#ifdef HAVE_WRESIZE
2986 if (wresize(topwin, 2, COLS) == ERR)
2987 die(_("Cannot resize top win"));
2988 if (mvwin(topwin, 0, 0) == ERR)
2989 die(_("Cannot move top win"));
2990 if (wresize(edit, editwinrows, COLS) == ERR)
2991 die(_("Cannot resize edit win"));
2992 if (mvwin(edit, 2, 0) == ERR)
2993 die(_("Cannot move edit win"));
2994 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2995 die(_("Cannot resize bottom win"));
2996 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2997 die(_("Cannot move bottom win"));
2998#endif /* HAVE_WRESIZE */
2999#endif /* HAVE_RESIZETERM */
3000
3001 fix_editbot();
3002
3003 if (current_y > editwinrows - 1)
3004 edit_update(editbot, CENTER);
3005 erase();
3006
3007 /* Do these b/c width may have changed... */
3008 refresh();
3009 titlebar(NULL);
3010 edit_refresh();
3011 display_main_list();
3012 blank_statusbar();
3013 total_refresh();
3014
3015 /* Turn cursor back on for sure */
3016 curs_set(1);
3017
3018 /* Jump back to main loop */
3019 siglongjmp(jmpbuf, 1);
3020}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003021#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00003022
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003023/* If the NumLock key has made the keypad go awry, print an error
3024 message; hopefully we can address it later. */
3025void print_numlock_warning(void)
3026{
3027 static int didmsg = 0;
3028 if (!didmsg) {
3029 statusbar(_
3030 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
3031 didmsg = 1;
3032 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003033}
3034
Chris Allegrettadab017e2002-04-23 10:56:06 +00003035#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00003036void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00003037{
Chris Allegretta6df90f52002-07-19 01:08:59 +00003038 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00003039
Chris Allegretta658399a2001-06-14 02:54:22 +00003040 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003041 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00003042
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003043 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00003044 case TOGGLE_SUSPEND_KEY:
3045 signal_init();
3046 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003047#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00003048 case TOGGLE_MOUSE_KEY:
3049 mouse_init();
3050 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003051#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003052 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00003053 wclear(bottomwin);
3054 wrefresh(bottomwin);
3055 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00003056 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00003057 edit_refresh();
3058 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00003059 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00003060 case TOGGLE_DOS_KEY:
3061 UNSET(MAC_FILE);
3062 break;
3063 case TOGGLE_MAC_KEY:
3064 UNSET(DOS_FILE);
3065 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003066#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00003067 case TOGGLE_SYNTAX_KEY:
3068 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003069 break;
3070#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00003071 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00003072
Chris Allegretta6df90f52002-07-19 01:08:59 +00003073 /* We are assuming here that shortcut_init() above didn't free and
3074 * reallocate the toggles. */
3075 enabled = ISSET(which->flag);
3076 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
3077 enabled = !enabled;
3078 statusbar("%s %s", which->desc,
3079 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00003080}
Chris Allegrettadab017e2002-04-23 10:56:06 +00003081#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00003082
Chris Allegretta1748cd12001-01-13 17:22:54 +00003083/* This function returns the correct keystroke, given the A,B,C or D
3084 input key. This is a common sequence of many terms which send
3085 Esc-O-[A-D] or Esc-[-[A-D]. */
Chris Allegretta908f7702003-01-15 11:18:58 +00003086int abcd(int input)
Chris Allegretta1748cd12001-01-13 17:22:54 +00003087{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003088 switch (input) {
3089 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003090 case 'a':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003091 return KEY_UP;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003092 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003093 case 'b':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003094 return KEY_DOWN;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003095 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003096 case 'c':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003097 return KEY_RIGHT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003098 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003099 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003100 return KEY_LEFT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003101 default:
3102 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00003103 }
3104}
3105
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003106int main(int argc, char *argv[])
3107{
3108 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003109 int startline = 0; /* Line to try and start at */
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003110 int modify_control_seq = 0;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003111 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003112 const shortcut *s;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003113 int keyhandled = 0; /* Have we handled the keystroke yet? */
3114 int kbinput = -1; /* Input from keyboard */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003115 int meta;
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003116
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003117#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003118 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003119#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003120#ifdef _POSIX_VDISABLE
3121 struct termios term;
3122#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003123#ifdef HAVE_GETOPT_LONG
3124 int option_index = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003125 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003126 {"help", 0, 0, 'h'},
3127#ifdef ENABLE_MULTIBUFFER
3128 {"multibuffer", 0, 0, 'F'},
3129#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003130#ifdef ENABLE_NANORC
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003131 {"historylog", 0, 0, 'H'},
Chris Allegretta6df90f52002-07-19 01:08:59 +00003132 {"ignorercfiles", 0, 0, 'I'},
3133#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003134#ifndef DISABLE_JUSTIFY
3135 {"quotestr", 1, 0, 'Q'},
3136#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003137#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003138 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003139#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003140 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003141 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003142#ifdef ENABLE_COLOR
3143 {"syntax", 1, 0, 'Y'},
3144#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003145 {"const", 0, 0, 'c'},
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003146 {"rebinddelete", 0, 0, 'd'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003147 {"nofollow", 0, 0, 'l'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003148#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003149 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003150#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003151#ifndef DISABLE_OPERATINGDIR
3152 {"operatingdir", 1, 0, 'o'},
3153#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003154 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003155#ifndef DISABLE_WRAPJUSTIFY
3156 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003157#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003158#ifndef DISABLE_SPELLER
3159 {"speller", 1, 0, 's'},
3160#endif
3161 {"tempfile", 0, 0, 't'},
3162 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003163#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003164 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003165#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003166 {"nohelp", 0, 0, 'x'},
3167 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003168#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003169 {"backup", 0, 0, 'B'},
3170 {"dos", 0, 0, 'D'},
3171 {"mac", 0, 0, 'M'},
3172 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003173 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003174 {"autoindent", 0, 0, 'i'},
3175 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003176#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003177 {0, 0, 0, 0}
3178 };
3179#endif
3180
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003181#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003182 setlocale(LC_ALL, "");
3183 bindtextdomain(PACKAGE, LOCALEDIR);
3184 textdomain(PACKAGE);
3185#endif
3186
Chris Allegretta7662c862003-01-13 01:35:15 +00003187#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003188 /* if we don't have rcfile support, we're root, and
3189 --disable-wrapping-as-root is used, turn wrapping off */
3190 if (geteuid() == 0)
3191 SET(NO_WRAP);
3192#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003193
3194#ifdef HAVE_GETOPT_LONG
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003195 while ((optchr = getopt_long(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz",
Chris Allegretta7662c862003-01-13 01:35:15 +00003196 long_options, &option_index)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003197#else
3198 while ((optchr =
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003199 getopt(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003200#endif
3201
3202 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003203
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003204 case 'a':
3205 case 'b':
3206 case 'e':
3207 case 'f':
3208 case 'g':
3209 case 'j':
3210 /* Pico compatibility flags */
3211 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003212#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003213 case 'B':
3214 SET(BACKUP_FILE);
3215 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003216 case 'D':
3217 SET(DOS_FILE);
3218 break;
3219#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003220#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003221 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003222 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003223 break;
3224#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003225#ifdef ENABLE_NANORC
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003226 case 'H':
3227 SET(HISTORYLOG);
3228 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003229 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003230 SET(NO_RCFILE);
3231 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003232#endif
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003233#ifndef NANO_SMALL
3234 case 'M':
3235 SET(MAC_FILE);
3236 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003237 case 'N':
3238 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003239 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003240#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003241#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003242 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003243 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003244 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003245#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003246#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003247 case 'R':
3248 SET(USE_REGEXP);
3249 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003250#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003251#ifndef NANO_SMALL
3252 case 'S':
3253 SET(SMOOTHSCROLL);
3254 break;
3255#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003256 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003257 {
3258 int i;
3259 char *first_error;
3260
Chris Allegretta7662c862003-01-13 01:35:15 +00003261 /* Using strtol() instead of atoi() lets us accept 0
3262 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003263 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003264 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003265 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003266 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003267 tabsize = i;
3268 if (tabsize <= 0) {
3269 fprintf(stderr, _("Tab size is too small for nano...\n"));
3270 exit(1);
3271 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003272 }
3273 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003274 case 'V':
3275 version();
3276 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003277#ifdef ENABLE_COLOR
3278 case 'Y':
3279 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3280 break;
3281#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003282 case 'c':
3283 SET(CONSTUPDATE);
3284 break;
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003285 case 'd':
3286 SET(REBIND_DELETE);
3287 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003288#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003289 case 'i':
3290 SET(AUTOINDENT);
3291 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003292 case 'k':
3293 SET(CUT_TO_END);
3294 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003295#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003296 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003297 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003298 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003299#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003300 case 'm':
3301 SET(USE_MOUSE);
3302 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003303#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003304#ifndef DISABLE_OPERATINGDIR
3305 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003306 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003307 break;
3308#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003309 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003310 SET(PRESERVE);
3311#ifdef HAVE_GETOPT_LONG
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003312#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003313 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003314#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003315 case 'r':
3316 {
3317 int i;
3318 char *first_error;
3319
Chris Allegretta7662c862003-01-13 01:35:15 +00003320 /* Using strtol() instead of atoi() lets us accept 0
3321 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003322 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003323 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003324 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003325 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003326 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003327 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003328 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003329 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003330#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003331#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003332 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003333 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003334 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003335#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003336 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003337 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003338 break;
3339 case 'v':
3340 SET(VIEW_MODE);
3341 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003342#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003343 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003344 SET(NO_WRAP);
3345 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003346#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003347 case 'x':
3348 SET(NO_HELP);
3349 break;
3350 case 'z':
3351 SET(SUSPEND);
3352 break;
3353 default:
3354 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003355 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003356 }
3357
Chris Allegretta7662c862003-01-13 01:35:15 +00003358/* We've read through the command line options. Now back up the flags
3359 and values that are set, and read the rcfile(s). If the values
3360 haven't changed afterward, restore the backed-up values. */
3361#ifdef ENABLE_NANORC
3362 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003363#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003364 char *operating_dir_cpy = operating_dir;
3365#endif
3366#ifndef DISABLE_WRAPPING
3367 int wrap_at_cpy = wrap_at;
3368#endif
3369#ifndef DISABLE_JUSTIFY
3370 char *quotestr_cpy = quotestr;
3371#endif
3372#ifndef DISABLE_SPELLER
3373 char *alt_speller_cpy = alt_speller;
3374#endif
3375 int tabsize_cpy = tabsize;
3376 long flags_cpy = flags;
3377
Chris Allegretta5ec68622003-02-05 02:39:34 +00003378#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003379 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003380#endif
3381#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003382 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003383#endif
3384#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003385 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003386#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003387
3388 do_rcfile();
3389
3390#ifndef DISABLE_OPERATINGDIR
3391 if (operating_dir_cpy != NULL) {
3392 free(operating_dir);
3393 operating_dir = operating_dir_cpy;
3394 }
3395#endif
3396#ifndef DISABLE_WRAPPING
3397 if (fill_flag_used)
3398 wrap_at = wrap_at_cpy;
3399#endif
3400#ifndef DISABLE_JUSTIFY
3401 if (quotestr_cpy != NULL) {
3402 free(quotestr);
3403 quotestr = quotestr_cpy;
3404 }
3405#endif
3406#ifndef DISABLE_SPELLER
3407 if (alt_speller_cpy != NULL) {
3408 free(alt_speller);
3409 alt_speller = alt_speller_cpy;
3410 }
3411#endif
3412 if (tabsize_cpy > 0)
3413 tabsize = tabsize_cpy;
3414 flags |= flags_cpy;
3415 }
3416#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3417 else if (geteuid() == 0)
3418 SET(NO_WRAP);
3419#endif
3420#endif /* ENABLE_NANORC */
3421
Chris Allegrettad8451932003-03-11 03:50:40 +00003422#ifndef NANO_SMALL
3423 history_init();
3424#ifdef ENABLE_NANORC
3425 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3426 load_history();
3427#endif
3428#endif
3429
Chris Allegretta7662c862003-01-13 01:35:15 +00003430#ifndef DISABLE_OPERATINGDIR
3431 /* Set up the operating directory. This entails chdir()ing there,
3432 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003433 init_operating_dir();
3434#endif
3435
Chris Allegretta7662c862003-01-13 01:35:15 +00003436#ifndef DISABLE_JUSTIFY
3437 if (quotestr == NULL)
3438#ifdef HAVE_REGEX_H
3439 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3440#else
3441 quotestr = mallocstrcpy(NULL, "> ");
3442#endif
3443#endif /* !DISABLE_JUSTIFY */
3444 if (tabsize == -1)
3445 tabsize = 8;
3446
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003447 /* Clear the filename we'll be using */
3448 filename = charalloc(1);
3449 filename[0] = '\0';
3450
Chris Allegretta7662c862003-01-13 01:35:15 +00003451 /* If there's a +LINE flag, it is the first non-option argument. */
3452 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3453 startline = atoi(&argv[optind][1]);
3454 optind++;
3455 }
3456 if (0 < optind && optind < argc)
3457 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003458
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003459 /* See if there's a non-option in argv (first non-option is the
3460 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003461 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003462 /* Look for the +line flag... */
3463 if (argv[optind][0] == '+') {
3464 startline = atoi(&argv[optind][1]);
3465 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003466 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003467 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003468 } else
3469 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003470 }
3471
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003472 /* First back up the old settings so they can be restored, duh */
3473 tcgetattr(0, &oldterm);
3474
3475#ifdef _POSIX_VDISABLE
3476 term = oldterm;
3477 term.c_cc[VINTR] = _POSIX_VDISABLE;
3478 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3479 term.c_lflag &= ~IEXTEN;
3480 tcsetattr(0, TCSANOW, &term);
3481#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003482
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003483 /* now ncurses init stuff... */
3484 initscr();
3485 savetty();
3486 nonl();
3487 cbreak();
3488 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003489
3490 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003491 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003492 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003493 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003494
3495#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003496 fprintf(stderr, "Main: set up windows\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003497#endif
3498
Chris Allegretta2a42af12000-09-12 23:02:49 +00003499 window_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003500#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00003501 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003502#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003503
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003504 keypad(edit, TRUE);
3505 keypad(bottomwin, TRUE);
Chris Allegretta48bd3782002-01-03 21:26:34 +00003506
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003507#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003508 fprintf(stderr, "Main: bottom win\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003509#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003510 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003511 display_main_list();
3512
3513#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003514 fprintf(stderr, "Main: open file\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003515#endif
3516
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003517 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003518#ifdef ENABLE_MULTIBUFFER
3519 /* If we're using multibuffers and more than one file is specified
3520 on the command line, load them all and switch to the first one
3521 afterward */
3522 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3523 for (optind++; optind < argc; optind++) {
3524 add_open_file(1);
3525 new_file();
3526 filename = mallocstrcpy(filename, argv[optind]);
3527 open_file(filename, 0, 0);
3528 load_file(0);
3529 }
3530 open_nextfile_void();
3531 }
3532#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003533
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003534 titlebar(NULL);
3535
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003536 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003537 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003538
Chris Allegretta7662c862003-01-13 01:35:15 +00003539 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003540 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003541
Chris Allegrettafe1d0722003-02-13 00:52:49 +00003542 /* SHUT UP GCC! */
3543 startline = 0;
3544 fill_flag_used = 0;
3545 keyhandled = 0;
3546
Chris Allegretta7662c862003-01-13 01:35:15 +00003547 /* This variable should be initialized after the sigsetjmp(), so we
3548 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003549 modify_control_seq = 0;
3550
Robert Siemborski6967eec2000-07-08 14:23:32 +00003551 edit_refresh();
3552 reset_cursor();
3553
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003554 while (1) {
Chris Allegrettad0845df2003-02-13 00:56:57 +00003555 keyhandled = 0;
Chris Allegretta9239d742000-09-06 15:19:18 +00003556
Chris Allegrettad26ab912003-01-28 01:16:47 +00003557 if (ISSET(CONSTUPDATE))
3558 do_cursorpos(1);
3559
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003560#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003561 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003562#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003563
Chris Allegretta9239d742000-09-06 15:19:18 +00003564#ifndef _POSIX_VDISABLE
3565 /* We're going to have to do it the old way, i.e. on cygwin */
3566 raw();
3567#endif
3568
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003569 kbinput = get_kbinput(edit, &meta, ISSET(REBIND_DELETE));
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003570#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003571 fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003572#endif
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003573 if (meta == 1) {
Chris Allegretta7662c862003-01-13 01:35:15 +00003574 switch (kbinput) {
Chris Allegretta355fbe52001-07-14 19:32:47 +00003575#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003576 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003577 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003578 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003579 keyhandled = 1;
3580 break;
3581 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003582 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003583 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003584 keyhandled = 1;
3585 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003586#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003587 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003588 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003589 for (s = main_list; s != NULL; s = s->next)
Chris Allegretta7662c862003-01-13 01:35:15 +00003590 if (kbinput == s->altval || (kbinput >= 'A' &&
3591 kbinput <= 'Z' && kbinput == s->altval - 32)) {
Chris Allegretta6232d662002-05-12 19:52:15 +00003592 if (ISSET(VIEW_MODE) && !s->viewok)
3593 print_view_warning();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003594 else {
3595 if (s->func != do_cut_text)
3596 UNSET(KEEP_CUTBUFFER);
Chris Allegretta6232d662002-05-12 19:52:15 +00003597 s->func();
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003598 }
Chris Allegretta6232d662002-05-12 19:52:15 +00003599 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003600 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003601 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003602#ifndef NANO_SMALL
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003603 if (!keyhandled)
3604 /* And for toggle switches */
3605 for (t = toggles; t != NULL; t = t->next)
3606 if (kbinput == t->val || (t->val >= 'a' &&
3607 t->val <= 'z' && kbinput == t->val - 32)) {
3608 UNSET(KEEP_CUTBUFFER);
3609 do_toggle(t);
3610 keyhandled = 1;
3611 break;
3612 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003613#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003614#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003615 fprintf(stderr, "I got Alt-%c! (%d)\n", kbinput,
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003616 kbinput);
3617#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003618 }
3619 }
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003620
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003621 /* Look through the main shortcut list to see if we've hit a
3622 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003623
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003624 if (!keyhandled)
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003625#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003626 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003627#else
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003628 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003629#endif
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003630 if (kbinput == s->val ||
3631 (s->misc1 && kbinput == s->misc1) ||
3632 (s->misc2 && kbinput == s->misc2)) {
3633 if (ISSET(VIEW_MODE) && !s->viewok)
3634 print_view_warning();
3635 else {
3636 if (s->func != do_cut_text)
3637 UNSET(KEEP_CUTBUFFER);
3638 s->func();
3639 }
3640 keyhandled = 1;
3641 /* Rarely, the value of s can change after
3642 s->func(), leading to problems; get around this
3643 by breaking out explicitly once we successfully
3644 handle a shortcut */
3645 break;
3646 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003647 }
Chris Allegrettae1e0fd62003-04-15 01:15:09 +00003648
3649 if (!keyhandled)
3650 UNSET(KEEP_CUTBUFFER);
Chris Allegrettae42df732002-10-15 00:27:55 +00003651
3652#ifdef _POSIX_VDISABLE
3653 /* Don't even think about changing this string */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003654 if (kbinput == NANO_CONTROL_Q)
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003655 statusbar(_("XON ignored, mumble mumble."));
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003656 if (kbinput == NANO_CONTROL_S)
3657 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003658#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003659 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3660 Control-S and Control-Q */
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003661 if (kbinput == NANO_CONTROL_Q || kbinput == NANO_CONTROL_S)
Chris Allegretta9239d742000-09-06 15:19:18 +00003662 keyhandled = 1;
3663
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003664 /* Catch ^Z by hand when triggered also */
3665 if (kbinput == NANO_SUSPEND_KEY) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003666 if (ISSET(SUSPEND))
3667 do_suspend(0);
3668 keyhandled = 1;
3669 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003670
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003671 /* Last gasp, stuff that's not in the main lists */
3672 if (!keyhandled)
3673 switch (kbinput) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003674#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003675 case KEY_MOUSE:
3676 do_mouse();
3677 break;
3678#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003679
David Lawrence Ramsey4d7c2602003-08-17 02:48:43 +00003680 case NANO_CONTROL_3: /* Ctrl-[ (Esc), which should
3681 * have been handled before we
3682 * got here */
3683 case NANO_CONTROL_5: /* Ctrl-] */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003684 break;
3685 default:
3686#ifdef DEBUG
Jordi Mallachf9390af2003-08-05 19:31:12 +00003687 fprintf(stderr, "I got %c (%d)!\n", kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003688#endif
3689 /* We no longer stop unhandled sequences so that people with
3690 odd character sets can type... */
3691
Chris Allegretta7662c862003-01-13 01:35:15 +00003692 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003693 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003694 else
3695 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003696 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003697
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003698 reset_cursor();
3699 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003700 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003701 assert(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003702}