blob: 905b192f0c29a847b1f995dfb00a3c1e8316cde3 [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{
Chris Allegretta5beed502003-01-05 20:41:21 +000069
70#ifndef NANO_SMALL
Chris Allegrettaf3de8b52003-01-16 23:44:46 +000071#ifdef ENABLE_NANORC
72 /* do here so errors about ./nano_history
73 don't confuse user */
74 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
75 save_history();
76#endif
Chris Allegretta5beed502003-01-05 20:41:21 +000077 free_history(&search_history);
78 free_history(&replace_history);
79#endif
80
Chris Allegrettac08f50d2001-01-06 18:12:43 +000081 keypad(edit, TRUE);
82 keypad(bottomwin, TRUE);
83
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000084 if (!ISSET(NO_HELP)) {
85 mvwaddstr(bottomwin, 1, 0, hblank);
86 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000087 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000088 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000089
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000090 wrefresh(bottomwin);
91 endwin();
92
93 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000094 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000095
Chris Allegretta6232d662002-05-12 19:52:15 +000096#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000097 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000098#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000099
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000100 exit(sigage);
101}
102
103/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000104void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105{
106 va_list ap;
107
Chris Allegrettaa0d89972003-02-03 03:32:08 +0000108 endwin();
109 curses_ended = TRUE;
110
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000111 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000112 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000113
Chris Allegretta6df90f52002-07-19 01:08:59 +0000114 va_start(ap, msg);
115 vfprintf(stderr, msg, ap);
116 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000117
Chris Allegretta32da4562002-01-02 15:12:21 +0000118 /* save the currently loaded file if it's been modified */
119 if (ISSET(MODIFIED))
120 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000121
Chris Allegretta355fbe52001-07-14 19:32:47 +0000122#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000123 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000124 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000125 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000126
127 tmp = open_files;
128
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000129 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000130 open_files = open_files->prev;
131
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000132 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000133
134 /* if we already saved the file above (i. e. if it was the
135 currently loaded file), don't save it again */
136 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000137 /* make sure open_files->fileage and fileage, and
138 open_files->filebot and filebot, are in sync; they
139 might not be if lines have been cut from the top or
140 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000141 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000142 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000143 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000144 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000145 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000146 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000147 open_files = open_files->next;
148 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149 }
150#endif
151
Chris Allegretta6df90f52002-07-19 01:08:59 +0000152 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000153}
154
Chris Allegretta6df90f52002-07-19 01:08:59 +0000155void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000156{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000157 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000158 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000159
Chris Allegretta6df90f52002-07-19 01:08:59 +0000160 /* If we can't save, we have REAL bad problems, but we might as well
161 TRY. */
162 if (die_filename[0] == '\0')
163 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000164 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000165 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000166
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000167 strcpy(buf, die_filename);
168 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000169 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000170 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000171 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 if (ret[0] != '\0')
173 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000174
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000175 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000176 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000177 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000178 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000179
180 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000181}
182
Chris Allegrettae61e8302001-01-14 05:18:27 +0000183/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000184 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000185void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000186{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000187 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000188}
189
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000190void print_view_warning(void)
191{
192 statusbar(_("Key illegal in VIEW mode"));
193}
194
Chris Allegretta56214c62001-09-27 02:46:53 +0000195/* Initialize global variables - no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000196 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000197void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000198{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000199 current_x = 0;
200 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000201
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000202 editwinrows = LINES - 5 + no_help();
203 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000204 die_too_small();
205
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000206 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000207 if (!save_cutbuffer)
208 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000209 current = NULL;
210 edittop = NULL;
211 editbot = NULL;
212 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000213 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000214 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000215
Chris Allegretta6fe61492001-05-21 12:56:25 +0000216#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000217 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000218 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000219 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000220 if (fill < 0)
221 fill = 0;
Chris Allegretta6fe61492001-05-21 12:56:25 +0000222#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000223
Chris Allegretta88b09152001-05-17 11:35:43 +0000224 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000225 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000226 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000227}
228
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000229void window_init(void)
230{
Chris Allegrettaf8f2d582003-02-10 02:43:48 +0000231 editwinrows = LINES - 5 + no_help();
232 if (editwinrows < MIN_EDITOR_ROWS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000233 die_too_small();
234
Chris Allegretta1a128af2003-01-26 04:15:56 +0000235 if (edit != NULL)
236 delwin(edit);
237 if (topwin != NULL)
238 delwin(topwin);
239 if (bottomwin != NULL)
240 delwin(bottomwin);
241
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000242 /* Set up the main text window */
243 edit = newwin(editwinrows, COLS, 2, 0);
244
245 /* And the other windows */
246 topwin = newwin(2, COLS, 0, 0);
247 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
248
249#ifdef PDCURSES
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000250 /* Oops, I guess we need this again. Moved here so the keypad still
251 works after a Meta-X, for example */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000252 keypad(edit, TRUE);
253 keypad(bottomwin, TRUE);
254#endif
255}
256
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000257#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000258void mouse_init(void)
259{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000260 if (ISSET(USE_MOUSE)) {
261 keypad_on(edit, 1);
262 keypad_on(bottomwin, 1);
263
264 mousemask(BUTTON1_RELEASED, NULL);
265 mouseinterval(50);
266 } else
267 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000268}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000269#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000270
271#ifndef DISABLE_HELP
272/* This function allocates help_text, and stores the help string in it.
273 * help_text should be NULL initially. */
274void help_init(void)
275{
Chris Allegretta908f7702003-01-15 11:18:58 +0000276 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000277 char *ptr = NULL;
278#ifndef NANO_SMALL
279 const toggle *t;
280#endif
281 const shortcut *s;
282
283 /* First set up the initial help text for the current function */
284 if (currshortcut == whereis_list || currshortcut == replace_list
285 || currshortcut == replace_list_2)
286 ptr = _("Search Command Help Text\n\n "
287 "Enter the words or characters you would like to search "
288 "for, then hit enter. If there is a match for the text you "
289 "entered, the screen will be updated to the location of the "
290 "nearest match for the search string.\n\n "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000291 "The previous search string will be shown in brackets after "
292 "the Search: prompt. Hitting Enter without entering any text "
293 "will perform the previous search.\n\n The following function "
294 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000295 else if (currshortcut == goto_list)
296 ptr = _("Go To Line Help Text\n\n "
297 "Enter the line number that you wish to go to and hit "
298 "Enter. If there are fewer lines of text than the "
299 "number you entered, you will be brought to the last line "
300 "of the file.\n\n The following function keys are "
301 "available in Go To Line mode:\n\n");
302 else if (currshortcut == insertfile_list)
303 ptr = _("Insert File Help Text\n\n "
304 "Type in the name of a file to be inserted into the current "
305 "file buffer at the current cursor location.\n\n "
306 "If you have compiled nano with multiple file buffer "
307 "support, and enable multiple buffers with the -F "
308 "or --multibuffer command line flags, the Meta-F toggle, or "
309 "a nanorc file, inserting a file will cause it to be "
310 "loaded into a separate buffer (use Meta-< and > to switch "
311 "between file buffers).\n\n If you need another blank "
312 "buffer, do not enter any filename, or type in a "
313 "nonexistent filename at the prompt and press "
314 "Enter.\n\n The following function keys are "
315 "available in Insert File mode:\n\n");
316 else if (currshortcut == writefile_list)
317 ptr = _("Write File Help Text\n\n "
318 "Type the name that you wish to save the current file "
319 "as and hit Enter to save the file.\n\n If you have "
320 "selected text with Ctrl-^, you will be prompted to "
321 "save only the selected portion to a separate file. To "
322 "reduce the chance of overwriting the current file with "
323 "just a portion of it, the current filename is not the "
324 "default in this mode.\n\n The following function keys "
325 "are available in Write File mode:\n\n");
326#ifndef DISABLE_BROWSER
327 else if (currshortcut == browser_list)
328 ptr = _("File Browser Help Text\n\n "
329 "The file browser is used to visually browse the "
330 "directory structure to select a file for reading "
331 "or writing. You may use the arrow keys or Page Up/"
332 "Down to browse through the files, and S or Enter to "
333 "choose the selected file or enter the selected "
334 "directory. To move up one level, select the directory "
335 "called \"..\" at the top of the file list.\n\n The "
336 "following function keys are available in the file "
337 "browser:\n\n");
338 else if (currshortcut == gotodir_list)
339 ptr = _("Browser Go To Directory Help Text\n\n "
340 "Enter the name of the directory you would like to "
341 "browse to.\n\n If tab completion has not been disabled, "
342 "you can use the TAB key to (attempt to) automatically "
343 "complete the directory name.\n\n The following function "
344 "keys are available in Browser Go To Directory mode:\n\n");
345#endif
Chris Allegretta201f1d92003-02-05 02:51:19 +0000346#ifndef DISABLE_SPELLER
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000347 else if (currshortcut == spell_list)
348 ptr = _("Spell Check Help Text\n\n "
349 "The spell checker checks the spelling of all text "
350 "in the current file. When an unknown word is "
351 "encountered, it is highlighted and a replacement can "
352 "be edited. It will then prompt to replace every "
353 "instance of the given misspelled word in the "
354 "current file.\n\n The following other functions are "
355 "available in Spell Check mode:\n\n");
Chris Allegretta201f1d92003-02-05 02:51:19 +0000356#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000357#ifndef NANO_SMALL
358 else if (currshortcut == extcmd_list)
359 ptr = _("External Command Help Text\n\n "
360 "This menu allows you to insert the output of a command "
361 "run by the shell into the current buffer (or a new "
362 "buffer in multibuffer mode).\n\n The following keys are "
363 "available in this mode:\n\n");
364#endif
365 else /* Default to the main help list */
366 ptr = _(" nano help text\n\n "
367 "The nano editor is designed to emulate the functionality and "
368 "ease-of-use of the UW Pico text editor. There are four main "
369 "sections of the editor: The top line shows the program "
370 "version, the current filename being edited, and whether "
371 "or not the file has been modified. Next is the main editor "
372 "window showing the file being edited. The status line is "
373 "the third line from the bottom and shows important messages. "
374 "The bottom two lines show the most commonly used shortcuts "
375 "in the editor.\n\n "
376 "The notation for shortcuts is as follows: Control-key "
377 "sequences are notated with a caret (^) symbol and are entered "
378 "with the Control (Ctrl) key. Escape-key sequences are notated "
379 "with the Meta (M) symbol and can be entered using either the "
380 "Esc, Alt or Meta key depending on your keyboard setup. The "
381 "following keystrokes are available in the main editor window. "
382 "Alternative keys are shown in parentheses:\n\n");
383
Chris Allegretta908f7702003-01-15 11:18:58 +0000384 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000385
386 /* The space needed for the shortcut lists, at most COLS characters,
387 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000388 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000389
390#ifndef NANO_SMALL
391 /* If we're on the main list, we also count the toggle help text.
392 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
393 * COLS - 24 characters, plus '\n'.*/
Chris Allegretta3a784062003-02-10 02:32:58 +0000394 if (currshortcut == main_list) {
395 size_t endislen = strlen(_("enable/disable"));
396
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000397 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta3a784062003-02-10 02:32:58 +0000398 allocsize += 8 + strlen(t->desc) + endislen;
399 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000400#endif /* !NANO_SMALL */
401
402 /* help_text has been freed and set to NULL unless the user resized
403 * while in the help screen. */
404 free(help_text);
405
406 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000407 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000408
409 /* Now add the text we want */
410 strcpy(help_text, ptr);
411 ptr = help_text + strlen(help_text);
412
413 /* Now add our shortcut info */
414 for (s = currshortcut; s != NULL; s = s->next) {
415 /* true if the character in s->altval is shown in first column */
416 int meta_shortcut = 0;
417
418 if (s->val > 0 && s->val < 32)
419 ptr += sprintf(ptr, "^%c", s->val + 64);
420#ifndef NANO_SMALL
421 else if (s->val == NANO_CONTROL_SPACE)
422 ptr += sprintf(ptr, "^%.6s", _("Space"));
423 else if (s->altval == NANO_ALT_SPACE) {
424 meta_shortcut = 1;
425 ptr += sprintf(ptr, "M-%.5s", _("Space"));
Chris Allegretta7662c862003-01-13 01:35:15 +0000426 } else if (s->val == KEY_UP)
427 ptr += sprintf(ptr, "%.2s", _("Up"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000428#endif
429 else if (s->altval > 0) {
430 meta_shortcut = 1;
431 ptr += sprintf(ptr, "M-%c", s->altval -
432 (('A' <= s->altval && s->altval <= 'Z') ||
433 'a' <= s->altval ? 32 : 0));
434 }
435 /* Hack */
436 else if (s->val >= 'a') {
437 meta_shortcut = 1;
438 ptr += sprintf(ptr, "M-%c", s->val - 32);
439 }
440
441 *(ptr++) = '\t';
442
443 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
444 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
445
446 *(ptr++) = '\t';
447
448 if (!meta_shortcut && s->altval > 0)
449 ptr += sprintf(ptr, "(M-%c)", s->altval -
450 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
451 ? 32 : 0));
452
453 *(ptr++) = '\t';
454
455 assert(s->help != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000456 ptr += sprintf(ptr, "%.*s\n", COLS > 24 ? COLS - 24 : 0, s->help);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000457 }
458
459#ifndef NANO_SMALL
460 /* And the toggles... */
461 if (currshortcut == main_list)
462 for (t = toggles; t != NULL; t = t->next) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000463 assert(t->desc != NULL);
Chris Allegretta3a784062003-02-10 02:32:58 +0000464 ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", t->val - 32, t->desc,
465 _("enable/disable"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000466 }
467#endif /* !NANO_SMALL */
468
469 /* If all went well, we didn't overwrite the allocated space for
470 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000471 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000472}
473#endif
474
475/* Create a new filestruct node. Note that we specifically do not set
476 * prevnode->next equal to the new line. */
477filestruct *make_new_node(filestruct *prevnode)
478{
479 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
480
481 newnode->data = NULL;
482 newnode->prev = prevnode;
483 newnode->next = NULL;
484 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
485
486 return newnode;
487}
488
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000489/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000490filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000491{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000492 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000493
Chris Allegretta6df90f52002-07-19 01:08:59 +0000494 assert(src != NULL);
495
Chris Allegretta88b09152001-05-17 11:35:43 +0000496 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000497 dst->next = src->next;
498 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000499 strcpy(dst->data, src->data);
500 dst->lineno = src->lineno;
501
502 return dst;
503}
504
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000505/* Splice a node into an existing filestruct. */
506void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
507{
508 if (newnode != NULL) {
509 newnode->next = end;
510 newnode->prev = begin;
511 }
512 if (begin != NULL)
513 begin->next = newnode;
514 if (end != NULL)
515 end->prev = newnode;
516}
517
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000518/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000519void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000520{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000521 assert(fileptr != NULL);
522
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523 if (fileptr->prev != NULL)
524 fileptr->prev->next = fileptr->next;
525
526 if (fileptr->next != NULL)
527 fileptr->next->prev = fileptr->prev;
528}
529
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000530/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000531void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000532{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000533 if (fileptr != NULL) {
534 if (fileptr->data != NULL)
535 free(fileptr->data);
536 free(fileptr);
537 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000538}
539
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000540/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000541filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000542{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000543 filestruct *head; /* copy of src, top of the copied list */
544 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000545
Chris Allegretta6df90f52002-07-19 01:08:59 +0000546 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000547
Chris Allegretta6df90f52002-07-19 01:08:59 +0000548 prev = copy_node(src);
549 prev->prev = NULL;
550 head = prev;
551 src = src->next;
552 while (src != NULL) {
553 prev->next = copy_node(src);
554 prev->next->prev = prev;
555 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000556
Chris Allegretta6df90f52002-07-19 01:08:59 +0000557 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000558 }
559
Chris Allegretta6df90f52002-07-19 01:08:59 +0000560 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000561 return head;
562}
563
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000564/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000565void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000566{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000567 if (src != NULL) {
568 while (src->next != NULL) {
569 src = src->next;
570 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +0000572 fprintf(stderr, _("%s: free'd a node, YAY!\n"), "delete_node()");
Chris Allegretta6df90f52002-07-19 01:08:59 +0000573#endif
574 }
575 delete_node(src);
576#ifdef DEBUG
Chris Allegretta0e86e602003-01-23 04:27:23 +0000577 fprintf(stderr, _("%s: free'd last node.\n"), "delete_node()");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000578#endif
579 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580}
581
Chris Allegretta6df90f52002-07-19 01:08:59 +0000582void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000583{
584 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000585 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000586
Chris Allegretta6df90f52002-07-19 01:08:59 +0000587 assert(fileage == NULL || fileage != fileage->next);
588 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000589 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000590}
591
Chris Allegretta6df90f52002-07-19 01:08:59 +0000592void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000593{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000594 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000595 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000596 else {
597 int lineno = fileptr->prev->lineno;
598
599 assert(fileptr != fileptr->next);
600 for (; fileptr != NULL; fileptr = fileptr->next)
601 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000602 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000603}
604
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000605/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000606 * strings to translate and takes out the parts that shouldn't be
607 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000608void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000609 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000610{
611 printf(" %s\t", shortflag);
612 if (strlen(shortflag) < 8)
613 printf("\t");
614
615#ifdef HAVE_GETOPT_LONG
616 printf("%s\t", longflag);
617 if (strlen(longflag) < 8)
618 printf("\t\t");
619 else if (strlen(longflag) < 16)
620 printf("\t");
621#endif
622
623 printf("%s\n", desc);
624}
625
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000626void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000627{
628#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000629 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
630 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000631#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000632 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
633 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000634#endif /* HAVE_GETOPT_LONG */
635
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000636 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000637 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000638#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000639 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000640 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000641#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000642#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000643 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000644#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000645#ifdef ENABLE_NANORC
Chris Allegretta36fec722003-01-22 01:13:25 +0000646 print1opt("-H", "--historylog", _("Log & read search/replace string history"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000647 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
648#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000649 print1opt("-K", "--keypad", _("Use alternate keypad routines"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000650#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000651 print1opt("-M", "--mac", _("Write file in Mac format"));
652 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000653#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000654#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000655 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000656#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000657#ifdef HAVE_REGEX_H
658 print1opt("-R", "--regexp", _("Do regular expression searches"));
659#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000660#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000661 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000662#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000663 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000664 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000665#ifdef ENABLE_COLOR
666 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
667#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000668 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000669#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000670 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
671 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000672#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000673 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000674#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000675 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000676#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000677#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000678 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000679#endif
Jordi Mallacheeb50042003-01-18 22:42:34 +0000680 print1opt("-p", "--preserve", _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000681#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000682 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000683#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000684#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000685 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000686#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000687 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
688 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000689#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000690 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000691#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000692 print1opt("-x", "--nohelp", _("Don't show help window"));
693 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000694
695 /* this is a special case */
696 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000697
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000698 exit(0);
699}
700
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000701void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000702{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000703 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000704 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000705 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000706 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000707 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000708
Chris Allegrettae6600372003-01-17 03:39:41 +0000709#ifndef ENABLE_NLS
710 printf(" --disable-nls");
711#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000712#ifdef DEBUG
713 printf(" --enable-debug");
714#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000715#ifdef NANO_EXTRA
716 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000717#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000718#ifdef NANO_SMALL
719 printf(" --enable-tiny");
720#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000721#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000722 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000723#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000724#ifdef DISABLE_HELP
725 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000726#endif
727#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000728 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000729#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000730#if defined(DISABLE_MOUSE) || !defined(NCURSES_MOUSE_VERSION)
Chris Allegretta84de5522001-04-12 14:51:48 +0000731 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000732#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000733#ifdef DISABLE_OPERATINGDIR
734 printf(" --disable-operatingdir");
735#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000736#ifdef DISABLE_SPELLER
737 printf(" --disable-speller");
738#endif
739#ifdef DISABLE_TABCOMP
740 printf(" --disable-tabcomp");
741#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000742#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000743#ifdef DISABLE_WRAPPING
744 printf(" --disable-wrapping");
745#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000746#ifdef DISABLE_ROOTWRAP
747 printf(" --disable-wrapping-as-root");
748#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000749#ifdef ENABLE_COLOR
750 printf(" --enable-color");
751#endif
752#ifdef ENABLE_MULTIBUFFER
753 printf(" --enable-multibuffer");
754#endif
755#ifdef ENABLE_NANORC
756 printf(" --enable-nanorc");
757#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000758#ifdef USE_SLANG
759 printf(" --with-slang");
760#endif
761 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000762}
763
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000764/* Stuff we do when we abort from programs and want to clean up the
765 * screen. This doesn't do much right now. */
766void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000767{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000768 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000769}
770
771int no_help(void)
772{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000773 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000774}
775
Chris Allegrettad865da12002-07-29 23:46:38 +0000776#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000777void nano_disabled_msg(void)
778{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000779 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000780}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000781#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000782
Chris Allegretta6cd143d2003-01-05 23:35:44 +0000783void do_preserve_msg(void)
784{
Jordi Mallacheeb50042003-01-18 22:42:34 +0000785 fprintf(stderr, _("\nThe -p flag now invokes the Pico \"preserve\" flag.\n"
786 "The Pico compatibility flag has been removed as nano\n"
787 "now fully Pico compatible. Please see the nano FAQ\n"
788 "for more info on this change...\n\n"
789 "Press return to continue\n"));
Chris Allegretta6cd143d2003-01-05 23:35:44 +0000790 while (getchar() != '\n');
791}
792
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000793#ifndef NANO_SMALL
794static int pid; /* This is the PID of the newly forked process
795 * below. It must be global since the signal
796 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000797RETSIGTYPE cancel_fork(int signal)
798{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000799 if (kill(pid, SIGKILL) == -1)
800 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000801}
802
803int open_pipe(const char *command)
804{
805 int fd[2];
806 FILE *f;
807 struct sigaction oldaction, newaction;
808 /* original and temporary handlers for SIGINT */
809#ifdef _POSIX_VDISABLE
810 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000811#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000812 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000813 /* cancel_sigs == 1 means that sigaction() failed without changing
814 * the signal handlers. cancel_sigs == 2 means the signal handler
815 * was changed, but the tcsetattr didn't succeed.
816 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000817 * I use this variable since it is important to put things back when
818 * we finish, even if we get errors. */
819
820 /* Make our pipes. */
821
822 if (pipe(fd) == -1) {
823 statusbar(_("Could not pipe"));
824 return 1;
825 }
826
827 /* Fork a child. */
828
829 if ((pid = fork()) == 0) {
830 close(fd[0]);
831 dup2(fd[1], fileno(stdout));
832 dup2(fd[1], fileno(stderr));
833 /* If execl() returns at all, there was an error. */
834
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000835 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000836 exit(0);
837 }
838
839 /* Else continue as parent. */
840
841 close(fd[1]);
842
843 if (pid == -1) {
844 close(fd[0]);
845 statusbar(_("Could not fork"));
846 return 1;
847 }
848
849 /* Before we start reading the forked command's output, we set
850 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000851 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000852 cancel_sigs = 1;
853 nperror("sigaction");
854 } else {
855 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000856 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000857 cancel_sigs = 1;
858 nperror("sigaction");
859 }
860 }
861 /* Note that now oldaction is the previous SIGINT signal handler,
862 * to be restored later. */
863
864 /* See if the platform supports disabling individual control
865 * characters. */
866#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000867 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000868 cancel_sigs = 2;
869 nperror("tcgetattr");
870 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000871 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000872 newterm = term;
873 /* Grab oldterm's VINTR key :-) */
874 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
875 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
876 cancel_sigs = 2;
877 nperror("tcsetattr");
878 }
879 }
880#endif /* _POSIX_VDISABLE */
881
882 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000883 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000884 nperror("fdopen");
885
886 read_file(f, "stdin", 0);
887 /* if multibuffer mode is on, we could be here in view mode; if so,
888 don't set the modification flag */
889 if (!ISSET(VIEW_MODE))
890 set_modified();
891
892 if (wait(NULL) == -1)
893 nperror("wait");
894
895#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000896 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000897 nperror("tcsetattr");
898#endif /* _POSIX_VDISABLE */
899
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000900 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000901 nperror("sigaction");
902
903 return 0;
904}
905#endif /* NANO_SMALL */
906
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000907#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000908void do_mouse(void)
909{
910 MEVENT mevent;
911 int currslen;
912 const shortcut *s = currshortcut;
913
914 if (getmouse(&mevent) == ERR)
915 return;
916
917 /* If mouse not in edit or bottom window, return */
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000918 if (wenclose(edit, mevent.y, mevent.x) && currshortcut == main_list) {
919 int sameline;
920 /* Did they click on the line with the cursor? If they
921 clicked on the cursor, we set the mark. */
922 size_t xcur;
923 /* The character they clicked on. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000924
925 /* Subtract out size of topwin. Perhaps we need a constant
926 * somewhere? */
927 mevent.y -= 2;
928
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000929 sameline = mevent.y == current_y;
930
931 /* Move to where the click occurred. */
932 for(; current_y < mevent.y && current->next != NULL; current_y++)
933 current = current->next;
934 for(; current_y > mevent.y && current->prev != NULL; current_y--)
935 current = current->prev;
936
937 xcur = actual_x(current, get_page_start(xplustabs()) + mevent.x);
938
939 /* Selecting where the cursor is toggles the mark. As does
940 selecting beyond the line length with the cursor at the end of
941 the line. */
942 if (sameline && xcur == current_x) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000943 if (ISSET(VIEW_MODE)) {
944 print_view_warning();
945 return;
946 }
947 do_mark();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000948 }
Chris Allegrettae92a7bc2003-01-28 01:36:38 +0000949
950 current_x = xcur;
951 placewewant = xplustabs();
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000952 edit_refresh();
953 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
954 int i, k;
955
956 if (currshortcut == main_list)
957 currslen = MAIN_VISIBLE;
958 else
959 currslen = length_of_list(currshortcut);
960
961 if (currslen < 2)
962 k = COLS / 6;
963 else
964 k = COLS / ((currslen + (currslen %2)) / 2);
965
966 /* Determine what shortcut list was clicked */
967 mevent.y -= (editwinrows + 3);
968
969 if (mevent.y < 0) /* They clicked on the statusbar */
970 return;
971
972 /* Don't select stuff beyond list length */
973 if (mevent.x / k >= currslen)
974 return;
975
976 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
977 s = s->next;
978
979 /* And ungetch that value */
980 ungetch(s->val);
981
982 /* And if it's an alt-key sequence, we should probably send alt
983 too ;-) */
984 if (s->val >= 'a' && s->val <= 'z')
985 ungetch(27);
986 }
987}
988#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000989
Chris Allegretta6df90f52002-07-19 01:08:59 +0000990/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000991void do_char(char ch)
992{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000993 size_t current_len = strlen(current->data);
994#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
995 int refresh = 0;
996 /* Do we have to run edit_refresh(), or can we get away with
997 * update_line()? */
998#endif
999
Robert Siemborski63b3d7e2000-07-04 22:15:39 +00001000 /* magic-line: when a character is inserted on the current magic line,
1001 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001002 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +00001003 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +00001004 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +00001005 }
1006
Chris Allegretta6df90f52002-07-19 01:08:59 +00001007 /* more dangerousness fun =) */
1008 current->data = nrealloc(current->data, current_len + 2);
1009 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001010 memmove(&current->data[current_x + 1],
1011 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +00001012 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001013 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001014 totsize++;
1015 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001016
Chris Allegretta6df90f52002-07-19 01:08:59 +00001017#ifndef NANO_SMALL
1018 /* note that current_x has not yet been incremented */
1019 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001020 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001021#endif
1022
Chris Allegretta6df90f52002-07-19 01:08:59 +00001023 do_right();
1024
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001025#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001026 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001027 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001028#endif
1029
Chris Allegretta6df90f52002-07-19 01:08:59 +00001030#ifdef ENABLE_COLOR
1031 refresh = 1;
1032#endif
1033
1034#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1035 if (refresh)
1036 edit_refresh();
1037#endif
1038
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001039 UNSET(KEEP_CUTBUFFER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001040}
1041
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001042int do_backspace(void)
1043{
1044 int refresh = 0;
1045 if (current_x > 0) {
1046 assert(current_x <= strlen(current->data));
1047 /* Let's get dangerous */
1048 memmove(&current->data[current_x - 1], &current->data[current_x],
1049 strlen(current->data) - current_x + 1);
1050#ifdef DEBUG
1051 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
1052#endif
1053 align(&current->data);
1054#ifndef NANO_SMALL
1055 if (current_x <= mark_beginx && mark_beginbuf == current)
1056 mark_beginx--;
1057#endif
1058 do_left();
1059#ifdef ENABLE_COLOR
1060 refresh = 1;
1061#endif
1062 } else {
1063 filestruct *previous;
1064 const filestruct *tmp;
1065
1066 if (current == fileage)
1067 return 0; /* Can't delete past top of file */
1068
1069 previous = current->prev;
1070 current_x = strlen(previous->data);
1071 placewewant = strlenpt(previous->data);
1072#ifndef NANO_SMALL
1073 if (current == mark_beginbuf) {
1074 mark_beginx += current_x;
1075 mark_beginbuf = previous;
1076 }
1077#endif
1078 previous->data = nrealloc(previous->data,
1079 current_x + strlen(current->data) + 1);
1080 strcpy(previous->data + current_x, current->data);
1081
1082 unlink_node(current);
1083 delete_node(current);
1084 tmp = current;
1085 current = (previous->next ? previous->next : previous);
1086 renumber(current);
1087 /* We had to renumber before doing update_line. */
1088 if (tmp == edittop)
1089 page_up();
1090
1091 /* Ooops, sanity check */
1092 if (tmp == filebot) {
1093 filebot = current;
1094 editbot = current;
1095
1096 /* Recreate the magic line if we're deleting it AND if the
1097 line we're on now is NOT blank. if it is blank we
1098 can just use IT for the magic line. This is how Pico
1099 appears to do it, in any case. */
1100 if (current->data[0] != '\0') {
1101 new_magicline();
1102 fix_editbot();
1103 }
1104 }
1105
1106 current = previous;
1107 if (current_y > 0)
1108 current_y--;
1109 totlines--;
1110#ifdef DEBUG
1111 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1112#endif
1113 UNSET(KEEP_CUTBUFFER);
1114 refresh = 1;
1115 }
1116
1117 totsize--;
1118 set_modified();
1119 if (refresh)
1120 edit_refresh();
1121 return 1;
1122}
1123
1124int do_delete(void)
1125{
1126 int refresh = 0;
1127
1128 /* blbf -> blank line before filebot (see below) */
1129 int blbf = 0;
1130
1131 if (current->next == filebot && current->data[0] == '\0')
1132 blbf = 1;
1133
1134 placewewant = xplustabs();
1135
1136 if (current_x != strlen(current->data)) {
1137 /* Let's get dangerous */
1138 memmove(&current->data[current_x], &current->data[current_x + 1],
1139 strlen(current->data) - current_x);
1140
1141 align(&current->data);
1142#ifdef ENABLE_COLOR
1143 refresh = 1;
1144#endif
1145 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1146 /* We can delete the line before filebot only if it is blank: it
1147 becomes the new magic line then. */
1148
1149 filestruct *foo;
1150
1151 current->data = nrealloc(current->data,
1152 strlen(current->data) +
1153 strlen(current->next->data) + 1);
1154 strcat(current->data, current->next->data);
1155
1156 foo = current->next;
1157 if (filebot == foo) {
1158 filebot = current;
1159 editbot = current;
1160 }
1161
1162 unlink_node(foo);
1163 delete_node(foo);
1164 renumber(current);
1165 totlines--;
1166 refresh = 1;
1167 } else
1168 return 0;
1169
1170 totsize--;
1171 set_modified();
1172 UNSET(KEEP_CUTBUFFER);
1173 update_line(current, current_x);
1174 if (refresh)
1175 edit_refresh();
1176 return 1;
1177}
1178
1179int do_tab(void)
1180{
1181 do_char('\t');
1182 return 1;
1183}
1184
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001185/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001186int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187{
Chris Allegrettae3167732001-03-18 16:59:34 +00001188 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001189 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001190
Chris Allegretta6df90f52002-07-19 01:08:59 +00001191 newnode = make_new_node(current);
1192 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001193 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001194
Chris Allegrettaff989832001-09-17 13:48:00 +00001195#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001196 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001197 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001198 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001199 const char *spc = current->data;
1200
1201 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001202 extra++;
1203 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001204 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001205 /* If current_x < extra, then we are breaking the line in the
1206 * indentation. Autoindenting should add only current_x
1207 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001208 if (current_x < extra)
1209 extra = current_x;
1210 else
1211 current_x = extra;
1212 totsize += extra;
1213
1214 newnode->data = charalloc(strlen(tmp) + extra + 1);
1215 strncpy(newnode->data, current->data, extra);
1216 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001217 } else
1218#endif
1219 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001220 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001221 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001222 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001223 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001224 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001225
Chris Allegretta6df90f52002-07-19 01:08:59 +00001226 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001227 filebot = newnode;
1228 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001229 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001230 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001231
1232 totsize++;
1233 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001234 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001235 align(&current->data);
1236
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001237 /* The logic here is as follows:
1238 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001239 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001240 * -> otherwise, we want simply to redraw the screen and update
1241 * where we think the cursor is.
1242 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001243 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001244#ifndef NANO_SMALL
1245 if (ISSET(SMOOTHSCROLL))
1246 edit_update(current, NONE);
1247 else
1248#endif
1249 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001250 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001251 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001252 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001253 edit_refresh();
1254 update_cursor();
1255 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001256
1257 totlines++;
1258 set_modified();
1259
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001260 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001261 return 1;
1262}
1263
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001264#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001265int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001266{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001267 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001268
Chris Allegretta6df90f52002-07-19 01:08:59 +00001269 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001270
Chris Allegretta6df90f52002-07-19 01:08:59 +00001271 /* Skip letters in this word first. */
1272 while (current->data[current_x] != '\0' &&
1273 isalnum((int)current->data[current_x]))
1274 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001275
Chris Allegretta6df90f52002-07-19 01:08:59 +00001276 for (; current != NULL; current = current->next) {
1277 while (current->data[current_x] != '\0' &&
1278 !isalnum((int)current->data[current_x]))
1279 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001280
Chris Allegretta6df90f52002-07-19 01:08:59 +00001281 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001282 break;
1283
Chris Allegretta6df90f52002-07-19 01:08:59 +00001284 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001285 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001286 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001287 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001288
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001289 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001290
Chris Allegrettad865da12002-07-29 23:46:38 +00001291 if (current->lineno >= editbot->lineno) {
1292 /* If we're on the last line, don't center the screen. */
1293 if (current->lineno == filebot->lineno)
1294 edit_refresh();
1295 else
1296 edit_update(current, CENTER);
1297 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001298 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001299 /* If we've jumped lines, refresh the old line. We can't just
1300 use current->prev here, because we may have skipped over some
1301 blank lines, in which case the previous line is the wrong
1302 one. */
1303 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001304 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001305 /* If the mark was set, then the lines between old and
1306 current have to be updated too. */
1307 if (ISSET(MARK_ISSET)) {
1308 while (old->next != current) {
1309 old = old->next;
1310 update_line(old, 0);
1311 }
1312 }
1313 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001314 update_line(current, current_x);
1315 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001316 return 0;
1317}
1318
Chris Allegretta6df90f52002-07-19 01:08:59 +00001319/* The same thing for backwards. */
1320int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001321{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001322 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001323
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001324 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001325
Chris Allegretta6df90f52002-07-19 01:08:59 +00001326 /* Skip letters in this word first. */
1327 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1328 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001329
Chris Allegretta6df90f52002-07-19 01:08:59 +00001330 for (; current != NULL; current = current->prev) {
1331 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1332 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001333
Chris Allegretta6df90f52002-07-19 01:08:59 +00001334 if (current_x >= 0)
1335 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001336
Chris Allegretta6df90f52002-07-19 01:08:59 +00001337 if (current->prev != NULL)
1338 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001339 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001340
Chris Allegretta6df90f52002-07-19 01:08:59 +00001341 if (current != NULL) {
1342 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1343 current_x--;
1344 } else {
1345 current = fileage;
1346 current_x = 0;
1347 }
1348
Chris Allegretta76e291b2001-10-14 19:05:10 +00001349 placewewant = xplustabs();
1350
Chris Allegrettad865da12002-07-29 23:46:38 +00001351 if (current->lineno <= edittop->lineno) {
1352 /* If we're on the first line, don't center the screen. */
1353 if (current->lineno == fileage->lineno)
1354 edit_refresh();
1355 else
1356 edit_update(current, CENTER);
1357 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001358 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001359 /* If we've jumped lines, refresh the old line. We can't just
1360 use current->prev here, because we may have skipped over some
1361 blank lines, in which case the previous line is the wrong
1362 one. */
1363 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001364 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001365 /* If the mark was set, then the lines between old and
1366 current have to be updated too. */
1367 if (ISSET(MARK_ISSET)) {
1368 while (old->prev != current) {
1369 old = old->prev;
1370 update_line(old, 0);
1371 }
1372 }
1373 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001374 update_line(current, current_x);
1375 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001376 return 0;
1377}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001378#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001379
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001380int do_mark(void)
1381{
1382#ifdef NANO_SMALL
1383 nano_disabled_msg();
1384#else
1385 if (!ISSET(MARK_ISSET)) {
1386 statusbar(_("Mark Set"));
1387 SET(MARK_ISSET);
1388 mark_beginbuf = current;
1389 mark_beginx = current_x;
1390 } else {
1391 statusbar(_("Mark UNset"));
1392 UNSET(MARK_ISSET);
1393 edit_refresh();
1394 }
1395#endif
1396 return 1;
1397}
1398
1399void wrap_reset(void)
1400{
1401 UNSET(SAMELINEWRAP);
1402}
1403
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001404#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001405/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001406 * moved forward since the last typed character. Return value:
1407 * whether we wrapped. */
1408int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001409{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001410 size_t len = strlen(inptr->data); /* length of the line we wrap */
1411 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001412 int wrap_loc = -1; /* index of inptr->data where we wrap */
1413 int word_back = -1;
1414#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001415 const char *indentation = NULL;
1416 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001417 int indent_len = 0; /* strlen(indentation) */
1418#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001419 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001420 int after_break_len; /* strlen(after_break) */
1421 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001422 const char *wrap_line = NULL;
1423 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001424 int wrap_line_len = 0; /* strlen(wrap_line) */
1425 char *newline = NULL; /* the line we create */
1426 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001427
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001428/* There are three steps. First, we decide where to wrap. Then, we
1429 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001430
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001431/* Step 1, finding where to wrap. We are going to add a new-line
1432 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001433 * location of this replacement.
1434 *
1435 * Where should we break the line? We need the last "legal wrap point"
1436 * such that the last word before it ended at or before fill. If there
1437 * is no such point, we settle for the first legal wrap point.
1438 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001439 * A "legal wrap point" is a white-space character that is not followed by
1440 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001441 *
1442 * If there is no legal wrap point or we found the last character of the
1443 * line, we should return without wrapping.
1444 *
1445 * Note that the initial indentation does not count as a legal wrap
1446 * point if we are going to auto-indent!
1447 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001448 * Note that the code below could be optimised, by not calling strnlenpt()
1449 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001450
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001451#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001452 if (ISSET(AUTOINDENT))
1453 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001454#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001455 wrap_line = inptr->data + i;
1456 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001457 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001458 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001459 word_back = i;
1460 /* if we have found a "legal wrap point" and the current word
1461 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001462 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001463 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001464 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001465 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001466 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001467 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001468 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001469 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001470
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001471/* Step 2, making the new wrap line. It will consist of indentation +
1472 * after_break + " " + wrap_line (although indentation and wrap_line are
1473 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001474
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001475 /* after_break is the text that will be moved to the next line. */
1476 after_break = inptr->data + wrap_loc + 1;
1477 after_break_len = len - wrap_loc - 1;
1478 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001479
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001480 /* new_line_len will later be increased by the lengths of indentation
1481 * and wrap_line. */
1482 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001483
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001484 /* We prepend the wrapped text to the next line, if the flag is set,
1485 * and there is a next line, and prepending would not make the line
1486 * too long. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +00001487 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001488 wrap_line = inptr->next->data;
1489 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001490
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001491 /* +1 for the space between after_break and wrap_line */
1492 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1493 wrapping = 1;
1494 new_line_len += (1 + wrap_line_len);
1495 }
1496 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001497
Chris Allegrettaff989832001-09-17 13:48:00 +00001498#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001499 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001500 /* Indentation comes from the next line if wrapping, else from
1501 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001502 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001503 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001504 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001505 /* The wrap_line text should not duplicate indentation.
1506 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001507 wrap_line += indent_len;
1508 else
1509 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001510 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001511#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001512
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001513 /* Now we allocate the new line and copy into it. */
1514 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1515 *newline = '\0';
1516
1517#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001518 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001519 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001520 newline[indent_len] = '\0';
1521 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001522#endif
1523 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001524 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001525 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001526 null_at(&inptr->data, wrap_loc + 1);
1527 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001528 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001529 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001530 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001531 * in a tab or a space, we don't add a space and decrement
1532 * totsize to account for that. */
Chris Allegrettad127c712003-02-12 23:20:45 +00001533 if (!isspace((int) newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001534 strcat(newline, " ");
1535 else
1536 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001537 strcat(newline, wrap_line);
1538 free(inptr->next->data);
1539 inptr->next->data = newline;
1540 } else {
1541 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001542
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001543 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001544 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001545#ifndef NANO_SMALL
1546 totsize += indent_len;
1547#endif
1548 totlines++;
1549 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001550 temp->prev = inptr;
1551 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001552 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001553 /* If temp->next is NULL, then temp is the last line of the
1554 * file, so we must set filebot. */
1555 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001556 temp->next->prev = temp;
1557 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001558 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001559 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001560
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001561/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1562 * other sundry things. */
1563
1564 /* later wraps of this line will be prepended to the next line. */
1565 SET(SAMELINEWRAP);
1566
1567 /* Each line knows its line number. We recalculate these if we
1568 * inserted a new line. */
1569 if (!wrapping)
1570 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001571
Chris Allegretta6df90f52002-07-19 01:08:59 +00001572 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001573 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001574 current = current->next;
1575 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001576#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001577 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001578#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001579 wrap_loc + 1;
1580 wrap_reset();
1581 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001582 }
1583
Chris Allegretta6df90f52002-07-19 01:08:59 +00001584#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001585 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001586 * If it was on the next line and we wrapped, we must move it
1587 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001588 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1589 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001590 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001591 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001592 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001593#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001594
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001595 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001596 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001597
1598 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001599}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001600#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001601
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001602#ifndef DISABLE_SPELLER
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001603/* word is misspelled in the file. Let the user replace it. We return
1604 False if the user cancels. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001605int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001606{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001607 char *save_search;
1608 char *save_replace;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001609 filestruct *current_save = current;
1610 int current_x_save = current_x;
1611 filestruct *edittop_save = edittop;
1612 /* Save where we are. */
1613 int i = 0;
1614 /* The return value. */
1615 int reverse_search_set = ISSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001616#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001617 int case_sens_set = ISSET(CASE_SENSITIVE);
1618 int mark_set = ISSET(MARK_ISSET);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001619
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001620 SET(CASE_SENSITIVE);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001621 /* Make sure the marking highlight is off during Spell Check */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001622 UNSET(MARK_ISSET);
1623#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001624 /* Make sure Spell Check goes forward only */
1625 UNSET(REVERSE_SEARCH);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001626
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001627 /* save the current search/replace strings */
1628 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001629 save_search = last_search;
1630 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001631
1632 /* set search/replace strings to mis-spelt word */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001633 last_search = mallocstrcpy(NULL, word);
1634 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001635
1636 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001637 current = fileage;
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001638 current_x = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001639
1640 search_last_line = FALSE;
1641
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001642 /* We find the first whole-word occurrence of word. */
1643 while (findnextstr(TRUE, TRUE, fileage, -1, word))
1644 if (is_whole_word(current_x, current->data, word)) {
1645 edit_refresh();
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001646
Chris Allegretta6df90f52002-07-19 01:08:59 +00001647 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001648
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001649 /* allow replace word to be corrected */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001650 i = statusq(0, spell_list, word,
Chris Allegretta7662c862003-01-13 01:35:15 +00001651#ifndef NANO_SMALL
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001652 NULL,
Chris Allegretta7662c862003-01-13 01:35:15 +00001653#endif
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001654 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001655
Chris Allegretta6df90f52002-07-19 01:08:59 +00001656 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001657
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001658 if (i != -1 && strcmp(word, answer)) {
1659 int j = 0;
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001660
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001661 search_last_line = FALSE;
1662 current_x--;
1663 do_replace_loop(word, current_save, &current_x_save, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001664 }
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001665
1666 break;
Chris Allegretta80838272001-12-02 06:03:22 +00001667 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001668
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001669 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001670 free(last_search); last_search=save_search;
1671 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001672
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001673 /* restore where we were */
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001674 current = current_save;
1675 current_x = current_x_save;
1676 edittop = edittop_save;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001677
Chris Allegretta23b74b22002-01-21 20:32:22 +00001678 /* restore Search/Replace direction */
1679 if (reverse_search_set)
1680 SET(REVERSE_SEARCH);
1681
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001682#ifndef NANO_SMALL
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001683 if (!case_sens_set)
1684 UNSET(CASE_SENSITIVE);
1685
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001686 /* restore marking highlight */
1687 if (mark_set)
1688 SET(MARK_ISSET);
1689#endif
1690
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001691 return i != -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001692}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001693
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001694/* Integrated spell checking using 'spell' program. Return value: NULL
1695 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001696char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001697{
Chris Allegretta271e9722000-11-10 18:15:43 +00001698 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001699 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001700 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001701 pid_t pid_spell, pid_sort, pid_uniq;
1702 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001703
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001704 /* Create all three pipes up front */
Chris Allegretta271e9722000-11-10 18:15:43 +00001705
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001706 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1707 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001708
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001709 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001710 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001711
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001712 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001713
1714 /* Child continues, (i.e. future spell process) */
1715
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001716 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001717
Chris Allegretta271e9722000-11-10 18:15:43 +00001718 /* replace the standard in with the tempfile */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001719 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1720 goto close_pipes_and_exit;
1721
1722 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1723 goto close_pipes_and_exit;
1724
Chris Allegretta271e9722000-11-10 18:15:43 +00001725 close(tempfile_fd);
1726
1727 /* send spell's standard out to the pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001728 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1729 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001730
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001731 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001732
1733 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001734 execlp("spell", "spell", NULL);
1735
Chris Allegretta271e9722000-11-10 18:15:43 +00001736 /* Should not be reached, if spell is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001737 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001738 }
1739
1740 /* Parent continues here */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001741 close(spell_fd[1]);
1742
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001743 /* A new process to run sort in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001744 if ((pid_sort = fork()) == 0) {
1745
1746 /* Child continues, (i.e. future spell process) */
1747 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001748 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1749 goto close_pipes_and_exit;
1750
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001751 close(spell_fd[0]);
1752
1753 /* send sort's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001754 if (dup2(sort_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(sort_fd[1]);
1758
1759 /* Start sort program. Use -f to remove mixed case without having
1760 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1761 execlp("sort", "sort", "-f", NULL);
1762
1763 /* Should not be reached, if sort is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001764 exit(1);
1765 }
1766
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001767 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001768 close(sort_fd[1]);
1769
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001770 /* A new process to run uniq in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001771 if ((pid_uniq = fork()) == 0) {
1772
1773 /* Child continues, (i.e. future uniq process) */
1774 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001775 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1776 goto close_pipes_and_exit;
1777
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001778 close(sort_fd[0]);
1779
1780 /* send uniq's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001781 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1782 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001783
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001784 close(uniq_fd[1]);
1785
1786 /* Start uniq program, we are using PATH */
1787 execlp("uniq", "uniq", NULL);
1788
1789 /* Should not be reached, if uniq is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001790 exit(1);
1791 }
1792
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001793 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001794 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001795
1796 /* Child process was not forked successfully */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001797 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1798 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001799 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001800 }
1801
Chris Allegretta271e9722000-11-10 18:15:43 +00001802 /* Get system pipe buffer size */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001803 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1804 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001805 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001806 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001807
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001808 /* Read-in the returned spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001809 read_buff_read = 0;
1810 read_buff_size = pipe_buff_size + 1;
1811 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001812
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001813 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001814 read_buff_read += bytesread;
1815 read_buff_size += pipe_buff_size;
1816 read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size);
1817 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001818
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001819 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001820
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001821 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001822 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001823
1824 /* Process the spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001825 read_buff_word = read_buff_ptr = read_buff;
1826
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001827 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001828
1829 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001830 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001831 if (read_buff_word != read_buff_ptr) {
1832 if (!do_int_spell_fix(read_buff_word)) {
1833 read_buff_word = read_buff_ptr;
1834 break;
1835 }
1836 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001837 read_buff_word = read_buff_ptr + 1;
1838 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001839 read_buff_ptr++;
1840 }
1841
1842 /* special case where last word doesn't end with \n or \r */
1843 if (read_buff_word != read_buff_ptr)
1844 do_int_spell_fix(read_buff_word);
1845
Chris Allegretta271e9722000-11-10 18:15:43 +00001846 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001847 replace_abort();
Chris Allegretta64fc78c2003-01-26 19:57:44 +00001848 edit_refresh();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001849
Chris Allegretta271e9722000-11-10 18:15:43 +00001850 /* Process end of spell process */
1851
Chris Allegretta334a9402002-12-16 04:25:53 +00001852 waitpid(pid_spell, &spell_status, 0);
1853 waitpid(pid_sort, &sort_status, 0);
1854 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001855
Chris Allegretta334a9402002-12-16 04:25:53 +00001856 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1857 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001858
Chris Allegretta334a9402002-12-16 04:25:53 +00001859 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1860 return _("Error invoking \"sort -f\"");
1861
1862 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1863 return _("Error invoking \"uniq\"");
1864
1865 /* Otherwise... */
1866 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001867
1868close_pipes_and_exit:
1869
1870 /* Don't leak any handles */
1871 close(tempfile_fd);
1872 close(spell_fd[0]);
1873 close(spell_fd[1]);
1874 close(sort_fd[0]);
1875 close(sort_fd[1]);
1876 close(uniq_fd[0]);
1877 close(uniq_fd[1]);
1878 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001879}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001880
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001881/* External spell checking. Return value: NULL for normal termination,
1882 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001883char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001884{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001885 int alt_spell_status, lineno_cur = current->lineno;
1886 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001887 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001888 char *ptr;
1889 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001890 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001891#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001892 int mark_set = ISSET(MARK_ISSET);
1893 int mbb_lineno_cur = 0;
1894 /* We're going to close the current file, and open the output of
1895 the alternate spell command. The line that mark_beginbuf
1896 points to will be freed, so we save the line number and restore
1897 afterwards. */
1898
1899 if (mark_set) {
1900 mbb_lineno_cur = mark_beginbuf->lineno;
1901 UNSET(MARK_ISSET);
1902 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001903#endif
1904
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001905 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001906
Chris Allegrettae434b452001-01-27 19:25:00 +00001907 /* Set up an argument list to pass the execvp function */
1908 if (spellargs == NULL) {
1909 spellargs = nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001910
Chris Allegrettae434b452001-01-27 19:25:00 +00001911 spellargs[0] = strtok(alt_speller, " ");
1912 while ((ptr = strtok(NULL, " ")) != NULL) {
1913 arglen++;
1914 spellargs = nrealloc(spellargs, arglen * sizeof(char *));
1915 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001916 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001917 spellargs[arglen - 1] = NULL;
1918 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001919 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001920
1921 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001922 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001923 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001924 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001925
1926 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001927 exit(1);
1928 }
1929
1930 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001931 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001932 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001933
1934 /* Wait for alternate speller to complete */
1935
1936 wait(&alt_spell_status);
Chris Allegretta334a9402002-12-16 04:25:53 +00001937 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1938 char *altspell_error = NULL;
1939 char *invoke_error = _("Could not invoke \"%s\"");
1940 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1941
1942 altspell_error = charalloc(msglen);
1943 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1944 return altspell_error;
1945 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001946
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001947 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001948 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001949 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001950 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001951
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001952#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001953 if (mark_set) {
1954 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1955 mark_beginbuf = current;
1956 mark_beginx = current_x;
1957 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001958 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001959 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001960#endif
1961
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001962 /* go back to the old position, mark the file as modified, and make
1963 sure that the titlebar is refreshed */
1964 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001965 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001966 clearok(topwin, FALSE);
1967 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001968
Chris Allegretta334a9402002-12-16 04:25:53 +00001969 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001970}
1971#endif
1972
1973int do_spell(void)
1974{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001975#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001976 nano_disabled_msg();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001977 return TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001978#else
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00001979 char *temp, *spell_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001980
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001981 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001982 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001983 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001984 return 0;
1985 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001986
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001987 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001988 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001989 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001990 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001991 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001992
Chris Allegrettae1f14522001-09-19 03:19:43 +00001993#ifdef ENABLE_MULTIBUFFER
1994 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001995 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00001996 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001997#endif
1998
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001999 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00002000 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002001 else
Chris Allegretta334a9402002-12-16 04:25:53 +00002002 spell_msg = do_int_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002003 remove(temp);
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00002004 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002005
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00002006 if (spell_msg != NULL) {
Chris Allegretta334a9402002-12-16 04:25:53 +00002007 statusbar(_("Spell checking failed: %s"), spell_msg);
2008 return 0;
2009 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002010
Chris Allegrettafdcb9e92003-02-12 02:52:04 +00002011 statusbar(_("Finished checking spelling"));
2012 return 1;
Chris Allegrettadbc12b22000-07-03 03:10:14 +00002013#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00002014}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002015
Chris Allegrettad865da12002-07-29 23:46:38 +00002016#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002017/* The "indentation" of a line is the white-space between the quote part
2018 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002019size_t indent_length(const char *line)
2020{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002021 size_t len = 0;
2022
2023 assert(line != NULL);
2024 while (*line == ' ' || *line == '\t') {
2025 line++;
2026 len++;
2027 }
2028 return len;
2029}
Chris Allegrettadffa2072002-07-24 01:02:26 +00002030#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002031
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002032#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00002033/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
2034 * it maintains 2 after a . ! or ?). Note the terminating \0
2035 * counts as a space.
2036 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002037 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00002038 * returns 1, otherwise returns 0.
2039 *
2040 * If changes_allowed, justify_format() might make line->data
2041 * shorter, and change the actual pointer with null_at().
2042 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002043 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002044 * skip should be at most strlen(line->data). The skip+1st character must
2045 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002046int justify_format(int changes_allowed, filestruct *line, size_t skip)
2047{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002048 const char *punct = ".?!";
2049 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00002050 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002051
Chris Allegretta6df90f52002-07-19 01:08:59 +00002052 /* These four asserts are assumptions about the input data. */
2053 assert(line != NULL);
2054 assert(line->data != NULL);
2055 assert(skip <= strlen(line->data));
2056 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002057
Chris Allegretta6df90f52002-07-19 01:08:59 +00002058 back = line->data + skip;
2059 front = back;
2060 for (; *front; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002061 int remove_space = 0;
2062 /* Do we want to remove this space? */
2063
Chris Allegretta6df90f52002-07-19 01:08:59 +00002064 if (*front == '\t') {
2065 if (!changes_allowed)
2066 return 1;
2067 *front = ' ';
2068 }
2069 /* these tests are safe since line->data + skip is not a space */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002070 if (*front == ' ' && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002071 const char *bob = front - 2;
2072
2073 remove_space = 1;
2074 for (bob = front - 2; bob >= line->data + skip; bob--) {
2075 if (strchr(punct, *bob) != NULL) {
2076 remove_space = 0;
2077 break;
2078 }
2079 if (strchr(brackets, *bob) == NULL)
2080 break;
2081 }
2082 }
2083
2084 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002085 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002086 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002087 if (!changes_allowed)
2088 return 1;
2089#ifndef NANO_SMALL
2090 if (mark_beginbuf == line && back - line->data < mark_beginx)
2091 mark_beginx--;
2092#endif
2093 } else {
2094 *back = *front;
2095 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002096 }
2097 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002098
2099 /* Remove spaces from the end of the line, except maintain 1 after a
2100 * sentence punctuation. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002101 while (line->data < back && *(back - 1) == ' ')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002102 back--;
2103 if (line->data < back && *back == ' ' &&
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002104 strchr(punct, *(back - 1)) != NULL)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002105 back++;
2106 if (!changes_allowed && back != front)
2107 return 1;
2108
2109 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002110 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002111
2112 /* Now back is the new end of line->data. */
2113 if (back != front) {
2114 totsize += back - line->data - strlen(line->data);
2115 null_at(&line->data, back - line->data);
2116#ifndef NANO_SMALL
2117 if (mark_beginbuf == line && back - line->data < mark_beginx)
2118 mark_beginx = back - line->data;
2119#endif
2120 }
2121 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002122}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002123
2124/* The "quote part" of a line is the largest initial substring matching
2125 * the quote string. This function returns the length of the quote part
2126 * of the given line.
2127 *
2128 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2129 * quotestr. */
2130#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002131size_t quote_length(const char *line, const regex_t *qreg)
2132{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002133 regmatch_t matches;
2134 int rc = regexec(qreg, line, 1, &matches, 0);
2135
2136 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2137 return 0;
2138 /* matches.rm_so should be 0, since the quote string should start with
2139 * the caret ^. */
2140 return matches.rm_eo;
2141}
2142#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002143size_t quote_length(const char *line)
2144{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002145 size_t qdepth = 0;
2146 size_t qlen = strlen(quotestr);
2147
2148 /* Compute quote depth level */
2149 while (!strcmp(line + qdepth, quotestr))
2150 qdepth += qlen;
2151 return qdepth;
2152}
2153#endif /* !HAVE_REGEX_H */
2154
Chris Allegretta6df90f52002-07-19 01:08:59 +00002155/* a_line and b_line are lines of text. The quotation part of a_line is
2156 * the first a_quote characters. Check that the quotation part of
2157 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002158int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002159 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002160{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002161 /* Here is the assumption about a_quote: */
2162 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002163 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002164 !strncmp(a_line, b_line, a_quote);
2165}
2166
2167/* We assume a_line and b_line have no quote part. Then, we return whether
2168 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002169size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002170 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002171{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002172 assert(a_indent == indent_length(a_line));
2173 assert(b_indent == indent_length(b_line));
2174
2175 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2176}
2177
2178/* Put the next par_len lines, starting with first_line, in the cut
2179 * buffer. We assume there are enough lines after first_line. We leave
2180 * copies of the lines in place, too. We return the new copy of
2181 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002182filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002183 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002184{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002185 /* We put the original lines, not copies, into the cut buffer, just
2186 * out of a misguided sense of consistency, so if you un-cut, you
2187 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002188 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002189
2190 set_modified();
2191 cutbuffer = NULL;
2192 for(; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002193 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002194
Chris Allegretta908f7702003-01-15 11:18:58 +00002195 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002196 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002197 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002198 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002199 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002200 edittop = bob;
2201#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002202 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002203 mark_beginbuf = bob;
2204#endif
2205 justify_format(1, bob,
2206 quote_len + indent_length(bob->data + quote_len));
2207
Chris Allegretta908f7702003-01-15 11:18:58 +00002208 assert(alice != NULL && bob != NULL);
2209 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002210 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002211 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002212 }
2213 return first_line;
2214}
2215
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002216/* Is it possible to break line at or before goal? */
2217int breakable(const char *line, int goal)
2218{
2219 for(; *line != '\0' && goal >= 0; line++) {
2220 if (*line == ' ' || *line == '\t')
2221 return TRUE;
2222
2223 if (is_cntrl_char(*line) != 0)
2224 goal -= 2;
2225 else
2226 goal -= 1;
2227 }
Chris Allegretta428f6202003-02-12 03:21:45 +00002228 /* If goal is not negative, the whole line (one word) was short
2229 * enough. */
2230 return goal >= 0;
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002231}
2232
Chris Allegretta6df90f52002-07-19 01:08:59 +00002233/* We are trying to break a chunk off line. We find the last space such
2234 * that the display length to there is at most goal + 1. If there is
2235 * no such space, and force is not 0, then we find the first space.
2236 * Anyway, we then take the last space in that group of spaces. The
2237 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002238int break_line(const char *line, int goal, int force)
2239{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002240 /* Note that we use int instead of size_t, since goal is at most COLS,
2241 * the screen width, which will always be reasonably small. */
2242 int space_loc = -1;
2243 /* Current tentative return value. Index of the last space we
2244 * found with short enough display width. */
2245 int cur_loc = 0;
2246 /* Current index in line */
2247
2248 assert(line != NULL);
2249 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2250 if (*line == ' ')
2251 space_loc = cur_loc;
2252 assert(*line != '\t');
2253
Chris Allegrettacf287c82002-07-20 13:57:41 +00002254 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002255 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002256 else
2257 goal--;
2258 }
2259 if (goal >= 0)
2260 /* In fact, the whole line displays shorter than goal. */
2261 return cur_loc;
2262 if (space_loc == -1) {
2263 /* No space found short enough. */
2264 if (force)
2265 for(; *line != '\0'; line++, cur_loc++)
2266 if (*line == ' ' && *(line + 1) != ' ')
2267 return cur_loc;
2268 return -1;
2269 }
2270 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002271 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002272 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2273 *(line - cur_loc + space_loc + 1) == '\0')
2274 space_loc++;
2275 return space_loc;
2276}
2277#endif /* !DISABLE_JUSTIFY */
2278
2279/* This function justifies the current paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002280int do_justify(void)
2281{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002282#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00002283 nano_disabled_msg();
2284 return 1;
2285#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002286
Chris Allegretta6df90f52002-07-19 01:08:59 +00002287/* To explain the justifying algorithm, I first need to define some
2288 * phrases about paragraphs and quotation:
2289 * A line of text consists of a "quote part", followed by an
2290 * "indentation part", followed by text. The functions quote_length()
2291 * and indent_length() calculate these parts.
2292 *
2293 * A line is "part of a paragraph" if it has a part not in the quote
2294 * part or the indentation.
2295 *
2296 * A line is "the beginning of a paragraph" if it is part of a paragraph
2297 * and
2298 * 1) it is the top line of the file, or
2299 * 2) the line above it is not part of a paragraph, or
2300 * 3) the line above it does not have precisely the same quote
2301 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002302 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002303 * indentation of the previous line, or
2304 * 5) this line has no quote part and some indentation, and
2305 * AUTOINDENT is not set.
2306 * The reason for number 5) is that if AUTOINDENT is not set, then an
2307 * indented line is expected to start a paragraph, like in books. Thus,
2308 * nano can justify an indented paragraph only if AUTOINDENT is turned
2309 * on.
2310 *
2311 * A contiguous set of lines is a "paragraph" if each line is part of
2312 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002313 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002314
Chris Allegretta6df90f52002-07-19 01:08:59 +00002315 size_t quote_len;
2316 /* Length of the initial quotation of the paragraph we justify. */
2317 size_t par_len;
2318 /* Number of lines in that paragraph. */
2319 filestruct *first_mod_line = NULL;
2320 /* Will be the first line of the resulting justified paragraph
2321 * that differs from the original. For restoring after uncut. */
2322 filestruct *last_par_line = current;
2323 /* Will be the last line of the result, also for uncut. */
2324 filestruct *cutbuffer_save = cutbuffer;
2325 /* When the paragraph gets modified, all lines from the changed
2326 * one down are stored in the cut buffer. We back up the original
2327 * to restore it later. */
2328
2329 /* We save these global variables to be restored if the user
2330 * unjustifies. Note we don't need to save totlines. */
2331 int current_x_save = current_x;
2332 int current_y_save = current_y;
2333 filestruct *current_save = current;
2334 int flags_save = flags;
2335 long totsize_save = totsize;
2336 filestruct *edittop_save = edittop;
2337 filestruct *editbot_save = editbot;
2338#ifndef NANO_SMALL
2339 filestruct *mark_beginbuf_save = mark_beginbuf;
2340 int mark_beginx_save = mark_beginx;
2341#endif
2342
2343 size_t indent_len; /* generic indentation length */
2344 filestruct *line; /* generic line of text */
2345 size_t i; /* generic loop variable */
2346
2347#ifdef HAVE_REGEX_H
2348 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002349 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002350 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2351
2352 if (rc) {
2353 size_t size = regerror(rc, &qreg, NULL, 0);
2354 char *strerror = charalloc(size);
2355
2356 regerror(rc, &qreg, strerror, size);
2357 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2358 free(strerror);
2359 return -1;
2360 }
2361#endif
2362
2363 /* Here is an assumption that is always true anyway. */
2364 assert(current != NULL);
2365
2366/* Here we find the first line of the paragraph to justify. If the
2367 * current line is in a paragraph, then we move back to the first line.
2368 * Otherwise we move down to the first line that is in a paragraph. */
2369 quote_len = quote_length(IFREG(current->data, &qreg));
2370 indent_len = indent_length(current->data + quote_len);
2371
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002372 current_x = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002373 if (current->data[quote_len + indent_len] != '\0') {
2374 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002375 * the first line of this paragraph. First we check items 1) and
2376 * 3) above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002377 while (current->prev != NULL && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002378 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002379 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002380 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002381 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002382
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002383 /* Is this line the beginning of a paragraph, according to
2384 items 2), 5), or 4) above? If so, stop. */
2385 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2386 (quote_len == 0 && indent_len > 0
2387#ifndef NANO_SMALL
2388 && !ISSET(AUTOINDENT)
2389#endif
2390 ) ||
2391 !indents_match(current->prev->data + quote_len,
2392 temp_id_len, current->data + quote_len, indent_len))
2393 break;
2394 indent_len = temp_id_len;
2395 current = current->prev;
2396 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002397 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002398 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002399 /* This line is not part of a paragraph. Move down until we get
2400 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002401 do {
2402 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002403 if (current->next == NULL) {
2404 placewewant = 0;
Chris Allegretta428f6202003-02-12 03:21:45 +00002405 edit_refresh();
2406#ifdef HAVE_REGEX_H
2407 regfree(&qreg);
2408#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00002409 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002410 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002411 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002412 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002413 quote_len = quote_length(IFREG(current->data, &qreg));
2414 indent_len = indent_length(current->data + quote_len);
2415 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002416 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002417/* Now current is the first line of the paragraph, and quote_len
2418 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002419
Chris Allegretta6df90f52002-07-19 01:08:59 +00002420/* Next step, compute par_len, the number of lines in this paragraph. */
2421 line = current;
2422 par_len = 1;
2423 indent_len = indent_length(line->data + quote_len);
2424
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002425 while (line->next != NULL && quotes_match(current->data, quote_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002426 IFREG(line->next->data, &qreg))) {
2427 size_t temp_id_len = indent_length(line->next->data + quote_len);
2428
2429 if (!indents_match(line->data + quote_len, indent_len,
2430 line->next->data + quote_len, temp_id_len) ||
2431 line->next->data[quote_len + temp_id_len] == '\0' ||
2432 (quote_len == 0 && temp_id_len > 0
2433#ifndef NANO_SMALL
2434 && !ISSET(AUTOINDENT)
2435#endif
2436 ))
2437 break;
2438 indent_len = temp_id_len;
2439 line = line->next;
2440 par_len++;
2441 }
2442#ifdef HAVE_REGEX_H
2443 /* We no longer need to check quotation. */
2444 regfree(&qreg);
2445#endif
2446/* Now par_len is the number of lines in this paragraph. Should never
2447 * call quotes_match() or quote_length() again. */
2448
2449/* Next step, we loop through the lines of this paragraph, justifying
2450 * each one individually. */
2451 for(; par_len > 0; current_y++, par_len--) {
2452 size_t line_len;
2453 size_t display_len;
2454 /* The width of current in screen columns. */
2455 int break_pos;
2456 /* Where we will break the line. */
2457
2458 indent_len = indent_length(current->data + quote_len) +
2459 quote_len;
2460 /* justify_format() removes excess spaces from the line, and
2461 * changes tabs to spaces. The first argument, 0, means don't
2462 * change the line, just say whether there are changes to be
2463 * made. If there are, we do backup_lines(), which copies the
2464 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002465 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002466 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002467 first_mod_line = backup_lines(current, par_len, quote_len);
2468
2469 line_len = strlen(current->data);
2470 display_len = strlenpt(current->data);
2471
2472 if (display_len > fill) {
2473 /* The line is too long. Try to wrap it to the next. */
2474 break_pos = break_line(current->data + indent_len,
2475 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002476 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002477 if (break_pos == -1 || break_pos + indent_len == line_len)
2478 /* We can't break the line, or don't need to, so just go
2479 * on to the next. */
2480 goto continue_loc;
2481 break_pos += indent_len;
2482 assert(break_pos < line_len);
2483 /* If we haven't backed up the paragraph, do it now. */
2484 if (first_mod_line == NULL)
2485 first_mod_line = backup_lines(current, par_len, quote_len);
2486 if (par_len == 1) {
2487 /* There is no next line in this paragraph. We make a new
2488 * line and copy text after break_pos into it. */
2489 splice_node(current, make_new_node(current),
2490 current->next);
Chris Allegretta428f6202003-02-12 03:21:45 +00002491 /* In a non-quoted paragraph, we copy the indent only if
2492 AUTOINDENT is turned on. */
2493 if (quote_len == 0)
2494#ifndef NANO_SMALL
2495 if (!ISSET(AUTOINDENT))
2496#endif
2497 indent_len = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002498 current->next->data = charalloc(indent_len + line_len -
2499 break_pos);
2500 strncpy(current->next->data, current->data,
2501 indent_len);
2502 strcpy(current->next->data + indent_len,
2503 current->data + break_pos + 1);
2504 assert(strlen(current->next->data) ==
2505 indent_len + line_len - break_pos - 1);
2506 totlines++;
2507 totsize += indent_len;
2508 par_len++;
2509 } else {
2510 size_t next_line_len = strlen(current->next->data);
2511
2512 indent_len = quote_len +
2513 indent_length(current->next->data + quote_len);
2514 current->next->data = (char *)nrealloc(current->next->data,
2515 sizeof(char) * (next_line_len + line_len -
2516 break_pos + 1));
2517
2518 memmove(current->next->data + indent_len + line_len - break_pos,
2519 current->next->data + indent_len,
2520 next_line_len - indent_len + 1);
2521 strcpy(current->next->data + indent_len,
2522 current->data + break_pos + 1);
2523 current->next->data[indent_len + line_len - break_pos - 1]
2524 = ' ';
2525#ifndef NANO_SMALL
2526 if (mark_beginbuf == current->next) {
2527 if (mark_beginx < indent_len)
2528 mark_beginx = indent_len;
2529 mark_beginx += line_len - break_pos;
2530 }
2531#endif
2532 }
2533#ifndef NANO_SMALL
2534 if (mark_beginbuf == current && mark_beginx > break_pos) {
2535 mark_beginbuf = current->next;
2536 mark_beginx -= break_pos + 1 - indent_len;
2537 }
2538#endif
2539 null_at(&current->data, break_pos);
2540 current = current->next;
2541 } else if (display_len < fill && par_len > 1) {
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002542 size_t next_line_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002543
2544 indent_len = quote_len +
2545 indent_length(current->next->data + quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002546 /* If we can't pull a word from the next line up to this one,
2547 * just go on. */
2548 if (!breakable(current->next->data + indent_len,
2549 fill - display_len - 1))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002550 goto continue_loc;
2551
2552 /* If we haven't backed up the paragraph, do it now. */
2553 if (first_mod_line == NULL)
2554 first_mod_line = backup_lines(current, par_len, quote_len);
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002555
2556 break_pos = break_line(current->next->data + indent_len,
2557 fill - display_len - 1, FALSE);
2558 assert(break_pos != -1);
2559
Chris Allegretta6df90f52002-07-19 01:08:59 +00002560 current->data = (char *)nrealloc(current->data,
2561 line_len + break_pos + 2);
2562 current->data[line_len] = ' ';
2563 strncpy(current->data + line_len + 1,
2564 current->next->data + indent_len, break_pos);
2565 current->data[line_len + break_pos + 1] = '\0';
2566#ifndef NANO_SMALL
2567 if (mark_beginbuf == current->next) {
2568 if (mark_beginx < indent_len + break_pos) {
2569 mark_beginbuf = current;
2570 if (mark_beginx <= indent_len)
2571 mark_beginx = line_len + 1;
2572 else
2573 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2574 } else
2575 mark_beginx -= break_pos + 1;
2576 }
2577#endif
Chris Allegrettacff6e6f2003-02-03 03:22:02 +00002578 next_line_len = strlen(current->next->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002579 if (indent_len + break_pos == next_line_len) {
2580 line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002581
2582 /* Don't destroy edittop! */
2583 if (line == edittop)
2584 edittop = current;
2585
Chris Allegretta6df90f52002-07-19 01:08:59 +00002586 unlink_node(line);
2587 delete_node(line);
2588 totlines--;
2589 totsize -= indent_len;
2590 current_y--;
2591 } else {
2592 memmove(current->next->data + indent_len,
2593 current->next->data + indent_len + break_pos + 1,
2594 next_line_len - break_pos - indent_len);
2595 null_at(&current->next->data,
2596 next_line_len - break_pos);
2597 current = current->next;
2598 }
2599 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002600 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002601 current = current->next;
2602 }
2603/* We are now done justifying the paragraph. There are cleanup things to
2604 * do, and we check for unjustify. */
2605
2606 /* totlines, totsize, and current_y have been maintained above. We
2607 * now set last_par_line to the new end of the paragraph, update
2608 * fileage, set current_x. Also, edit_refresh() needs the line
2609 * numbers to be right, so we renumber(). */
2610 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002611 if (first_mod_line != NULL) {
2612 if (first_mod_line->prev == NULL)
2613 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002614 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002615 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002616
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002617 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002618 edit_update(current, CENTER);
2619 else
2620 edit_refresh();
2621
Chris Allegretta9149e612000-11-27 00:23:41 +00002622 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002623 /* Change the shortcut list to display the unjustify code */
2624 shortcut_init(1);
2625 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002626 reset_cursor();
2627
Chris Allegretta6df90f52002-07-19 01:08:59 +00002628 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002629 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002630
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002631#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002632 /* If it was a mouse click, parse it with do_mouse() and it might
2633 * become the unjustify key. Else give it back to the input stream. */
2634 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002635 do_mouse();
2636 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002637 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002638#endif
Chris Allegretta5f071802001-05-06 02:34:31 +00002639
Chris Allegretta6df90f52002-07-19 01:08:59 +00002640 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2641 ungetch(i);
2642 /* Did we back up anything at all? */
2643 if (cutbuffer != cutbuffer_save)
2644 free_filestruct(cutbuffer);
2645 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002646 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002647 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002648 current = current_save;
2649 current_x = current_x_save;
2650 current_y = current_y_save;
2651 edittop = edittop_save;
2652 editbot = editbot_save;
2653 if (first_mod_line != NULL) {
2654 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002655
Chris Allegretta6df90f52002-07-19 01:08:59 +00002656 /* Splice the cutbuffer back into the file. */
2657 cutbottom->next = last_par_line->next;
2658 cutbottom->next->prev = cutbottom;
2659 /* The line numbers after the end of the paragraph have
2660 * been changed, so we change them back. */
2661 renumber(cutbottom->next);
2662 if (first_mod_line->prev != NULL) {
2663 cutbuffer->prev = first_mod_line->prev;
2664 cutbuffer->prev->next = cutbuffer;
2665 } else
2666 fileage = cutbuffer;
2667 cutbuffer = NULL;
2668
2669 last_par_line->next = NULL;
2670 free_filestruct(first_mod_line);
2671
2672 /* Restore global variables from before justify */
2673 totsize = totsize_save;
2674 totlines = filebot->lineno;
2675#ifndef NANO_SMALL
2676 mark_beginbuf = mark_beginbuf_save;
2677 mark_beginx = mark_beginx_save;
2678#endif
2679 flags = flags_save;
2680 if (!ISSET(MODIFIED)) {
2681 titlebar(NULL);
2682 wrefresh(topwin);
2683 }
2684 }
2685 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002686 }
Chris Allegretta2a7b8b22003-01-30 00:42:20 +00002687 UNSET(KEEP_CUTBUFFER);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002688 cutbuffer = cutbuffer_save;
2689 blank_statusbar_refresh();
2690 /* display shortcut list without UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002691 shortcut_init(0);
2692 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002693
Chris Allegretta6df90f52002-07-19 01:08:59 +00002694 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002695#endif
2696}
2697
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002698int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002699{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002700 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002701
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002702 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002703
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002704#ifdef ENABLE_MULTIBUFFER
2705 if (!close_open_file()) {
2706 display_main_list();
2707 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002708 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002709 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002710#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002711 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002712 }
2713
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002714 if (ISSET(TEMP_OPT)) {
2715 i = 1;
2716 } else {
2717 i = do_yesno(0, 0,
2718 _
2719 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2720 }
2721
2722#ifdef DEBUG
2723 dump_buffer(fileage);
2724#endif
2725
2726 if (i == 1) {
2727 if (do_writeout(filename, 1, 0) > 0) {
2728
2729#ifdef ENABLE_MULTIBUFFER
2730 if (!close_open_file()) {
2731 display_main_list();
2732 return 1;
2733 }
2734 else
2735#endif
2736 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002737 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002738 } else if (i == 0) {
2739
2740#ifdef ENABLE_MULTIBUFFER
2741 if (!close_open_file()) {
2742 display_main_list();
2743 return 1;
2744 }
2745 else
2746#endif
2747 finish(0);
2748 } else
2749 statusbar(_("Cancelled"));
2750
2751 display_main_list();
2752 return 1;
2753}
2754
2755void signal_init(void)
2756{
2757#ifdef _POSIX_VDISABLE
2758 struct termios term;
2759#endif
2760
2761 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2762 memset(&act, 0, sizeof(struct sigaction));
2763 act.sa_handler = SIG_IGN;
2764 sigaction(SIGINT, &act, NULL);
2765
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002766 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2767 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002768 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002769 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002770
2771#ifndef NANO_SMALL
2772 act.sa_handler = handle_sigwinch;
2773 sigaction(SIGWINCH, &act, NULL);
2774#endif
2775
2776#ifdef _POSIX_VDISABLE
2777 tcgetattr(0, &term);
2778
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002779 if (!ISSET(PRESERVE)) {
2780 /* Ignore ^S and ^Q, much to Chris' chagrin */
2781 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2782 term.c_cc[VSTART] = _POSIX_VDISABLE;
2783 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002784#ifdef VDSUSP
2785 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2786#endif /* VDSUSP */
2787
2788#endif /* _POSIX_VDISABLE */
2789
2790 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002791 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002792#ifdef _POSIX_VDISABLE
2793 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2794#else
2795 act.sa_handler = SIG_IGN;
2796 sigaction(SIGTSTP, &act, NULL);
2797#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002798 } else {
2799 /* If we don't do this, it seems other stuff interrupts the
2800 suspend handler! Try using nano with mutt without this
2801 line. */
2802 sigfillset(&act.sa_mask);
2803
2804 act.sa_handler = do_suspend;
2805 sigaction(SIGTSTP, &act, NULL);
2806
2807 act.sa_handler = do_cont;
2808 sigaction(SIGCONT, &act, NULL);
2809 }
2810
2811#ifdef _POSIX_VDISABLE
2812 tcsetattr(0, TCSANOW, &term);
2813#endif
2814}
2815
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002816/* Handler for SIGHUP and SIGTERM */
2817RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002818{
Chris Allegrettaa0d89972003-02-03 03:32:08 +00002819 die(_("Received SIGHUP or SIGTERM\n"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002820}
2821
2822/* What do we do when we catch the suspend signal */
2823RETSIGTYPE do_suspend(int signal)
2824{
2825 endwin();
Chris Allegretta76417082003-02-12 23:54:34 +00002826 printf("\n\n\n\n\n%s\n", _("Use \"fg\" to return to nano"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002827 fflush(stdout);
2828
2829 /* Restore the terminal settings for the disabled keys */
2830 tcsetattr(0, TCSANOW, &oldterm);
2831
2832 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002833 then we could be (and were) interrupted in the middle of the call.
2834 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002835 kill(0, SIGSTOP);
2836}
2837
2838/* Restore the suspend handler when we come back into the prog */
2839RETSIGTYPE do_cont(int signal)
2840{
2841 /* Now we just update the screen instead of having to reenable the
2842 SIGTSTP handler. */
2843
2844 doupdate();
2845 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2846 start suspending again. */
2847 signal_init();
2848
2849#ifndef NANO_SMALL
2850 /* Perhaps the user resized the window while we slept. */
2851 handle_sigwinch(0);
2852#endif
2853}
2854
2855#ifndef NANO_SMALL
2856void handle_sigwinch(int s)
2857{
2858 const char *tty = ttyname(0);
2859 int fd;
2860 int result = 0;
2861 struct winsize win;
2862
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002863 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002864 return;
2865 fd = open(tty, O_RDWR);
2866 if (fd == -1)
2867 return;
2868 result = ioctl(fd, TIOCGWINSZ, &win);
2869 close(fd);
2870 if (result == -1)
2871 return;
2872
2873 /* Could check whether the COLS or LINES changed, and return
2874 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2875 * variables, and in some cases ncurses has already updated them.
2876 * But not in all cases, argh. */
2877 COLS = win.ws_col;
2878 LINES = win.ws_row;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002879 editwinrows = LINES - 5 + no_help();
2880 if (editwinrows < MIN_EDITOR_ROWS || COLS < MIN_EDITOR_COLS)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002881 die_too_small();
2882
2883#ifndef DISABLE_WRAPJUSTIFY
2884 fill = wrap_at;
2885 if (fill <= 0)
2886 fill += COLS;
Chris Allegrettaf8f2d582003-02-10 02:43:48 +00002887 if (fill < 0)
2888 fill = 0;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002889#endif
2890
2891 hblank = nrealloc(hblank, COLS + 1);
2892 memset(hblank, ' ', COLS);
2893 hblank[COLS] = '\0';
2894
2895#ifdef HAVE_RESIZETERM
2896 resizeterm(LINES, COLS);
2897#ifdef HAVE_WRESIZE
2898 if (wresize(topwin, 2, COLS) == ERR)
2899 die(_("Cannot resize top win"));
2900 if (mvwin(topwin, 0, 0) == ERR)
2901 die(_("Cannot move top win"));
2902 if (wresize(edit, editwinrows, COLS) == ERR)
2903 die(_("Cannot resize edit win"));
2904 if (mvwin(edit, 2, 0) == ERR)
2905 die(_("Cannot move edit win"));
2906 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2907 die(_("Cannot resize bottom win"));
2908 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2909 die(_("Cannot move bottom win"));
2910#endif /* HAVE_WRESIZE */
2911#endif /* HAVE_RESIZETERM */
2912
2913 fix_editbot();
2914
2915 if (current_y > editwinrows - 1)
2916 edit_update(editbot, CENTER);
2917 erase();
2918
2919 /* Do these b/c width may have changed... */
2920 refresh();
2921 titlebar(NULL);
2922 edit_refresh();
2923 display_main_list();
2924 blank_statusbar();
2925 total_refresh();
2926
2927 /* Turn cursor back on for sure */
2928 curs_set(1);
2929
2930 /* Jump back to main loop */
2931 siglongjmp(jmpbuf, 1);
2932}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002933#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002934
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002935/* If the NumLock key has made the keypad go awry, print an error
2936 message; hopefully we can address it later. */
2937void print_numlock_warning(void)
2938{
2939 static int didmsg = 0;
2940 if (!didmsg) {
2941 statusbar(_
2942 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2943 didmsg = 1;
2944 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002945}
2946
Chris Allegrettadab017e2002-04-23 10:56:06 +00002947#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002948void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002949{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002950 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002951
Chris Allegretta658399a2001-06-14 02:54:22 +00002952 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002953 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002954
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002955 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002956 case TOGGLE_SUSPEND_KEY:
2957 signal_init();
2958 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002959#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00002960 case TOGGLE_MOUSE_KEY:
2961 mouse_init();
2962 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002963#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002964 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002965 wclear(bottomwin);
2966 wrefresh(bottomwin);
2967 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002968 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002969 edit_refresh();
2970 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002971 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002972 case TOGGLE_DOS_KEY:
2973 UNSET(MAC_FILE);
2974 break;
2975 case TOGGLE_MAC_KEY:
2976 UNSET(DOS_FILE);
2977 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002978#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002979 case TOGGLE_SYNTAX_KEY:
2980 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002981 break;
2982#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002983 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002984
Chris Allegretta6df90f52002-07-19 01:08:59 +00002985 /* We are assuming here that shortcut_init() above didn't free and
2986 * reallocate the toggles. */
2987 enabled = ISSET(which->flag);
2988 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2989 enabled = !enabled;
2990 statusbar("%s %s", which->desc,
2991 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002992}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002993#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002994
Chris Allegretta1748cd12001-01-13 17:22:54 +00002995/* This function returns the correct keystroke, given the A,B,C or D
2996 input key. This is a common sequence of many terms which send
2997 Esc-O-[A-D] or Esc-[-[A-D]. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002998int abcd(int input)
Chris Allegretta1748cd12001-01-13 17:22:54 +00002999{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003000 switch (input) {
3001 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003002 case 'a':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003003 return KEY_UP;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003004 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003005 case 'b':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003006 return KEY_DOWN;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003007 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003008 case 'c':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003009 return KEY_RIGHT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003010 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003011 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003012 return KEY_LEFT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003013 default:
3014 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00003015 }
3016}
3017
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003018int main(int argc, char *argv[])
3019{
3020 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003021 int startline = 0; /* Line to try and start at */
Chris Allegretta9caa1932002-02-15 20:08:05 +00003022 int modify_control_seq;
Chris Allegretta09fc4302003-01-16 22:16:38 +00003023 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003024 const shortcut *s;
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003025#ifdef HAVE_GETOPT_LONG
3026 int preserveopt = 0; /* Did the cmdline include --preserve? */
3027#endif
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003028#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003029 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003030#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003031#ifdef _POSIX_VDISABLE
3032 struct termios term;
3033#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003034#ifdef HAVE_GETOPT_LONG
3035 int option_index = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003036 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003037 {"help", 0, 0, 'h'},
3038#ifdef ENABLE_MULTIBUFFER
3039 {"multibuffer", 0, 0, 'F'},
3040#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003041#ifdef ENABLE_NANORC
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003042 {"historylog", 0, 0, 'H'},
Chris Allegretta6df90f52002-07-19 01:08:59 +00003043 {"ignorercfiles", 0, 0, 'I'},
3044#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003045 {"keypad", 0, 0, 'K'},
3046#ifndef DISABLE_JUSTIFY
3047 {"quotestr", 1, 0, 'Q'},
3048#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003049#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003050 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003051#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003052 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003053 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054#ifdef ENABLE_COLOR
3055 {"syntax", 1, 0, 'Y'},
3056#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003057 {"const", 0, 0, 'c'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003058 {"nofollow", 0, 0, 'l'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003059#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003060 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003061#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003062#ifndef DISABLE_OPERATINGDIR
3063 {"operatingdir", 1, 0, 'o'},
3064#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003065 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003066#ifndef DISABLE_WRAPJUSTIFY
3067 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003068#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003069#ifndef DISABLE_SPELLER
3070 {"speller", 1, 0, 's'},
3071#endif
3072 {"tempfile", 0, 0, 't'},
3073 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003074#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003075 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003076#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003077 {"nohelp", 0, 0, 'x'},
3078 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003079#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003080 {"backup", 0, 0, 'B'},
3081 {"dos", 0, 0, 'D'},
3082 {"mac", 0, 0, 'M'},
3083 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003084 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003085 {"autoindent", 0, 0, 'i'},
3086 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003087#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003088 {0, 0, 0, 0}
3089 };
3090#endif
3091
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003092#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003093 setlocale(LC_ALL, "");
3094 bindtextdomain(PACKAGE, LOCALEDIR);
3095 textdomain(PACKAGE);
3096#endif
3097
Chris Allegretta7662c862003-01-13 01:35:15 +00003098#ifdef HAVE_GETOPT_LONG
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003099 {
Chris Allegretta7662c862003-01-13 01:35:15 +00003100 /* Check for the --preserve flag, and report error if people are
3101 still using --pico. */
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003102 int i;
3103 for (i = 1; i < argc; i++) {
Chris Allegretta7662c862003-01-13 01:35:15 +00003104 if (!strcmp(argv[i], "--preserve"))
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003105 preserveopt = 1;
3106 else if (!strcmp(argv[i], "--pico"))
3107 do_preserve_msg();
Chris Allegretta6df90f52002-07-19 01:08:59 +00003108 }
3109 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003110#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00003111
Chris Allegretta7662c862003-01-13 01:35:15 +00003112#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003113 /* if we don't have rcfile support, we're root, and
3114 --disable-wrapping-as-root is used, turn wrapping off */
3115 if (geteuid() == 0)
3116 SET(NO_WRAP);
3117#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003118
3119#ifdef HAVE_GETOPT_LONG
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003120 while ((optchr = getopt_long(argc, argv, "h?BDFHIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz",
Chris Allegretta7662c862003-01-13 01:35:15 +00003121 long_options, &option_index)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003122#else
3123 while ((optchr =
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003124 getopt(argc, argv, "h?BDFHIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003125#endif
3126
3127 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003128
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003129 case 'a':
3130 case 'b':
3131 case 'e':
3132 case 'f':
3133 case 'g':
3134 case 'j':
3135 /* Pico compatibility flags */
3136 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003137#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003138 case 'B':
3139 SET(BACKUP_FILE);
3140 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003141 case 'D':
3142 SET(DOS_FILE);
3143 break;
3144#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003145#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003146 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003147 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003148 break;
3149#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003150#ifdef ENABLE_NANORC
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003151 case 'H':
3152 SET(HISTORYLOG);
3153 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003154 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003155 SET(NO_RCFILE);
3156 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003157#endif
Chris Allegretta48bd3782002-01-03 21:26:34 +00003158 case 'K':
3159 SET(ALT_KEYPAD);
3160 break;
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003161#ifndef NANO_SMALL
3162 case 'M':
3163 SET(MAC_FILE);
3164 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003165 case 'N':
3166 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003167 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003168#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003169#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003170 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003171 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003172 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003173#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003174#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003175 case 'R':
3176 SET(USE_REGEXP);
3177 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003178#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003179#ifndef NANO_SMALL
3180 case 'S':
3181 SET(SMOOTHSCROLL);
3182 break;
3183#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003184 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003185 {
3186 int i;
3187 char *first_error;
3188
Chris Allegretta7662c862003-01-13 01:35:15 +00003189 /* Using strtol() instead of atoi() lets us accept 0
3190 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003191 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003192 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003193 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003194 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003195 tabsize = i;
3196 if (tabsize <= 0) {
3197 fprintf(stderr, _("Tab size is too small for nano...\n"));
3198 exit(1);
3199 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003200 }
3201 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003202 case 'V':
3203 version();
3204 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003205#ifdef ENABLE_COLOR
3206 case 'Y':
3207 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3208 break;
3209#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003210 case 'c':
3211 SET(CONSTUPDATE);
3212 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003213#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003214 case 'i':
3215 SET(AUTOINDENT);
3216 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003217 case 'k':
3218 SET(CUT_TO_END);
3219 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003220#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003221 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003222 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003223 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003224#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003225 case 'm':
3226 SET(USE_MOUSE);
3227 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003228#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003229#ifndef DISABLE_OPERATINGDIR
3230 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003231 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003232 break;
3233#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003234 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003235 SET(PRESERVE);
3236#ifdef HAVE_GETOPT_LONG
3237 if (!preserveopt)
3238 do_preserve_msg();
3239#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003240 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003241#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003242 case 'r':
3243 {
3244 int i;
3245 char *first_error;
3246
Chris Allegretta7662c862003-01-13 01:35:15 +00003247 /* Using strtol() instead of atoi() lets us accept 0
3248 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003249 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003250 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003251 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003252 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003253 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003254 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003255 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003256 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003257#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003258#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003259 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003260 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003261 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003262#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003263 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003264 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003265 break;
3266 case 'v':
3267 SET(VIEW_MODE);
3268 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003269#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003270 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003271 SET(NO_WRAP);
3272 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003273#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003274 case 'x':
3275 SET(NO_HELP);
3276 break;
3277 case 'z':
3278 SET(SUSPEND);
3279 break;
3280 default:
3281 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003282 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003283 }
3284
Chris Allegretta7662c862003-01-13 01:35:15 +00003285/* We've read through the command line options. Now back up the flags
3286 and values that are set, and read the rcfile(s). If the values
3287 haven't changed afterward, restore the backed-up values. */
3288#ifdef ENABLE_NANORC
3289 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003290#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003291 char *operating_dir_cpy = operating_dir;
3292#endif
3293#ifndef DISABLE_WRAPPING
3294 int wrap_at_cpy = wrap_at;
3295#endif
3296#ifndef DISABLE_JUSTIFY
3297 char *quotestr_cpy = quotestr;
3298#endif
3299#ifndef DISABLE_SPELLER
3300 char *alt_speller_cpy = alt_speller;
3301#endif
3302 int tabsize_cpy = tabsize;
3303 long flags_cpy = flags;
3304
Chris Allegretta5ec68622003-02-05 02:39:34 +00003305#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003306 operating_dir = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003307#endif
3308#ifndef DISABLE_JUSTIFY
Chris Allegretta7662c862003-01-13 01:35:15 +00003309 quotestr = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003310#endif
3311#ifndef DISABLE_SPELLER
Chris Allegretta7662c862003-01-13 01:35:15 +00003312 alt_speller = NULL;
Chris Allegretta5ec68622003-02-05 02:39:34 +00003313#endif
Chris Allegretta7662c862003-01-13 01:35:15 +00003314
3315 do_rcfile();
3316
3317#ifndef DISABLE_OPERATINGDIR
3318 if (operating_dir_cpy != NULL) {
3319 free(operating_dir);
3320 operating_dir = operating_dir_cpy;
3321 }
3322#endif
3323#ifndef DISABLE_WRAPPING
3324 if (fill_flag_used)
3325 wrap_at = wrap_at_cpy;
3326#endif
3327#ifndef DISABLE_JUSTIFY
3328 if (quotestr_cpy != NULL) {
3329 free(quotestr);
3330 quotestr = quotestr_cpy;
3331 }
3332#endif
3333#ifndef DISABLE_SPELLER
3334 if (alt_speller_cpy != NULL) {
3335 free(alt_speller);
3336 alt_speller = alt_speller_cpy;
3337 }
3338#endif
3339 if (tabsize_cpy > 0)
3340 tabsize = tabsize_cpy;
3341 flags |= flags_cpy;
3342 }
3343#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3344 else if (geteuid() == 0)
3345 SET(NO_WRAP);
3346#endif
3347#endif /* ENABLE_NANORC */
3348
3349#ifndef DISABLE_OPERATINGDIR
3350 /* Set up the operating directory. This entails chdir()ing there,
3351 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003352 init_operating_dir();
3353#endif
3354
Chris Allegretta7662c862003-01-13 01:35:15 +00003355#ifndef DISABLE_JUSTIFY
3356 if (quotestr == NULL)
3357#ifdef HAVE_REGEX_H
3358 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3359#else
3360 quotestr = mallocstrcpy(NULL, "> ");
3361#endif
3362#endif /* !DISABLE_JUSTIFY */
3363 if (tabsize == -1)
3364 tabsize = 8;
3365
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003366 /* Clear the filename we'll be using */
3367 filename = charalloc(1);
3368 filename[0] = '\0';
3369
Chris Allegretta7662c862003-01-13 01:35:15 +00003370 /* If there's a +LINE flag, it is the first non-option argument. */
3371 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3372 startline = atoi(&argv[optind][1]);
3373 optind++;
3374 }
3375 if (0 < optind && optind < argc)
3376 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003377
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003378 /* See if there's a non-option in argv (first non-option is the
3379 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003380 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003381 /* Look for the +line flag... */
3382 if (argv[optind][0] == '+') {
3383 startline = atoi(&argv[optind][1]);
3384 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003385 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003386 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003387 } else
3388 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003389 }
3390
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003391 /* First back up the old settings so they can be restored, duh */
3392 tcgetattr(0, &oldterm);
3393
3394#ifdef _POSIX_VDISABLE
3395 term = oldterm;
3396 term.c_cc[VINTR] = _POSIX_VDISABLE;
3397 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3398 term.c_lflag &= ~IEXTEN;
3399 tcsetattr(0, TCSANOW, &term);
3400#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003401
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003402 /* now ncurses init stuff... */
3403 initscr();
3404 savetty();
3405 nonl();
3406 cbreak();
3407 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003408
3409 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003410 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003411 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003412 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003413
3414#ifdef DEBUG
3415 fprintf(stderr, _("Main: set up windows\n"));
3416#endif
3417
Chris Allegretta2a42af12000-09-12 23:02:49 +00003418 window_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003419#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00003420 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003421#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003422
Chris Allegretta48bd3782002-01-03 21:26:34 +00003423 if (!ISSET(ALT_KEYPAD)) {
3424 keypad(edit, TRUE);
3425 keypad(bottomwin, TRUE);
3426 }
3427
Chris Allegretta5beed502003-01-05 20:41:21 +00003428#ifndef NANO_SMALL
3429 history_init();
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003430#ifdef ENABLE_NANORC
3431 if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
3432 load_history();
Chris Allegretta5beed502003-01-05 20:41:21 +00003433#endif
Chris Allegrettaf3de8b52003-01-16 23:44:46 +00003434#endif
3435
3436
3437
Chris Allegretta5beed502003-01-05 20:41:21 +00003438
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003439#ifdef DEBUG
3440 fprintf(stderr, _("Main: bottom win\n"));
3441#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003442 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003443 display_main_list();
3444
3445#ifdef DEBUG
3446 fprintf(stderr, _("Main: open file\n"));
3447#endif
3448
Chris Allegretta3d459ad2003-01-22 01:09:40 +00003449 open_file(filename, 0, 1);
Chris Allegretta7662c862003-01-13 01:35:15 +00003450#ifdef ENABLE_MULTIBUFFER
3451 /* If we're using multibuffers and more than one file is specified
3452 on the command line, load them all and switch to the first one
3453 afterward */
3454 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3455 for (optind++; optind < argc; optind++) {
3456 add_open_file(1);
3457 new_file();
3458 filename = mallocstrcpy(filename, argv[optind]);
3459 open_file(filename, 0, 0);
3460 load_file(0);
3461 }
3462 open_nextfile_void();
3463 }
3464#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003465
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003466 titlebar(NULL);
3467
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003468 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003469 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003470
Chris Allegretta7662c862003-01-13 01:35:15 +00003471 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003472 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003473
Chris Allegretta7662c862003-01-13 01:35:15 +00003474 /* This variable should be initialized after the sigsetjmp(), so we
3475 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003476 modify_control_seq = 0;
3477
Robert Siemborski6967eec2000-07-08 14:23:32 +00003478 edit_refresh();
3479 reset_cursor();
3480
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003481 while (1) {
Chris Allegretta7662c862003-01-13 01:35:15 +00003482 int keyhandled = 0; /* Have we handled the keystroke yet? */
3483 int kbinput; /* Input from keyboard */
Chris Allegretta9239d742000-09-06 15:19:18 +00003484
Chris Allegrettad26ab912003-01-28 01:16:47 +00003485 if (ISSET(CONSTUPDATE))
3486 do_cursorpos(1);
3487
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003488#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003489 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003490#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003491
Chris Allegretta9239d742000-09-06 15:19:18 +00003492#ifndef _POSIX_VDISABLE
3493 /* We're going to have to do it the old way, i.e. on cygwin */
3494 raw();
3495#endif
3496
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003497 kbinput = wgetch(edit);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003498#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003499 fprintf(stderr, _("AHA! %c (%d)\n"), kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003500#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003501 if (kbinput == 27) { /* Grab Alt-key stuff first */
Chris Allegretta7662c862003-01-13 01:35:15 +00003502 kbinput = wgetch(edit);
3503 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003504 /* Alt-O, suddenly very important ;) */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003505 case 'O':
Chris Allegretta16e41682000-09-11 22:33:54 +00003506 kbinput = wgetch(edit);
Chris Allegretta7662c862003-01-13 01:35:15 +00003507 /* Shift or Ctrl + Arrows are Alt-O-[2,5,6]-[A,B,C,D] on some terms */
3508 if (kbinput == '2' || kbinput == '5' || kbinput == '6')
3509 kbinput = wgetch(edit);
Chris Allegretta316e4d92001-04-28 16:31:19 +00003510 if ((kbinput <= 'D' && kbinput >= 'A') ||
3511 (kbinput <= 'd' && kbinput >= 'a'))
Chris Allegretta908f7702003-01-15 11:18:58 +00003512 kbinput = abcd(kbinput);
Chris Allegretta201d9bf2001-01-14 03:17:53 +00003513 else if (kbinput <= 'z' && kbinput >= 'j')
3514 print_numlock_warning();
3515 else if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003516 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00003517#ifdef DEBUG
3518 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003519 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
3520 kbinput, kbinput);
3521 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003522 }
3523#endif
3524 break;
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003525 case 27:
3526 /* If we get Alt-Alt, the next keystroke should be the same as a
3527 control sequence */
3528 modify_control_seq = 1;
3529 keyhandled = 1;
3530 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003531 case '[':
Chris Allegretta7662c862003-01-13 01:35:15 +00003532 kbinput = wgetch(edit);
3533 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003534 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00003535 kbinput = wgetch(edit);
3536 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003537 kbinput = KEY_F(kbinput - 48);
3538 wgetch(edit);
3539 } else if (kbinput >= '7' && kbinput <= '9') {
3540 kbinput = KEY_F(kbinput - 49);
3541 wgetch(edit);
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003542 } else if (kbinput == '~')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003543 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00003544#ifdef DEBUG
3545 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003546 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
3547 kbinput, kbinput);
3548 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003549 }
3550#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003551 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003552 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00003553 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00003554 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003555 case '0':
3556 kbinput = KEY_F(9);
3557 wgetch(edit);
3558 break;
3559 case '1':
3560 kbinput = KEY_F(10);
3561 wgetch(edit);
3562 break;
3563 case '3':
3564 kbinput = KEY_F(11);
3565 wgetch(edit);
3566 break;
3567 case '4':
3568 kbinput = KEY_F(12);
3569 wgetch(edit);
3570 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003571 case '~':
Chris Allegretta7662c862003-01-13 01:35:15 +00003572 kbinput = NANO_INSERTFILE_KEY;
3573 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003574#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003575 default:
3576 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
3577 kbinput, kbinput);
3578 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003579#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003580 }
3581 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003582 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003583 kbinput = NANO_DELETE_KEY;
3584 wgetch(edit);
3585 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003586 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003587 kbinput = NANO_END_KEY;
3588 wgetch(edit);
3589 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003590 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00003591 kbinput = KEY_PPAGE;
3592 wgetch(edit);
3593 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003594 case 'V': /* Alt-[-V = Page Up in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003595 case 'I': /* Alt-[-I = Page Up - FreeBSD Console */
3596 kbinput = KEY_PPAGE;
3597 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003598 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00003599 kbinput = KEY_NPAGE;
3600 wgetch(edit);
3601 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003602 case 'U': /* Alt-[-U = Page Down in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003603 case 'G': /* Alt-[-G = Page Down - FreeBSD Console */
3604 kbinput = KEY_NPAGE;
3605 break;
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003606 case '7':
3607 kbinput = KEY_HOME;
3608 wgetch(edit);
3609 break;
3610 case '8':
3611 kbinput = KEY_END;
3612 wgetch(edit);
3613 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003614 case '9': /* Alt-[-9 = Delete in Hurd Console */
3615 kbinput = KEY_DC;
3616 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003617 case '@': /* Alt-[-@ = Insert in Hurd Console */
3618 case 'L': /* Alt-[-L = Insert - FreeBSD Console */
Chris Allegretta7662c862003-01-13 01:35:15 +00003619 kbinput = NANO_INSERTFILE_KEY;
3620 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003621 case '[': /* Alt-[-[-[A-E], F1-F5 in Linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00003622 kbinput = wgetch(edit);
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003623 if (kbinput >= 'A' && kbinput <= 'E')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003624 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00003625 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003626 case 'A':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003627 case 'B':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003628 case 'C':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003629 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003630 case 'a':
3631 case 'b':
3632 case 'c':
3633 case 'd':
Chris Allegretta908f7702003-01-15 11:18:58 +00003634 kbinput = abcd(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003635 break;
3636 case 'H':
3637 kbinput = KEY_HOME;
3638 break;
3639 case 'F':
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003640 case 'Y': /* End Key in Hurd Console */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003641 kbinput = KEY_END;
3642 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003643 default:
3644#ifdef DEBUG
3645 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
3646 kbinput, kbinput);
3647#endif
3648 break;
3649 }
3650 break;
Chris Allegretta355fbe52001-07-14 19:32:47 +00003651#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003652 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003653 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003654 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003655 keyhandled = 1;
3656 break;
3657 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003658 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003659 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003660 keyhandled = 1;
3661 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003662#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003663 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003664 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003665 for (s = main_list; s != NULL; s = s->next)
Chris Allegretta7662c862003-01-13 01:35:15 +00003666 if (kbinput == s->altval || (kbinput >= 'A' &&
3667 kbinput <= 'Z' && kbinput == s->altval - 32)) {
Chris Allegretta6232d662002-05-12 19:52:15 +00003668 if (ISSET(VIEW_MODE) && !s->viewok)
3669 print_view_warning();
3670 else
3671 s->func();
3672 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003673 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003674 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003675#ifndef NANO_SMALL
3676 /* And for toggle switches */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003677 for (t = toggles; t != NULL && !keyhandled; t = t->next)
Chris Allegretta7662c862003-01-13 01:35:15 +00003678 if (kbinput == t->val || (t->val >= 'a' &&
3679 t->val <= 'z' && kbinput == t->val - 32)) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003680 do_toggle(t);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003681 keyhandled = 1;
3682 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00003683 }
3684#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003685#ifdef DEBUG
3686 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
3687 kbinput);
3688#endif
3689 break;
3690 }
3691 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003692 /* Hack, make insert key do something useful, like insert file */
3693 else if (kbinput == KEY_IC)
3694 kbinput = NANO_INSERTFILE_KEY;
3695
Chris Allegrettacf287c82002-07-20 13:57:41 +00003696 /* If modify_control_seq is set, we received an Alt-Alt
3697 sequence before this, so we make this key a control sequence
3698 by subtracting 32, 64, or 96, depending on its value. */
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003699 if (!keyhandled && modify_control_seq) {
Chris Allegrettacf287c82002-07-20 13:57:41 +00003700 if (kbinput == ' ')
3701 kbinput -= 32;
3702 else if (kbinput >= 'A' && kbinput < 'a')
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003703 kbinput -= 64;
3704 else if (kbinput >= 'a' && kbinput <= 'z')
3705 kbinput -= 96;
3706
3707 modify_control_seq = 0;
3708 }
3709
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003710 /* Look through the main shortcut list to see if we've hit a
3711 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003712
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003713#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003714 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003715#else
3716 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3717#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003718 if (kbinput == s->val ||
3719 (s->misc1 && kbinput == s->misc1) ||
3720 (s->misc2 && kbinput == s->misc2)) {
3721 if (ISSET(VIEW_MODE) && !s->viewok)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003722 print_view_warning();
3723 else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003724 s->func();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003725 keyhandled = 1;
Chris Allegretta7662c862003-01-13 01:35:15 +00003726 /* Rarely, the value of s can change after s->func(),
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003727 leading to problems; get around this by breaking out
3728 explicitly once we successfully handle a shortcut */
3729 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003730 }
3731 }
Chris Allegrettae42df732002-10-15 00:27:55 +00003732
3733#ifdef _POSIX_VDISABLE
3734 /* Don't even think about changing this string */
3735 if (kbinput == 19)
3736 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003737 if (kbinput == 17)
3738 statusbar(_("XON ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003739#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003740 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3741 Control-S and Control-Q */
Chris Allegretta9239d742000-09-06 15:19:18 +00003742 if (kbinput == 17 || kbinput == 19)
3743 keyhandled = 1;
3744
Chris Allegretta7662c862003-01-13 01:35:15 +00003745 /* Catch ^Z by hand when triggered also
Chris Allegretta9caa1932002-02-15 20:08:05 +00003746 407 == ^Z in Linux console when keypad() is used? */
3747 if (kbinput == 26 || kbinput == 407) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003748 if (ISSET(SUSPEND))
3749 do_suspend(0);
3750 keyhandled = 1;
3751 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003752
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003753 /* Last gasp, stuff that's not in the main lists */
3754 if (!keyhandled)
3755 switch (kbinput) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003756#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003757 case KEY_MOUSE:
3758 do_mouse();
3759 break;
3760#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003761
Chris Allegrettad757e252003-01-15 19:33:27 +00003762 case -1: /* Stuff that we don't want to do squat */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003763 case 0: /* Erg */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003764 case 29: /* Ctrl-] */
Chris Allegretta7662c862003-01-13 01:35:15 +00003765 case 410: /* Must ignore this, it's sent when we resize */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003766#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003767 case 541: /* ???? */
3768 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00003769 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003770 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00003771 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003772#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003773
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003774 break;
3775 default:
3776#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003777 fprintf(stderr, _("I got %c (%d)!\n"), kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003778#endif
3779 /* We no longer stop unhandled sequences so that people with
3780 odd character sets can type... */
3781
Chris Allegretta7662c862003-01-13 01:35:15 +00003782 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003783 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003784 else
3785 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003786 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003787
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003788 reset_cursor();
3789 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003790 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003791 assert(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003792}