blob: e8de005c77ba9b72002acbd46fb4f72c7ffc3f6c [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
Jordi Mallach8ae57892002-01-04 17:57:40 +00005 * Copyright (C) 1999-2002 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
71 free_history(&search_history);
72 free_history(&replace_history);
73#endif
74
Chris Allegrettac08f50d2001-01-06 18:12:43 +000075 keypad(edit, TRUE);
76 keypad(bottomwin, TRUE);
77
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000078 if (!ISSET(NO_HELP)) {
79 mvwaddstr(bottomwin, 1, 0, hblank);
80 mvwaddstr(bottomwin, 2, 0, hblank);
Chris Allegretta4da1fc62000-06-21 03:00:43 +000081 } else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000082 mvwaddstr(bottomwin, 0, 0, hblank);
Chris Allegretta6b58acd2001-04-12 03:01:53 +000083
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000084 wrefresh(bottomwin);
85 endwin();
86
87 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +000088 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000089
Chris Allegretta6232d662002-05-12 19:52:15 +000090#ifdef DEBUG
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000091 thanks_for_all_the_fish();
Chris Allegretta6232d662002-05-12 19:52:15 +000092#endif
Chris Allegrettaf5de33a2002-02-27 04:14:16 +000093
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000094 exit(sigage);
95}
96
97/* Die (gracefully?) */
Chris Allegretta6df90f52002-07-19 01:08:59 +000098void die(const char *msg, ...)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000099{
100 va_list ap;
101
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000102 /* Restore the old term settings */
Chris Allegretta4da1fc62000-06-21 03:00:43 +0000103 tcsetattr(0, TCSANOW, &oldterm);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000104
105 clear();
106 refresh();
107 resetty();
108 endwin();
109
Chris Allegretta6df90f52002-07-19 01:08:59 +0000110 va_start(ap, msg);
111 vfprintf(stderr, msg, ap);
112 va_end(ap);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000113
Chris Allegretta32da4562002-01-02 15:12:21 +0000114 /* save the currently loaded file if it's been modified */
115 if (ISSET(MODIFIED))
116 die_save_file(filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000117
Chris Allegretta355fbe52001-07-14 19:32:47 +0000118#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +0000119 /* then save all of the other modified loaded files, if any */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000120 if (open_files != NULL) {
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000121 openfilestruct *tmp;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000122
123 tmp = open_files;
124
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000125 while (open_files->prev != NULL)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000126 open_files = open_files->prev;
127
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000128 while (open_files->next != NULL) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000129
130 /* if we already saved the file above (i. e. if it was the
131 currently loaded file), don't save it again */
132 if (tmp != open_files) {
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000133 /* make sure open_files->fileage and fileage, and
134 open_files->filebot and filebot, are in sync; they
135 might not be if lines have been cut from the top or
136 bottom of the file */
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000137 fileage = open_files->fileage;
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000138 filebot = open_files->filebot;
Chris Allegretta32da4562002-01-02 15:12:21 +0000139 /* save the file if it's been modified */
Chris Allegretta4dc03d52002-05-11 03:04:44 +0000140 if (open_files->file_flags & MODIFIED)
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000141 die_save_file(open_files->filename);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000142 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000143 open_files = open_files->next;
144 }
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000145 }
146#endif
147
Chris Allegretta6df90f52002-07-19 01:08:59 +0000148 exit(1); /* We have a problem: exit w/ errorlevel(1) */
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000149}
150
Chris Allegretta6df90f52002-07-19 01:08:59 +0000151void die_save_file(const char *die_filename)
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000152{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000153 char *ret;
Chris Allegretta48b06702002-02-22 04:30:50 +0000154 int i = -1;
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000155
Chris Allegretta6df90f52002-07-19 01:08:59 +0000156 /* If we can't save, we have REAL bad problems, but we might as well
157 TRY. */
158 if (die_filename[0] == '\0')
159 ret = get_next_filename("nano.save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000160 else {
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000161 char *buf = charalloc(strlen(die_filename) + 6);
Chris Allegretta6df90f52002-07-19 01:08:59 +0000162
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000163 strcpy(buf, die_filename);
164 strcat(buf, ".save");
Chris Allegretta48b06702002-02-22 04:30:50 +0000165 ret = get_next_filename(buf);
Chris Allegretta7162e3d2002-04-06 05:02:14 +0000166 free(buf);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000167 }
Chris Allegretta6df90f52002-07-19 01:08:59 +0000168 if (ret[0] != '\0')
169 i = write_file(ret, 1, 0, 0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +0000170
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000171 if (i != -1)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000172 fprintf(stderr, _("\nBuffer written to %s\n"), ret);
Chris Allegretta3dbb2782000-12-02 04:36:50 +0000173 else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000174 fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret);
Chris Allegretta48b06702002-02-22 04:30:50 +0000175
176 free(ret);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000177}
178
Chris Allegrettae61e8302001-01-14 05:18:27 +0000179/* Die with an error message that the screen was too small if, well, the
Chris Allegretta6df90f52002-07-19 01:08:59 +0000180 * screen is too small. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000181void die_too_small(void)
Chris Allegrettae61e8302001-01-14 05:18:27 +0000182{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000183 die(_("Window size is too small for nano...\n"));
Chris Allegrettae61e8302001-01-14 05:18:27 +0000184}
185
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000186void print_view_warning(void)
187{
188 statusbar(_("Key illegal in VIEW mode"));
189}
190
Chris Allegretta56214c62001-09-27 02:46:53 +0000191/* Initialize global variables - no better way for now. If
Chris Allegretta6df90f52002-07-19 01:08:59 +0000192 * save_cutbuffer is nonzero, don't set cutbuffer to NULL. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000193void global_init(int save_cutbuffer)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000194{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000195 current_x = 0;
196 current_y = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000197
198 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
199 die_too_small();
200
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000201 fileage = NULL;
Chris Allegretta56214c62001-09-27 02:46:53 +0000202 if (!save_cutbuffer)
203 cutbuffer = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000204 current = NULL;
205 edittop = NULL;
206 editbot = NULL;
207 totlines = 0;
Chris Allegretta56214c62001-09-27 02:46:53 +0000208 totsize = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000209 placewewant = 0;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000210
Chris Allegretta6fe61492001-05-21 12:56:25 +0000211#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000212 fill = wrap_at;
Chris Allegrettadffa2072002-07-24 01:02:26 +0000213 if (fill <= 0)
Chris Allegretta6df90f52002-07-19 01:08:59 +0000214 fill += COLS;
Chris Allegrettae61e8302001-01-14 05:18:27 +0000215 if (fill < MIN_FILL_LENGTH)
216 die_too_small();
Chris Allegretta6fe61492001-05-21 12:56:25 +0000217#endif
Chris Allegrettae61e8302001-01-14 05:18:27 +0000218
Chris Allegretta88b09152001-05-17 11:35:43 +0000219 hblank = charalloc(COLS + 1);
Chris Allegretta0a06e072001-01-23 02:35:04 +0000220 memset(hblank, ' ', COLS);
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +0000221 hblank[COLS] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000222}
223
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000224void window_init(void)
225{
226 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
227 die_too_small();
228
229 /* Set up the main text window */
230 edit = newwin(editwinrows, COLS, 2, 0);
231
232 /* And the other windows */
233 topwin = newwin(2, COLS, 0, 0);
234 bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0);
235
236#ifdef PDCURSES
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000237 /* Oops, I guess we need this again. Moved here so the keypad still
238 works after a Meta-X, for example */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000239 keypad(edit, TRUE);
240 keypad(bottomwin, TRUE);
241#endif
242}
243
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000244#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000245void mouse_init(void)
246{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000247 if (ISSET(USE_MOUSE)) {
248 keypad_on(edit, 1);
249 keypad_on(bottomwin, 1);
250
251 mousemask(BUTTON1_RELEASED, NULL);
252 mouseinterval(50);
253 } else
254 mousemask(0, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000255}
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000256#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000257
258#ifndef DISABLE_HELP
259/* This function allocates help_text, and stores the help string in it.
260 * help_text should be NULL initially. */
261void help_init(void)
262{
263 size_t allocsize = 1; /* space needed for help_text */
264 char *ptr = NULL;
265#ifndef NANO_SMALL
266 const toggle *t;
267#endif
268 const shortcut *s;
269
270 /* First set up the initial help text for the current function */
271 if (currshortcut == whereis_list || currshortcut == replace_list
272 || currshortcut == replace_list_2)
273 ptr = _("Search Command Help Text\n\n "
274 "Enter the words or characters you would like to search "
275 "for, then hit enter. If there is a match for the text you "
276 "entered, the screen will be updated to the location of the "
277 "nearest match for the search string.\n\n "
278 "If using Pico Mode via the -p or --pico flags, the "
279 "Meta-P toggle, or a nanorc file, the previous search "
280 "string will be shown in brackets after the Search: prompt. "
281 "Hitting Enter without entering any text will perform the "
282 "previous search. Otherwise, the previous string will be "
283 "placed before the cursor, and can be edited or deleted "
284 "before hitting enter.\n\n The following function keys are "
285 "available in Search mode:\n\n");
286 else if (currshortcut == goto_list)
287 ptr = _("Go To Line Help Text\n\n "
288 "Enter the line number that you wish to go to and hit "
289 "Enter. If there are fewer lines of text than the "
290 "number you entered, you will be brought to the last line "
291 "of the file.\n\n The following function keys are "
292 "available in Go To Line mode:\n\n");
293 else if (currshortcut == insertfile_list)
294 ptr = _("Insert File Help Text\n\n "
295 "Type in the name of a file to be inserted into the current "
296 "file buffer at the current cursor location.\n\n "
297 "If you have compiled nano with multiple file buffer "
298 "support, and enable multiple buffers with the -F "
299 "or --multibuffer command line flags, the Meta-F toggle, or "
300 "a nanorc file, inserting a file will cause it to be "
301 "loaded into a separate buffer (use Meta-< and > to switch "
302 "between file buffers).\n\n If you need another blank "
303 "buffer, do not enter any filename, or type in a "
304 "nonexistent filename at the prompt and press "
305 "Enter.\n\n The following function keys are "
306 "available in Insert File mode:\n\n");
307 else if (currshortcut == writefile_list)
308 ptr = _("Write File Help Text\n\n "
309 "Type the name that you wish to save the current file "
310 "as and hit Enter to save the file.\n\n If you have "
311 "selected text with Ctrl-^, you will be prompted to "
312 "save only the selected portion to a separate file. To "
313 "reduce the chance of overwriting the current file with "
314 "just a portion of it, the current filename is not the "
315 "default in this mode.\n\n The following function keys "
316 "are available in Write File mode:\n\n");
317#ifndef DISABLE_BROWSER
318 else if (currshortcut == browser_list)
319 ptr = _("File Browser Help Text\n\n "
320 "The file browser is used to visually browse the "
321 "directory structure to select a file for reading "
322 "or writing. You may use the arrow keys or Page Up/"
323 "Down to browse through the files, and S or Enter to "
324 "choose the selected file or enter the selected "
325 "directory. To move up one level, select the directory "
326 "called \"..\" at the top of the file list.\n\n The "
327 "following function keys are available in the file "
328 "browser:\n\n");
329 else if (currshortcut == gotodir_list)
330 ptr = _("Browser Go To Directory Help Text\n\n "
331 "Enter the name of the directory you would like to "
332 "browse to.\n\n If tab completion has not been disabled, "
333 "you can use the TAB key to (attempt to) automatically "
334 "complete the directory name.\n\n The following function "
335 "keys are available in Browser Go To Directory mode:\n\n");
336#endif
337 else if (currshortcut == spell_list)
338 ptr = _("Spell Check Help Text\n\n "
339 "The spell checker checks the spelling of all text "
340 "in the current file. When an unknown word is "
341 "encountered, it is highlighted and a replacement can "
342 "be edited. It will then prompt to replace every "
343 "instance of the given misspelled word in the "
344 "current file.\n\n The following other functions are "
345 "available in Spell Check mode:\n\n");
346#ifndef NANO_SMALL
347 else if (currshortcut == extcmd_list)
348 ptr = _("External Command Help Text\n\n "
349 "This menu allows you to insert the output of a command "
350 "run by the shell into the current buffer (or a new "
351 "buffer in multibuffer mode).\n\n The following keys are "
352 "available in this mode:\n\n");
353#endif
354 else /* Default to the main help list */
355 ptr = _(" nano help text\n\n "
356 "The nano editor is designed to emulate the functionality and "
357 "ease-of-use of the UW Pico text editor. There are four main "
358 "sections of the editor: The top line shows the program "
359 "version, the current filename being edited, and whether "
360 "or not the file has been modified. Next is the main editor "
361 "window showing the file being edited. The status line is "
362 "the third line from the bottom and shows important messages. "
363 "The bottom two lines show the most commonly used shortcuts "
364 "in the editor.\n\n "
365 "The notation for shortcuts is as follows: Control-key "
366 "sequences are notated with a caret (^) symbol and are entered "
367 "with the Control (Ctrl) key. Escape-key sequences are notated "
368 "with the Meta (M) symbol and can be entered using either the "
369 "Esc, Alt or Meta key depending on your keyboard setup. The "
370 "following keystrokes are available in the main editor window. "
371 "Alternative keys are shown in parentheses:\n\n");
372
373 allocsize += strlen(ptr);
374
375 /* The space needed for the shortcut lists, at most COLS characters,
376 * plus '\n'. */
377 allocsize += (COLS + 1) * length_of_list(currshortcut);
378
379#ifndef NANO_SMALL
380 /* If we're on the main list, we also count the toggle help text.
381 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
382 * COLS - 24 characters, plus '\n'.*/
383 if (currshortcut == main_list)
384 for (t = toggles; t != NULL; t = t->next)
385 allocsize += COLS - 17;
386#endif /* !NANO_SMALL */
387
388 /* help_text has been freed and set to NULL unless the user resized
389 * while in the help screen. */
390 free(help_text);
391
392 /* Allocate space for the help text */
393 help_text = charalloc(allocsize);
394
395 /* Now add the text we want */
396 strcpy(help_text, ptr);
397 ptr = help_text + strlen(help_text);
398
399 /* Now add our shortcut info */
400 for (s = currshortcut; s != NULL; s = s->next) {
401 /* true if the character in s->altval is shown in first column */
402 int meta_shortcut = 0;
403
404 if (s->val > 0 && s->val < 32)
405 ptr += sprintf(ptr, "^%c", s->val + 64);
406#ifndef NANO_SMALL
407 else if (s->val == NANO_CONTROL_SPACE)
408 ptr += sprintf(ptr, "^%.6s", _("Space"));
409 else if (s->altval == NANO_ALT_SPACE) {
410 meta_shortcut = 1;
411 ptr += sprintf(ptr, "M-%.5s", _("Space"));
412 }
413#endif
414 else if (s->altval > 0) {
415 meta_shortcut = 1;
416 ptr += sprintf(ptr, "M-%c", s->altval -
417 (('A' <= s->altval && s->altval <= 'Z') ||
418 'a' <= s->altval ? 32 : 0));
419 }
420 /* Hack */
421 else if (s->val >= 'a') {
422 meta_shortcut = 1;
423 ptr += sprintf(ptr, "M-%c", s->val - 32);
424 }
425
426 *(ptr++) = '\t';
427
428 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
429 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
430
431 *(ptr++) = '\t';
432
433 if (!meta_shortcut && s->altval > 0)
434 ptr += sprintf(ptr, "(M-%c)", s->altval -
435 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
436 ? 32 : 0));
437
438 *(ptr++) = '\t';
439
440 assert(s->help != NULL);
441 ptr += sprintf(ptr, "%.*s\n", COLS - 24, s->help);
442 }
443
444#ifndef NANO_SMALL
445 /* And the toggles... */
446 if (currshortcut == main_list)
447 for (t = toggles; t != NULL; t = t->next) {
448 ptr += sprintf(ptr, "M-%c\t\t\t", t->val - 32);
449 assert(t->desc != NULL);
450 ptr += sprintf(ptr, _("%.*s enable/disable\n"), COLS - 24, t->desc);
451 }
452#endif /* !NANO_SMALL */
453
454 /* If all went well, we didn't overwrite the allocated space for
455 help_text. */
456 assert(strlen(help_text) < allocsize);
457}
458#endif
459
460/* Create a new filestruct node. Note that we specifically do not set
461 * prevnode->next equal to the new line. */
462filestruct *make_new_node(filestruct *prevnode)
463{
464 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
465
466 newnode->data = NULL;
467 newnode->prev = prevnode;
468 newnode->next = NULL;
469 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
470
471 return newnode;
472}
473
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000474/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000475filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000476{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000477 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000478
Chris Allegretta6df90f52002-07-19 01:08:59 +0000479 assert(src != NULL);
480
Chris Allegretta88b09152001-05-17 11:35:43 +0000481 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000482 dst->next = src->next;
483 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000484 strcpy(dst->data, src->data);
485 dst->lineno = src->lineno;
486
487 return dst;
488}
489
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000490/* Splice a node into an existing filestruct. */
491void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
492{
493 if (newnode != NULL) {
494 newnode->next = end;
495 newnode->prev = begin;
496 }
497 if (begin != NULL)
498 begin->next = newnode;
499 if (end != NULL)
500 end->prev = newnode;
501}
502
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000503/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000504void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000505{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000506 assert(fileptr != NULL);
507
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000508 if (fileptr->prev != NULL)
509 fileptr->prev->next = fileptr->next;
510
511 if (fileptr->next != NULL)
512 fileptr->next->prev = fileptr->prev;
513}
514
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000515/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000516void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000517{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000518 if (fileptr != NULL) {
519 if (fileptr->data != NULL)
520 free(fileptr->data);
521 free(fileptr);
522 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000523}
524
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000525/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000526filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000527{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000528 filestruct *head; /* copy of src, top of the copied list */
529 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000530
Chris Allegretta6df90f52002-07-19 01:08:59 +0000531 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000532
Chris Allegretta6df90f52002-07-19 01:08:59 +0000533 prev = copy_node(src);
534 prev->prev = NULL;
535 head = prev;
536 src = src->next;
537 while (src != NULL) {
538 prev->next = copy_node(src);
539 prev->next->prev = prev;
540 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000541
Chris Allegretta6df90f52002-07-19 01:08:59 +0000542 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543 }
544
Chris Allegretta6df90f52002-07-19 01:08:59 +0000545 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000546 return head;
547}
548
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000549/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000550void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000551{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000552 if (src != NULL) {
553 while (src->next != NULL) {
554 src = src->next;
555 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000556#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000557 fprintf(stderr, _("delete_node(): free'd a node, YAY!\n"));
558#endif
559 }
560 delete_node(src);
561#ifdef DEBUG
562 fprintf(stderr, _("delete_node(): free'd last node.\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000563#endif
564 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000565}
566
Chris Allegretta6df90f52002-07-19 01:08:59 +0000567void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000568{
569 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000570 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571
Chris Allegretta6df90f52002-07-19 01:08:59 +0000572 assert(fileage == NULL || fileage != fileage->next);
573 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000574 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000575}
576
Chris Allegretta6df90f52002-07-19 01:08:59 +0000577void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000578{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000579 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000580 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000581 else {
582 int lineno = fileptr->prev->lineno;
583
584 assert(fileptr != fileptr->next);
585 for (; fileptr != NULL; fileptr = fileptr->next)
586 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000587 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000588}
589
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000590/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000591 * strings to translate and takes out the parts that shouldn't be
592 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000593void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000594 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000595{
596 printf(" %s\t", shortflag);
597 if (strlen(shortflag) < 8)
598 printf("\t");
599
600#ifdef HAVE_GETOPT_LONG
601 printf("%s\t", longflag);
602 if (strlen(longflag) < 8)
603 printf("\t\t");
604 else if (strlen(longflag) < 16)
605 printf("\t");
606#endif
607
608 printf("%s\n", desc);
609}
610
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000611void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000612{
613#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000614 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
615 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000616#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000617 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
618 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000619#endif /* HAVE_GETOPT_LONG */
620
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000621 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000622 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000623#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000624 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000625 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000626#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000627#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000628 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000629#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000630#ifdef ENABLE_NANORC
631 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
632#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000633 print1opt("-K", "--keypad", _("Use alternate keypad routines"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000634#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000635 print1opt("-M", "--mac", _("Write file in Mac format"));
636 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000637#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000638#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000639 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000640#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000641#ifdef HAVE_REGEX_H
642 print1opt("-R", "--regexp", _("Do regular expression searches"));
643#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000644#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000645 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000646#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000647 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000648 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000649#ifdef ENABLE_COLOR
650 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
651#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000652 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000653#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000654 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
655 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000656#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000657 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000658#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000659 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000660#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000661#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000662 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000663#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000664 print1opt("-p", "--pico", _("Emulate Pico as closely as possible"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000665#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000666 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000667#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000668#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000669 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000670#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000671 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
672 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000673#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000674 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000675#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000676 print1opt("-x", "--nohelp", _("Don't show help window"));
677 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000678
679 /* this is a special case */
680 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000681
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000682 exit(0);
683}
684
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000685void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000686{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000687 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000688 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000689 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000690 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000691 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000692
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000693#ifdef DEBUG
694 printf(" --enable-debug");
695#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000696#ifdef NANO_EXTRA
697 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000698#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000699#ifdef NANO_SMALL
700 printf(" --enable-tiny");
701#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000702#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000703 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000704#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000705#ifdef DISABLE_HELP
706 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000707#endif
708#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000709 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000710#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000711#if defined(DISABLE_MOUSE) || !defined(NCURSES_MOUSE_VERSION)
Chris Allegretta84de5522001-04-12 14:51:48 +0000712 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000713#endif
Chris Allegretta2a15c582002-10-25 01:51:13 +0000714#ifndef ENABLE_NLS
715 printf(" --disable-nls");
716#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000717#ifdef DISABLE_OPERATINGDIR
718 printf(" --disable-operatingdir");
719#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000720#ifdef DISABLE_SPELLER
721 printf(" --disable-speller");
722#endif
723#ifdef DISABLE_TABCOMP
724 printf(" --disable-tabcomp");
725#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000726#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000727#ifdef DISABLE_WRAPPING
728 printf(" --disable-wrapping");
729#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000730#ifdef DISABLE_ROOTWRAP
731 printf(" --disable-wrapping-as-root");
732#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000733#ifdef ENABLE_COLOR
734 printf(" --enable-color");
735#endif
736#ifdef ENABLE_MULTIBUFFER
737 printf(" --enable-multibuffer");
738#endif
739#ifdef ENABLE_NANORC
740 printf(" --enable-nanorc");
741#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000742#ifdef USE_SLANG
743 printf(" --with-slang");
744#endif
745 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000746}
747
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000748/* Stuff we do when we abort from programs and want to clean up the
749 * screen. This doesn't do much right now. */
750void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000751{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000752 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000753}
754
755int no_help(void)
756{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000757 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000758}
759
Chris Allegrettad865da12002-07-29 23:46:38 +0000760#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000761void nano_disabled_msg(void)
762{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000763 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000764}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000765#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000766
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000767#ifndef NANO_SMALL
768static int pid; /* This is the PID of the newly forked process
769 * below. It must be global since the signal
770 * handler needs it. */
771
772RETSIGTYPE cancel_fork(int signal)
773{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000774 if (kill(pid, SIGKILL) == -1)
775 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000776}
777
778int open_pipe(const char *command)
779{
780 int fd[2];
781 FILE *f;
782 struct sigaction oldaction, newaction;
783 /* original and temporary handlers for SIGINT */
784#ifdef _POSIX_VDISABLE
785 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000786#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000787 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000788 /* cancel_sigs == 1 means that sigaction() failed without changing
789 * the signal handlers. cancel_sigs == 2 means the signal handler
790 * was changed, but the tcsetattr didn't succeed.
791 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000792 * I use this variable since it is important to put things back when
793 * we finish, even if we get errors. */
794
795 /* Make our pipes. */
796
797 if (pipe(fd) == -1) {
798 statusbar(_("Could not pipe"));
799 return 1;
800 }
801
802 /* Fork a child. */
803
804 if ((pid = fork()) == 0) {
805 close(fd[0]);
806 dup2(fd[1], fileno(stdout));
807 dup2(fd[1], fileno(stderr));
808 /* If execl() returns at all, there was an error. */
809
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000810 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000811 exit(0);
812 }
813
814 /* Else continue as parent. */
815
816 close(fd[1]);
817
818 if (pid == -1) {
819 close(fd[0]);
820 statusbar(_("Could not fork"));
821 return 1;
822 }
823
824 /* Before we start reading the forked command's output, we set
825 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000826 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000827 cancel_sigs = 1;
828 nperror("sigaction");
829 } else {
830 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000831 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000832 cancel_sigs = 1;
833 nperror("sigaction");
834 }
835 }
836 /* Note that now oldaction is the previous SIGINT signal handler,
837 * to be restored later. */
838
839 /* See if the platform supports disabling individual control
840 * characters. */
841#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000842 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000843 cancel_sigs = 2;
844 nperror("tcgetattr");
845 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000846 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000847 newterm = term;
848 /* Grab oldterm's VINTR key :-) */
849 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
850 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
851 cancel_sigs = 2;
852 nperror("tcsetattr");
853 }
854 }
855#endif /* _POSIX_VDISABLE */
856
857 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000858 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000859 nperror("fdopen");
860
861 read_file(f, "stdin", 0);
862 /* if multibuffer mode is on, we could be here in view mode; if so,
863 don't set the modification flag */
864 if (!ISSET(VIEW_MODE))
865 set_modified();
866
867 if (wait(NULL) == -1)
868 nperror("wait");
869
870#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000871 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000872 nperror("tcsetattr");
873#endif /* _POSIX_VDISABLE */
874
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000875 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000876 nperror("sigaction");
877
878 return 0;
879}
880#endif /* NANO_SMALL */
881
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000882#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000883void do_mouse(void)
884{
885 MEVENT mevent;
886 int currslen;
887 const shortcut *s = currshortcut;
888
889 if (getmouse(&mevent) == ERR)
890 return;
891
892 /* If mouse not in edit or bottom window, return */
893 if (wenclose(edit, mevent.y, mevent.x)) {
894
895 /* Don't let people screw with the marker when they're in a
896 * subfunction. */
897 if (currshortcut != main_list)
898 return;
899
900 /* Subtract out size of topwin. Perhaps we need a constant
901 * somewhere? */
902 mevent.y -= 2;
903
904 /* Selecting where the cursor is sets the mark. Selecting
905 * beyond the line length with the cursor at the end of the line
906 * sets the mark as well. */
907 if ((mevent.y == current_y) &&
908 ((mevent.x == current_x) || (current_x == strlen(current->data)
909 && (mevent.x >
910 strlen(current->data))))) {
911 if (ISSET(VIEW_MODE)) {
912 print_view_warning();
913 return;
914 }
915 do_mark();
916 } else if (mevent.y > current_y) {
917 while (mevent.y > current_y) {
918 if (current->next != NULL)
919 current = current->next;
920 else
921 break;
922 current_y++;
923 }
924 } else if (mevent.y < current_y) {
925 while (mevent.y < current_y) {
926 if (current->prev != NULL)
927 current = current->prev;
928 else
929 break;
930 current_y--;
931 }
932 }
933 current_x = actual_x(current, mevent.x);
934 placewewant = current_x;
935 update_cursor();
936 edit_refresh();
937 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
938 int i, k;
939
940 if (currshortcut == main_list)
941 currslen = MAIN_VISIBLE;
942 else
943 currslen = length_of_list(currshortcut);
944
945 if (currslen < 2)
946 k = COLS / 6;
947 else
948 k = COLS / ((currslen + (currslen %2)) / 2);
949
950 /* Determine what shortcut list was clicked */
951 mevent.y -= (editwinrows + 3);
952
953 if (mevent.y < 0) /* They clicked on the statusbar */
954 return;
955
956 /* Don't select stuff beyond list length */
957 if (mevent.x / k >= currslen)
958 return;
959
960 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
961 s = s->next;
962
963 /* And ungetch that value */
964 ungetch(s->val);
965
966 /* And if it's an alt-key sequence, we should probably send alt
967 too ;-) */
968 if (s->val >= 'a' && s->val <= 'z')
969 ungetch(27);
970 }
971}
972#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000973
Chris Allegretta6df90f52002-07-19 01:08:59 +0000974/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000975void do_char(char ch)
976{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000977 size_t current_len = strlen(current->data);
978#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
979 int refresh = 0;
980 /* Do we have to run edit_refresh(), or can we get away with
981 * update_line()? */
982#endif
983
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000984 /* magic-line: when a character is inserted on the current magic line,
985 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000986 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000987 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000988 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000989 }
990
Chris Allegretta6df90f52002-07-19 01:08:59 +0000991 /* more dangerousness fun =) */
992 current->data = nrealloc(current->data, current_len + 2);
993 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000994 memmove(&current->data[current_x + 1],
995 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +0000996 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000997 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +0000998 totsize++;
999 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001000
Chris Allegretta6df90f52002-07-19 01:08:59 +00001001#ifndef NANO_SMALL
1002 /* note that current_x has not yet been incremented */
1003 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001004 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001005#endif
1006
Chris Allegretta6df90f52002-07-19 01:08:59 +00001007 do_right();
1008
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001009#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001010 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001011 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001012#endif
1013
Chris Allegretta6df90f52002-07-19 01:08:59 +00001014#ifdef ENABLE_COLOR
1015 refresh = 1;
1016#endif
1017
1018#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1019 if (refresh)
1020 edit_refresh();
1021#endif
1022
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001023 check_statblank();
1024 UNSET(KEEP_CUTBUFFER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001025}
1026
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001027int do_backspace(void)
1028{
1029 int refresh = 0;
1030 if (current_x > 0) {
1031 assert(current_x <= strlen(current->data));
1032 /* Let's get dangerous */
1033 memmove(&current->data[current_x - 1], &current->data[current_x],
1034 strlen(current->data) - current_x + 1);
1035#ifdef DEBUG
1036 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
1037#endif
1038 align(&current->data);
1039#ifndef NANO_SMALL
1040 if (current_x <= mark_beginx && mark_beginbuf == current)
1041 mark_beginx--;
1042#endif
1043 do_left();
1044#ifdef ENABLE_COLOR
1045 refresh = 1;
1046#endif
1047 } else {
1048 filestruct *previous;
1049 const filestruct *tmp;
1050
1051 if (current == fileage)
1052 return 0; /* Can't delete past top of file */
1053
1054 previous = current->prev;
1055 current_x = strlen(previous->data);
1056 placewewant = strlenpt(previous->data);
1057#ifndef NANO_SMALL
1058 if (current == mark_beginbuf) {
1059 mark_beginx += current_x;
1060 mark_beginbuf = previous;
1061 }
1062#endif
1063 previous->data = nrealloc(previous->data,
1064 current_x + strlen(current->data) + 1);
1065 strcpy(previous->data + current_x, current->data);
1066
1067 unlink_node(current);
1068 delete_node(current);
1069 tmp = current;
1070 current = (previous->next ? previous->next : previous);
1071 renumber(current);
1072 /* We had to renumber before doing update_line. */
1073 if (tmp == edittop)
1074 page_up();
1075
1076 /* Ooops, sanity check */
1077 if (tmp == filebot) {
1078 filebot = current;
1079 editbot = current;
1080
1081 /* Recreate the magic line if we're deleting it AND if the
1082 line we're on now is NOT blank. if it is blank we
1083 can just use IT for the magic line. This is how Pico
1084 appears to do it, in any case. */
1085 if (current->data[0] != '\0') {
1086 new_magicline();
1087 fix_editbot();
1088 }
1089 }
1090
1091 current = previous;
1092 if (current_y > 0)
1093 current_y--;
1094 totlines--;
1095#ifdef DEBUG
1096 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1097#endif
1098 UNSET(KEEP_CUTBUFFER);
1099 refresh = 1;
1100 }
1101
1102 totsize--;
1103 set_modified();
1104 if (refresh)
1105 edit_refresh();
1106 return 1;
1107}
1108
1109int do_delete(void)
1110{
1111 int refresh = 0;
1112
1113 /* blbf -> blank line before filebot (see below) */
1114 int blbf = 0;
1115
1116 if (current->next == filebot && current->data[0] == '\0')
1117 blbf = 1;
1118
1119 placewewant = xplustabs();
1120
1121 if (current_x != strlen(current->data)) {
1122 /* Let's get dangerous */
1123 memmove(&current->data[current_x], &current->data[current_x + 1],
1124 strlen(current->data) - current_x);
1125
1126 align(&current->data);
1127#ifdef ENABLE_COLOR
1128 refresh = 1;
1129#endif
1130 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1131 /* We can delete the line before filebot only if it is blank: it
1132 becomes the new magic line then. */
1133
1134 filestruct *foo;
1135
1136 current->data = nrealloc(current->data,
1137 strlen(current->data) +
1138 strlen(current->next->data) + 1);
1139 strcat(current->data, current->next->data);
1140
1141 foo = current->next;
1142 if (filebot == foo) {
1143 filebot = current;
1144 editbot = current;
1145 }
1146
1147 unlink_node(foo);
1148 delete_node(foo);
1149 renumber(current);
1150 totlines--;
1151 refresh = 1;
1152 } else
1153 return 0;
1154
1155 totsize--;
1156 set_modified();
1157 UNSET(KEEP_CUTBUFFER);
1158 update_line(current, current_x);
1159 if (refresh)
1160 edit_refresh();
1161 return 1;
1162}
1163
1164int do_tab(void)
1165{
1166 do_char('\t');
1167 return 1;
1168}
1169
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001170/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001171int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001172{
Chris Allegrettae3167732001-03-18 16:59:34 +00001173 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001174 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176 newnode = make_new_node(current);
1177 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001178 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001179
Chris Allegrettaff989832001-09-17 13:48:00 +00001180#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001181 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001182 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001183 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001184 const char *spc = current->data;
1185
1186 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001187 extra++;
1188 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001189 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001190 /* If current_x < extra, then we are breaking the line in the
1191 * indentation. Autoindenting should add only current_x
1192 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001193 if (current_x < extra)
1194 extra = current_x;
1195 else
1196 current_x = extra;
1197 totsize += extra;
1198
1199 newnode->data = charalloc(strlen(tmp) + extra + 1);
1200 strncpy(newnode->data, current->data, extra);
1201 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001202 } else
1203#endif
1204 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001205 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001206 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001207 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001208 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001209 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001210
Chris Allegretta6df90f52002-07-19 01:08:59 +00001211 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001212 filebot = newnode;
1213 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001214 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001215 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001216
1217 totsize++;
1218 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001219 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001220 align(&current->data);
1221
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001222 /* The logic here is as follows:
1223 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001224 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001225 * -> otherwise, we want simply to redraw the screen and update
1226 * where we think the cursor is.
1227 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001228 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001229#ifndef NANO_SMALL
1230 if (ISSET(SMOOTHSCROLL))
1231 edit_update(current, NONE);
1232 else
1233#endif
1234 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001235 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001236 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001237 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001238 edit_refresh();
1239 update_cursor();
1240 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001241
1242 totlines++;
1243 set_modified();
1244
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001245 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001246 return 1;
1247}
1248
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001249#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001250int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001251{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001252 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001253
Chris Allegretta6df90f52002-07-19 01:08:59 +00001254 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001255
Chris Allegretta6df90f52002-07-19 01:08:59 +00001256 /* Skip letters in this word first. */
1257 while (current->data[current_x] != '\0' &&
1258 isalnum((int)current->data[current_x]))
1259 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001260
Chris Allegretta6df90f52002-07-19 01:08:59 +00001261 for (; current != NULL; current = current->next) {
1262 while (current->data[current_x] != '\0' &&
1263 !isalnum((int)current->data[current_x]))
1264 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001265
Chris Allegretta6df90f52002-07-19 01:08:59 +00001266 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001267 break;
1268
Chris Allegretta6df90f52002-07-19 01:08:59 +00001269 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001270 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001271 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001272 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001273
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001274 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001275
Chris Allegrettad865da12002-07-29 23:46:38 +00001276 if (current->lineno >= editbot->lineno) {
1277 /* If we're on the last line, don't center the screen. */
1278 if (current->lineno == filebot->lineno)
1279 edit_refresh();
1280 else
1281 edit_update(current, CENTER);
1282 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001283 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001284 /* If we've jumped lines, refresh the old line. We can't just
1285 use current->prev here, because we may have skipped over some
1286 blank lines, in which case the previous line is the wrong
1287 one. */
1288 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001289 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001290 /* If the mark was set, then the lines between old and
1291 current have to be updated too. */
1292 if (ISSET(MARK_ISSET)) {
1293 while (old->next != current) {
1294 old = old->next;
1295 update_line(old, 0);
1296 }
1297 }
1298 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001299 update_line(current, current_x);
1300 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001301 return 0;
1302}
1303
Chris Allegretta6df90f52002-07-19 01:08:59 +00001304/* The same thing for backwards. */
1305int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001306{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001307 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001308
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001309 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001310
Chris Allegretta6df90f52002-07-19 01:08:59 +00001311 /* Skip letters in this word first. */
1312 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1313 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001314
Chris Allegretta6df90f52002-07-19 01:08:59 +00001315 for (; current != NULL; current = current->prev) {
1316 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1317 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001318
Chris Allegretta6df90f52002-07-19 01:08:59 +00001319 if (current_x >= 0)
1320 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001321
Chris Allegretta6df90f52002-07-19 01:08:59 +00001322 if (current->prev != NULL)
1323 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001324 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001325
Chris Allegretta6df90f52002-07-19 01:08:59 +00001326 if (current != NULL) {
1327 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1328 current_x--;
1329 } else {
1330 current = fileage;
1331 current_x = 0;
1332 }
1333
Chris Allegretta76e291b2001-10-14 19:05:10 +00001334 placewewant = xplustabs();
1335
Chris Allegrettad865da12002-07-29 23:46:38 +00001336 if (current->lineno <= edittop->lineno) {
1337 /* If we're on the first line, don't center the screen. */
1338 if (current->lineno == fileage->lineno)
1339 edit_refresh();
1340 else
1341 edit_update(current, CENTER);
1342 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001343 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001344 /* If we've jumped lines, refresh the old line. We can't just
1345 use current->prev here, because we may have skipped over some
1346 blank lines, in which case the previous line is the wrong
1347 one. */
1348 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001349 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001350 /* If the mark was set, then the lines between old and
1351 current have to be updated too. */
1352 if (ISSET(MARK_ISSET)) {
1353 while (old->prev != current) {
1354 old = old->prev;
1355 update_line(old, 0);
1356 }
1357 }
1358 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001359 update_line(current, current_x);
1360 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001361 return 0;
1362}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001363#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001364
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001365int do_mark(void)
1366{
1367#ifdef NANO_SMALL
1368 nano_disabled_msg();
1369#else
1370 if (!ISSET(MARK_ISSET)) {
1371 statusbar(_("Mark Set"));
1372 SET(MARK_ISSET);
1373 mark_beginbuf = current;
1374 mark_beginx = current_x;
1375 } else {
1376 statusbar(_("Mark UNset"));
1377 UNSET(MARK_ISSET);
1378 edit_refresh();
1379 }
1380#endif
1381 return 1;
1382}
1383
1384void wrap_reset(void)
1385{
1386 UNSET(SAMELINEWRAP);
1387}
1388
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001389#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001390/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001391 * moved forward since the last typed character. Return value:
1392 * whether we wrapped. */
1393int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001394{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001395 size_t len = strlen(inptr->data); /* length of the line we wrap */
1396 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001397 int wrap_loc = -1; /* index of inptr->data where we wrap */
1398 int word_back = -1;
1399#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001400 const char *indentation = NULL;
1401 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001402 int indent_len = 0; /* strlen(indentation) */
1403#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001404 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001405 int after_break_len; /* strlen(after_break) */
1406 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001407 const char *wrap_line = NULL;
1408 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001409 int wrap_line_len = 0; /* strlen(wrap_line) */
1410 char *newline = NULL; /* the line we create */
1411 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001412
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001413/* There are three steps. First, we decide where to wrap. Then, we
1414 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001415
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001416/* Step 1, finding where to wrap. We are going to add a new-line
1417 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001418 * location of this replacement.
1419 *
1420 * Where should we break the line? We need the last "legal wrap point"
1421 * such that the last word before it ended at or before fill. If there
1422 * is no such point, we settle for the first legal wrap point.
1423 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001424 * A "legal wrap point" is a white-space character that is not followed by
1425 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001426 *
1427 * If there is no legal wrap point or we found the last character of the
1428 * line, we should return without wrapping.
1429 *
1430 * Note that the initial indentation does not count as a legal wrap
1431 * point if we are going to auto-indent!
1432 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001433 * Note that the code below could be optimised, by not calling strnlenpt()
1434 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001435
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001436#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001437 if (ISSET(AUTOINDENT))
1438 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001439#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001440 wrap_line = inptr->data + i;
1441 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001442 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001443 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001444 word_back = i;
1445 /* if we have found a "legal wrap point" and the current word
1446 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001447 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001448 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001449 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001450 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001451 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001452 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001453 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001454 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001455
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001456/* Step 2, making the new wrap line. It will consist of indentation +
1457 * after_break + " " + wrap_line (although indentation and wrap_line are
1458 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001459
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001460 /* after_break is the text that will be moved to the next line. */
1461 after_break = inptr->data + wrap_loc + 1;
1462 after_break_len = len - wrap_loc - 1;
1463 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001464
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001465 /* new_line_len will later be increased by the lengths of indentation
1466 * and wrap_line. */
1467 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001468
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001469 /* We prepend the wrapped text to the next line, if the flag is set,
1470 * and there is a next line, and prepending would not make the line
1471 * too long. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +00001472 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001473 wrap_line = inptr->next->data;
1474 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001475
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001476 /* +1 for the space between after_break and wrap_line */
1477 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1478 wrapping = 1;
1479 new_line_len += (1 + wrap_line_len);
1480 }
1481 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001482
Chris Allegrettaff989832001-09-17 13:48:00 +00001483#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001484 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001485 /* Indentation comes from the next line if wrapping, else from
1486 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001487 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001488 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001489 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001490 /* The wrap_line text should not duplicate indentation.
1491 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001492 wrap_line += indent_len;
1493 else
1494 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001495 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001496#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001497
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001498 /* Now we allocate the new line and copy into it. */
1499 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1500 *newline = '\0';
1501
1502#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001503 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001504 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001505 newline[indent_len] = '\0';
1506 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001507#endif
1508 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001509 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001510 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001511 null_at(&inptr->data, wrap_loc + 1);
1512 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001513 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001514 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001515 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001516 * in a tab or a space, we don't add a space and decrement
1517 * totsize to account for that. */
David Lawrence Ramsey7c4222c2002-09-26 22:49:56 +00001518 if (!isspace(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001519 strcat(newline, " ");
1520 else
1521 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001522 strcat(newline, wrap_line);
1523 free(inptr->next->data);
1524 inptr->next->data = newline;
1525 } else {
1526 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001527
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001528 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001529 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001530#ifndef NANO_SMALL
1531 totsize += indent_len;
1532#endif
1533 totlines++;
1534 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001535 temp->prev = inptr;
1536 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001537 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001538 /* If temp->next is NULL, then temp is the last line of the
1539 * file, so we must set filebot. */
1540 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001541 temp->next->prev = temp;
1542 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001543 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001544 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001545
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001546/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1547 * other sundry things. */
1548
1549 /* later wraps of this line will be prepended to the next line. */
1550 SET(SAMELINEWRAP);
1551
1552 /* Each line knows its line number. We recalculate these if we
1553 * inserted a new line. */
1554 if (!wrapping)
1555 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001556
Chris Allegretta6df90f52002-07-19 01:08:59 +00001557 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001558 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001559 current = current->next;
1560 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001561#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001562 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001563#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001564 wrap_loc + 1;
1565 wrap_reset();
1566 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001567 }
1568
Chris Allegretta6df90f52002-07-19 01:08:59 +00001569#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001570 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001571 * If it was on the next line and we wrapped, we must move it
1572 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001573 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1574 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001575 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001576 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001577 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001578#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001579
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001580 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001581 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001582
1583 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001584}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001585#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001586
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001587#ifndef DISABLE_SPELLER
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001588int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001589{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001590 char *save_search;
1591 char *save_replace;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001592 filestruct *begin;
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001593 int i = 0, j = 0, beginx, beginx_top, reverse_search_set, case_sens_set;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001594#ifndef NANO_SMALL
1595 int mark_set;
1596#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001597
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001598 /* save where we are */
1599 begin = current;
1600 beginx = current_x + 1;
1601
Chris Allegretta23b74b22002-01-21 20:32:22 +00001602 /* Make sure Spell Check goes forward only */
1603 reverse_search_set = ISSET(REVERSE_SEARCH);
1604 UNSET(REVERSE_SEARCH);
1605
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001606 case_sens_set = ISSET(CASE_SENSITIVE);
1607 SET(CASE_SENSITIVE);
1608
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001609#ifndef NANO_SMALL
1610 /* Make sure the marking highlight is off during Spell Check */
1611 mark_set = ISSET(MARK_ISSET);
1612 UNSET(MARK_ISSET);
1613#endif
1614
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001615 /* save the current search/replace strings */
1616 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001617 save_search = last_search;
1618 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001619
1620 /* set search/replace strings to mis-spelt word */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001621 last_search = mallocstrcpy(NULL, word);
1622 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001623
1624 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001625 current = fileage;
1626 current_x = beginx_top = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001627
1628 search_last_line = FALSE;
1629
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001630 while (1) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001631 /* make sure word is still mis-spelt (i.e. when multi-errors) */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001632 if (findnextstr(TRUE, FALSE, fileage, beginx_top, word)) {
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001633
Chris Allegretta6df90f52002-07-19 01:08:59 +00001634 /* find whole words only */
1635 if (!is_whole_word(current_x, current->data, word))
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001636 continue;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001637
Chris Allegrettabfd2f562002-12-10 03:03:20 +00001638 edit_update(current, current_x);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001639 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001640
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001641 /* allow replace word to be corrected */
Chris Allegretta5beed502003-01-05 20:41:21 +00001642 i = statusq(0, spell_list, last_replace, 0, _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001643
Chris Allegretta6df90f52002-07-19 01:08:59 +00001644 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001645
1646 /* start from the start of this line again */
1647 current = fileage;
1648 current_x = beginx_top;
1649
1650 search_last_line = FALSE;
1651
Chris Allegretta6df90f52002-07-19 01:08:59 +00001652 if (strcmp(word, answer)) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001653 j = i;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001654 do_replace_loop(word, fileage, &beginx_top, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001655 }
Chris Allegretta80838272001-12-02 06:03:22 +00001656 }
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001657 break;
Rocco Corsi562964d2002-01-13 03:18:03 +00001658 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001659
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001660 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001661 free(last_search); last_search=save_search;
1662 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001663
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001664 /* restore where we were */
1665 current = begin;
1666 current_x = beginx - 1;
1667
Chris Allegretta23b74b22002-01-21 20:32:22 +00001668 /* restore Search/Replace direction */
1669 if (reverse_search_set)
1670 SET(REVERSE_SEARCH);
1671
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001672 if (!case_sens_set)
1673 UNSET(CASE_SENSITIVE);
1674
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001675#ifndef NANO_SMALL
1676 /* restore marking highlight */
1677 if (mark_set)
1678 SET(MARK_ISSET);
1679#endif
1680
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001681 if (i == -1)
1682 return FALSE;
1683
1684 return TRUE;
1685}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001686
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001687/* Integrated spell checking using 'spell' program. Return value: NULL
1688 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001689char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001690{
Chris Allegretta271e9722000-11-10 18:15:43 +00001691 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001692 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001693 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd;
1694 pid_t pid_spell, pid_sort, pid_uniq;
1695 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001696
Chris Allegretta334a9402002-12-16 04:25:53 +00001697 char *pipe_msg = _("Could not create pipe");
Chris Allegretta271e9722000-11-10 18:15:43 +00001698 /* Create a pipe to spell program */
1699
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001700 if (pipe(spell_fd) == -1)
Chris Allegretta334a9402002-12-16 04:25:53 +00001701 return pipe_msg;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001702
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001703 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001704 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001705
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001706 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001707
1708 /* Child continues, (i.e. future spell process) */
1709
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001710 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001711
Chris Allegretta271e9722000-11-10 18:15:43 +00001712 /* replace the standard in with the tempfile */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001713 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) {
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001714 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001715 exit(1);
1716 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001717 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001718 close(tempfile_fd);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001719 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001720 exit(1);
1721 }
1722 close(tempfile_fd);
1723
1724 /* send spell's standard out to the pipe */
1725
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001726 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1727 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001728 exit(1);
1729 }
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001730 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001731
1732 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001733 execlp("spell", "spell", NULL);
1734
Chris Allegretta271e9722000-11-10 18:15:43 +00001735 /* Should not be reached, if spell is found!!! */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001736
Chris Allegretta271e9722000-11-10 18:15:43 +00001737 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001738 }
1739
1740 /* Parent continues here */
1741
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001742 close(spell_fd[1]);
1743
1744 if (pipe(sort_fd) == -1)
Chris Allegretta334a9402002-12-16 04:25:53 +00001745 return pipe_msg;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001746
1747 /* A new process to run sort in */
1748
1749 if ((pid_sort = fork()) == 0) {
1750
1751 /* Child continues, (i.e. future spell process) */
1752 /* replace the standard in with output of the old pipe */
1753 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO) {
1754 close(spell_fd[0]);
1755 close(sort_fd[1]);
1756 exit(1);
1757 }
1758 close(spell_fd[0]);
1759
1760 /* send sort's standard out to the new pipe */
1761
1762 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1763 close(sort_fd[1]);
1764 exit(1);
1765 }
1766 close(sort_fd[1]);
1767
1768 /* Start sort program. Use -f to remove mixed case without having
1769 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1770 execlp("sort", "sort", "-f", NULL);
1771
1772 /* Should not be reached, if sort is found */
1773
1774 exit(1);
1775 }
1776
1777 close(sort_fd[1]);
1778
1779 /* And one more for uniq! */
1780
1781 if (pipe(uniq_fd) == -1)
Chris Allegretta334a9402002-12-16 04:25:53 +00001782 return pipe_msg;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001783
1784 /* A new process to run uniq in */
1785
1786 if ((pid_uniq = fork()) == 0) {
1787
1788 /* Child continues, (i.e. future uniq process) */
1789 /* replace the standard in with output of the old pipe */
1790 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO) {
1791 close(sort_fd[0]);
1792 close(uniq_fd[1]);
1793 exit(1);
1794 }
1795 close(sort_fd[0]);
1796
1797 /* send uniq's standard out to the new pipe */
1798
1799 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
1800 close(uniq_fd[1]);
1801 exit(1);
1802 }
1803 close(uniq_fd[1]);
1804
1805 /* Start uniq program, we are using PATH */
1806 execlp("uniq", "uniq", NULL);
1807
1808 /* Should not be reached, if uniq is found */
1809
1810 exit(1);
1811 }
1812
1813 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001814
1815 /* Child process was not forked successfully */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001816
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001817 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1818 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001819 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001820 }
1821
Chris Allegretta271e9722000-11-10 18:15:43 +00001822 /* Get system pipe buffer size */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001823
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001824 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1825 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001826 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001827 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001828
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001829 /* Read-in the returned spelling errors */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001830
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001831 read_buff_read = 0;
1832 read_buff_size = pipe_buff_size + 1;
1833 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001834
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001835 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001836 read_buff_read += bytesread;
1837 read_buff_size += pipe_buff_size;
1838 read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size);
1839 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001840
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001841 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001842
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001843 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001844 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001845
1846 /* Process the spelling errors */
1847
1848 read_buff_word = read_buff_ptr = read_buff;
1849
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001850 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001851
1852 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001853 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001854 if (read_buff_word != read_buff_ptr) {
1855 if (!do_int_spell_fix(read_buff_word)) {
1856 read_buff_word = read_buff_ptr;
1857 break;
1858 }
1859 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001860 read_buff_word = read_buff_ptr + 1;
1861 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001862 read_buff_ptr++;
1863 }
1864
1865 /* special case where last word doesn't end with \n or \r */
1866 if (read_buff_word != read_buff_ptr)
1867 do_int_spell_fix(read_buff_word);
1868
Chris Allegretta271e9722000-11-10 18:15:43 +00001869 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001870 replace_abort();
Chris Allegretta35908f82002-12-10 00:55:32 +00001871 edit_update(current, current_x);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001872
Chris Allegretta271e9722000-11-10 18:15:43 +00001873 /* Process end of spell process */
1874
Chris Allegretta334a9402002-12-16 04:25:53 +00001875 waitpid(pid_spell, &spell_status, 0);
1876 waitpid(pid_sort, &sort_status, 0);
1877 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001878
Chris Allegretta334a9402002-12-16 04:25:53 +00001879 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1880 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001881
Chris Allegretta334a9402002-12-16 04:25:53 +00001882 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1883 return _("Error invoking \"sort -f\"");
1884
1885 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1886 return _("Error invoking \"uniq\"");
1887
1888 /* Otherwise... */
1889 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001890}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001891
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001892/* External spell checking. Return value: NULL for normal termination,
1893 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001894char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001895{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001896 int alt_spell_status, lineno_cur = current->lineno;
1897 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001898 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001899 char *ptr;
1900 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001901 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001902#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001903 int mark_set = ISSET(MARK_ISSET);
1904 int mbb_lineno_cur = 0;
1905 /* We're going to close the current file, and open the output of
1906 the alternate spell command. The line that mark_beginbuf
1907 points to will be freed, so we save the line number and restore
1908 afterwards. */
1909
1910 if (mark_set) {
1911 mbb_lineno_cur = mark_beginbuf->lineno;
1912 UNSET(MARK_ISSET);
1913 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001914#endif
1915
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001916 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001917
Chris Allegrettae434b452001-01-27 19:25:00 +00001918 /* Set up an argument list to pass the execvp function */
1919 if (spellargs == NULL) {
1920 spellargs = nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001921
Chris Allegrettae434b452001-01-27 19:25:00 +00001922 spellargs[0] = strtok(alt_speller, " ");
1923 while ((ptr = strtok(NULL, " ")) != NULL) {
1924 arglen++;
1925 spellargs = nrealloc(spellargs, arglen * sizeof(char *));
1926 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001927 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001928 spellargs[arglen - 1] = NULL;
1929 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001930 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001931
1932 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001933 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001934 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001935 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001936
1937 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001938 exit(1);
1939 }
1940
1941 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001942 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001943 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001944
1945 /* Wait for alternate speller to complete */
1946
1947 wait(&alt_spell_status);
Chris Allegretta334a9402002-12-16 04:25:53 +00001948 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1949 char *altspell_error = NULL;
1950 char *invoke_error = _("Could not invoke \"%s\"");
1951 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1952
1953 altspell_error = charalloc(msglen);
1954 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1955 return altspell_error;
1956 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001957
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001958 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001959 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001960 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001961 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001962
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001963#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001964 if (mark_set) {
1965 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1966 mark_beginbuf = current;
1967 mark_beginx = current_x;
1968 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001969 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001970 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001971#endif
1972
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001973 /* go back to the old position, mark the file as modified, and make
1974 sure that the titlebar is refreshed */
1975 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001976 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001977 clearok(topwin, FALSE);
1978 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001979
Chris Allegretta334a9402002-12-16 04:25:53 +00001980 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001981}
1982#endif
1983
1984int do_spell(void)
1985{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001986#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001987 nano_disabled_msg();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001988 return TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001989#else
Chris Allegretta334a9402002-12-16 04:25:53 +00001990 char *temp, *spell_msg = _("Generic error");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001991
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001992 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001993 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001994 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001995 return 0;
1996 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001997
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001998 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001999 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00002000 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002001 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00002002 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002003
Chris Allegrettae1f14522001-09-19 03:19:43 +00002004#ifdef ENABLE_MULTIBUFFER
2005 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00002006 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00002007 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00002008#endif
2009
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002010 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00002011 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002012 else
Chris Allegretta334a9402002-12-16 04:25:53 +00002013 spell_msg = do_int_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002014 remove(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002015
Chris Allegretta334a9402002-12-16 04:25:53 +00002016 if (spell_msg == NULL) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002017 statusbar(_("Finished checking spelling"));
Chris Allegretta334a9402002-12-16 04:25:53 +00002018 return 1;
2019 } else {
2020 statusbar(_("Spell checking failed: %s"), spell_msg);
2021 return 0;
2022 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002023
Chris Allegrettabef12972002-03-06 03:30:40 +00002024 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002025
Chris Allegrettadbc12b22000-07-03 03:10:14 +00002026#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00002027}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002028
Chris Allegrettad865da12002-07-29 23:46:38 +00002029#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002030/* The "indentation" of a line is the white-space between the quote part
2031 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002032size_t indent_length(const char *line)
2033{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002034 size_t len = 0;
2035
2036 assert(line != NULL);
2037 while (*line == ' ' || *line == '\t') {
2038 line++;
2039 len++;
2040 }
2041 return len;
2042}
Chris Allegrettadffa2072002-07-24 01:02:26 +00002043#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002044
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002045#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00002046/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
2047 * it maintains 2 after a . ! or ?). Note the terminating \0
2048 * counts as a space.
2049 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002050 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00002051 * returns 1, otherwise returns 0.
2052 *
2053 * If changes_allowed, justify_format() might make line->data
2054 * shorter, and change the actual pointer with null_at().
2055 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002056 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002057 * skip should be at most strlen(line->data). The skip+1st character must
2058 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002059int justify_format(int changes_allowed, filestruct *line, size_t skip)
2060{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002061 const char *punct = ".?!";
2062 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00002063 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002064
Chris Allegretta6df90f52002-07-19 01:08:59 +00002065 /* These four asserts are assumptions about the input data. */
2066 assert(line != NULL);
2067 assert(line->data != NULL);
2068 assert(skip <= strlen(line->data));
2069 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002070
Chris Allegretta6df90f52002-07-19 01:08:59 +00002071 back = line->data + skip;
2072 front = back;
2073 for (; *front; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002074 int remove_space = 0;
2075 /* Do we want to remove this space? */
2076
Chris Allegretta6df90f52002-07-19 01:08:59 +00002077 if (*front == '\t') {
2078 if (!changes_allowed)
2079 return 1;
2080 *front = ' ';
2081 }
2082 /* these tests are safe since line->data + skip is not a space */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002083 if (*front == ' ' && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002084 const char *bob = front - 2;
2085
2086 remove_space = 1;
2087 for (bob = front - 2; bob >= line->data + skip; bob--) {
2088 if (strchr(punct, *bob) != NULL) {
2089 remove_space = 0;
2090 break;
2091 }
2092 if (strchr(brackets, *bob) == NULL)
2093 break;
2094 }
2095 }
2096
2097 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002098 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002099 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002100 if (!changes_allowed)
2101 return 1;
2102#ifndef NANO_SMALL
2103 if (mark_beginbuf == line && back - line->data < mark_beginx)
2104 mark_beginx--;
2105#endif
2106 } else {
2107 *back = *front;
2108 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002109 }
2110 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002111
2112 /* Remove spaces from the end of the line, except maintain 1 after a
2113 * sentence punctuation. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002114 while (line->data < back && *(back - 1) == ' ')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002115 back--;
2116 if (line->data < back && *back == ' ' &&
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002117 strchr(punct, *(back - 1)) != NULL)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002118 back++;
2119 if (!changes_allowed && back != front)
2120 return 1;
2121
2122 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002123 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002124
2125 /* Now back is the new end of line->data. */
2126 if (back != front) {
2127 totsize += back - line->data - strlen(line->data);
2128 null_at(&line->data, back - line->data);
2129#ifndef NANO_SMALL
2130 if (mark_beginbuf == line && back - line->data < mark_beginx)
2131 mark_beginx = back - line->data;
2132#endif
2133 }
2134 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002135}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002136
2137/* The "quote part" of a line is the largest initial substring matching
2138 * the quote string. This function returns the length of the quote part
2139 * of the given line.
2140 *
2141 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2142 * quotestr. */
2143#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002144size_t quote_length(const char *line, const regex_t *qreg)
2145{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002146 regmatch_t matches;
2147 int rc = regexec(qreg, line, 1, &matches, 0);
2148
2149 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2150 return 0;
2151 /* matches.rm_so should be 0, since the quote string should start with
2152 * the caret ^. */
2153 return matches.rm_eo;
2154}
2155#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002156size_t quote_length(const char *line)
2157{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002158 size_t qdepth = 0;
2159 size_t qlen = strlen(quotestr);
2160
2161 /* Compute quote depth level */
2162 while (!strcmp(line + qdepth, quotestr))
2163 qdepth += qlen;
2164 return qdepth;
2165}
2166#endif /* !HAVE_REGEX_H */
2167
Chris Allegretta6df90f52002-07-19 01:08:59 +00002168/* a_line and b_line are lines of text. The quotation part of a_line is
2169 * the first a_quote characters. Check that the quotation part of
2170 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002171int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002172 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002173{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002174 /* Here is the assumption about a_quote: */
2175 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002176 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002177 !strncmp(a_line, b_line, a_quote);
2178}
2179
2180/* We assume a_line and b_line have no quote part. Then, we return whether
2181 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002182size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002183 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002184{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002185 assert(a_indent == indent_length(a_line));
2186 assert(b_indent == indent_length(b_line));
2187
2188 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2189}
2190
2191/* Put the next par_len lines, starting with first_line, in the cut
2192 * buffer. We assume there are enough lines after first_line. We leave
2193 * copies of the lines in place, too. We return the new copy of
2194 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002195filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002196 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002197{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002198 /* We put the original lines, not copies, into the cut buffer, just
2199 * out of a misguided sense of consistency, so if you un-cut, you
2200 * get the actual same paragraph back, not a copy. */
2201 filestruct *alice = first_line;
2202
2203 set_modified();
2204 cutbuffer = NULL;
2205 for(; par_len > 0; par_len--) {
2206 filestruct *bob = copy_node(alice);
2207
2208 if (alice == first_line)
2209 first_line = bob;
2210 if (alice == current)
2211 current = bob;
2212 if (alice == edittop)
2213 edittop = bob;
2214#ifndef NANO_SMALL
2215 if (alice == mark_beginbuf)
2216 mark_beginbuf = bob;
2217#endif
2218 justify_format(1, bob,
2219 quote_len + indent_length(bob->data + quote_len));
2220
2221 assert(alice != NULL && bob != NULL);
2222 add_to_cutbuffer(alice);
2223 splice_node(bob->prev, bob, bob->next);
2224 alice = bob->next;
2225 }
2226 return first_line;
2227}
2228
2229/* We are trying to break a chunk off line. We find the last space such
2230 * that the display length to there is at most goal + 1. If there is
2231 * no such space, and force is not 0, then we find the first space.
2232 * Anyway, we then take the last space in that group of spaces. The
2233 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002234int break_line(const char *line, int goal, int force)
2235{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002236 /* Note that we use int instead of size_t, since goal is at most COLS,
2237 * the screen width, which will always be reasonably small. */
2238 int space_loc = -1;
2239 /* Current tentative return value. Index of the last space we
2240 * found with short enough display width. */
2241 int cur_loc = 0;
2242 /* Current index in line */
2243
2244 assert(line != NULL);
2245 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2246 if (*line == ' ')
2247 space_loc = cur_loc;
2248 assert(*line != '\t');
2249
Chris Allegrettacf287c82002-07-20 13:57:41 +00002250 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002251 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002252 else
2253 goal--;
2254 }
2255 if (goal >= 0)
2256 /* In fact, the whole line displays shorter than goal. */
2257 return cur_loc;
2258 if (space_loc == -1) {
2259 /* No space found short enough. */
2260 if (force)
2261 for(; *line != '\0'; line++, cur_loc++)
2262 if (*line == ' ' && *(line + 1) != ' ')
2263 return cur_loc;
2264 return -1;
2265 }
2266 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002267 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002268 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2269 *(line - cur_loc + space_loc + 1) == '\0')
2270 space_loc++;
2271 return space_loc;
2272}
2273#endif /* !DISABLE_JUSTIFY */
2274
2275/* This function justifies the current paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002276int do_justify(void)
2277{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002278#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00002279 nano_disabled_msg();
2280 return 1;
2281#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002282
Chris Allegretta6df90f52002-07-19 01:08:59 +00002283/* To explain the justifying algorithm, I first need to define some
2284 * phrases about paragraphs and quotation:
2285 * A line of text consists of a "quote part", followed by an
2286 * "indentation part", followed by text. The functions quote_length()
2287 * and indent_length() calculate these parts.
2288 *
2289 * A line is "part of a paragraph" if it has a part not in the quote
2290 * part or the indentation.
2291 *
2292 * A line is "the beginning of a paragraph" if it is part of a paragraph
2293 * and
2294 * 1) it is the top line of the file, or
2295 * 2) the line above it is not part of a paragraph, or
2296 * 3) the line above it does not have precisely the same quote
2297 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002298 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002299 * indentation of the previous line, or
2300 * 5) this line has no quote part and some indentation, and
2301 * AUTOINDENT is not set.
2302 * The reason for number 5) is that if AUTOINDENT is not set, then an
2303 * indented line is expected to start a paragraph, like in books. Thus,
2304 * nano can justify an indented paragraph only if AUTOINDENT is turned
2305 * on.
2306 *
2307 * A contiguous set of lines is a "paragraph" if each line is part of
2308 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002309 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002310
Chris Allegretta6df90f52002-07-19 01:08:59 +00002311 size_t quote_len;
2312 /* Length of the initial quotation of the paragraph we justify. */
2313 size_t par_len;
2314 /* Number of lines in that paragraph. */
2315 filestruct *first_mod_line = NULL;
2316 /* Will be the first line of the resulting justified paragraph
2317 * that differs from the original. For restoring after uncut. */
2318 filestruct *last_par_line = current;
2319 /* Will be the last line of the result, also for uncut. */
2320 filestruct *cutbuffer_save = cutbuffer;
2321 /* When the paragraph gets modified, all lines from the changed
2322 * one down are stored in the cut buffer. We back up the original
2323 * to restore it later. */
2324
2325 /* We save these global variables to be restored if the user
2326 * unjustifies. Note we don't need to save totlines. */
2327 int current_x_save = current_x;
2328 int current_y_save = current_y;
2329 filestruct *current_save = current;
2330 int flags_save = flags;
2331 long totsize_save = totsize;
2332 filestruct *edittop_save = edittop;
2333 filestruct *editbot_save = editbot;
2334#ifndef NANO_SMALL
2335 filestruct *mark_beginbuf_save = mark_beginbuf;
2336 int mark_beginx_save = mark_beginx;
2337#endif
2338
2339 size_t indent_len; /* generic indentation length */
2340 filestruct *line; /* generic line of text */
2341 size_t i; /* generic loop variable */
2342
2343#ifdef HAVE_REGEX_H
2344 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002345 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002346 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2347
2348 if (rc) {
2349 size_t size = regerror(rc, &qreg, NULL, 0);
2350 char *strerror = charalloc(size);
2351
2352 regerror(rc, &qreg, strerror, size);
2353 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2354 free(strerror);
2355 return -1;
2356 }
2357#endif
2358
2359 /* Here is an assumption that is always true anyway. */
2360 assert(current != NULL);
2361
2362/* Here we find the first line of the paragraph to justify. If the
2363 * current line is in a paragraph, then we move back to the first line.
2364 * Otherwise we move down to the first line that is in a paragraph. */
2365 quote_len = quote_length(IFREG(current->data, &qreg));
2366 indent_len = indent_length(current->data + quote_len);
2367
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002368 current_x = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002369 if (current->data[quote_len + indent_len] != '\0') {
2370 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002371 * the first line of this paragraph. First we check items 1) and
2372 * 3) above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002373 while (current->prev != NULL && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002374 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002375 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002376 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002377 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002378
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002379 /* Is this line the beginning of a paragraph, according to
2380 items 2), 5), or 4) above? If so, stop. */
2381 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2382 (quote_len == 0 && indent_len > 0
2383#ifndef NANO_SMALL
2384 && !ISSET(AUTOINDENT)
2385#endif
2386 ) ||
2387 !indents_match(current->prev->data + quote_len,
2388 temp_id_len, current->data + quote_len, indent_len))
2389 break;
2390 indent_len = temp_id_len;
2391 current = current->prev;
2392 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002393 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002394 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002395 /* This line is not part of a paragraph. Move down until we get
2396 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002397 do {
2398 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002399 if (current->next == NULL) {
2400 placewewant = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002401 if (current_y > editwinrows - 1)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002402 edit_update(current, CENTER);
2403 else
2404 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002405 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002406 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002407 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002408 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002409 quote_len = quote_length(IFREG(current->data, &qreg));
2410 indent_len = indent_length(current->data + quote_len);
2411 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002412 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002413/* Now current is the first line of the paragraph, and quote_len
2414 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002415
Chris Allegretta6df90f52002-07-19 01:08:59 +00002416/* Next step, compute par_len, the number of lines in this paragraph. */
2417 line = current;
2418 par_len = 1;
2419 indent_len = indent_length(line->data + quote_len);
2420
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002421 while (line->next != NULL && quotes_match(current->data, quote_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002422 IFREG(line->next->data, &qreg))) {
2423 size_t temp_id_len = indent_length(line->next->data + quote_len);
2424
2425 if (!indents_match(line->data + quote_len, indent_len,
2426 line->next->data + quote_len, temp_id_len) ||
2427 line->next->data[quote_len + temp_id_len] == '\0' ||
2428 (quote_len == 0 && temp_id_len > 0
2429#ifndef NANO_SMALL
2430 && !ISSET(AUTOINDENT)
2431#endif
2432 ))
2433 break;
2434 indent_len = temp_id_len;
2435 line = line->next;
2436 par_len++;
2437 }
2438#ifdef HAVE_REGEX_H
2439 /* We no longer need to check quotation. */
2440 regfree(&qreg);
2441#endif
2442/* Now par_len is the number of lines in this paragraph. Should never
2443 * call quotes_match() or quote_length() again. */
2444
2445/* Next step, we loop through the lines of this paragraph, justifying
2446 * each one individually. */
2447 for(; par_len > 0; current_y++, par_len--) {
2448 size_t line_len;
2449 size_t display_len;
2450 /* The width of current in screen columns. */
2451 int break_pos;
2452 /* Where we will break the line. */
2453
2454 indent_len = indent_length(current->data + quote_len) +
2455 quote_len;
2456 /* justify_format() removes excess spaces from the line, and
2457 * changes tabs to spaces. The first argument, 0, means don't
2458 * change the line, just say whether there are changes to be
2459 * made. If there are, we do backup_lines(), which copies the
2460 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002461 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002462 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002463 first_mod_line = backup_lines(current, par_len, quote_len);
2464
2465 line_len = strlen(current->data);
2466 display_len = strlenpt(current->data);
2467
2468 if (display_len > fill) {
2469 /* The line is too long. Try to wrap it to the next. */
2470 break_pos = break_line(current->data + indent_len,
2471 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002472 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002473 if (break_pos == -1 || break_pos + indent_len == line_len)
2474 /* We can't break the line, or don't need to, so just go
2475 * on to the next. */
2476 goto continue_loc;
2477 break_pos += indent_len;
2478 assert(break_pos < line_len);
2479 /* If we haven't backed up the paragraph, do it now. */
2480 if (first_mod_line == NULL)
2481 first_mod_line = backup_lines(current, par_len, quote_len);
2482 if (par_len == 1) {
2483 /* There is no next line in this paragraph. We make a new
2484 * line and copy text after break_pos into it. */
2485 splice_node(current, make_new_node(current),
2486 current->next);
2487 current->next->data = charalloc(indent_len + line_len -
2488 break_pos);
2489 strncpy(current->next->data, current->data,
2490 indent_len);
2491 strcpy(current->next->data + indent_len,
2492 current->data + break_pos + 1);
2493 assert(strlen(current->next->data) ==
2494 indent_len + line_len - break_pos - 1);
2495 totlines++;
2496 totsize += indent_len;
2497 par_len++;
2498 } else {
2499 size_t next_line_len = strlen(current->next->data);
2500
2501 indent_len = quote_len +
2502 indent_length(current->next->data + quote_len);
2503 current->next->data = (char *)nrealloc(current->next->data,
2504 sizeof(char) * (next_line_len + line_len -
2505 break_pos + 1));
2506
2507 memmove(current->next->data + indent_len + line_len - break_pos,
2508 current->next->data + indent_len,
2509 next_line_len - indent_len + 1);
2510 strcpy(current->next->data + indent_len,
2511 current->data + break_pos + 1);
2512 current->next->data[indent_len + line_len - break_pos - 1]
2513 = ' ';
2514#ifndef NANO_SMALL
2515 if (mark_beginbuf == current->next) {
2516 if (mark_beginx < indent_len)
2517 mark_beginx = indent_len;
2518 mark_beginx += line_len - break_pos;
2519 }
2520#endif
2521 }
2522#ifndef NANO_SMALL
2523 if (mark_beginbuf == current && mark_beginx > break_pos) {
2524 mark_beginbuf = current->next;
2525 mark_beginx -= break_pos + 1 - indent_len;
2526 }
2527#endif
2528 null_at(&current->data, break_pos);
2529 current = current->next;
2530 } else if (display_len < fill && par_len > 1) {
2531 size_t next_line_len = strlen(current->next->data);
2532
2533 indent_len = quote_len +
2534 indent_length(current->next->data + quote_len);
2535 break_pos = break_line(current->next->data + indent_len,
2536 fill - display_len - 1, 0);
2537 if (break_pos == -1)
2538 /* We can't pull a word from the next line up to this one,
2539 * so just go on. */
2540 goto continue_loc;
2541
2542 /* If we haven't backed up the paragraph, do it now. */
2543 if (first_mod_line == NULL)
2544 first_mod_line = backup_lines(current, par_len, quote_len);
2545 current->data = (char *)nrealloc(current->data,
2546 line_len + break_pos + 2);
2547 current->data[line_len] = ' ';
2548 strncpy(current->data + line_len + 1,
2549 current->next->data + indent_len, break_pos);
2550 current->data[line_len + break_pos + 1] = '\0';
2551#ifndef NANO_SMALL
2552 if (mark_beginbuf == current->next) {
2553 if (mark_beginx < indent_len + break_pos) {
2554 mark_beginbuf = current;
2555 if (mark_beginx <= indent_len)
2556 mark_beginx = line_len + 1;
2557 else
2558 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2559 } else
2560 mark_beginx -= break_pos + 1;
2561 }
2562#endif
2563 if (indent_len + break_pos == next_line_len) {
2564 line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002565
2566 /* Don't destroy edittop! */
2567 if (line == edittop)
2568 edittop = current;
2569
Chris Allegretta6df90f52002-07-19 01:08:59 +00002570 unlink_node(line);
2571 delete_node(line);
2572 totlines--;
2573 totsize -= indent_len;
2574 current_y--;
2575 } else {
2576 memmove(current->next->data + indent_len,
2577 current->next->data + indent_len + break_pos + 1,
2578 next_line_len - break_pos - indent_len);
2579 null_at(&current->next->data,
2580 next_line_len - break_pos);
2581 current = current->next;
2582 }
2583 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002584 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002585 current = current->next;
2586 }
2587/* We are now done justifying the paragraph. There are cleanup things to
2588 * do, and we check for unjustify. */
2589
2590 /* totlines, totsize, and current_y have been maintained above. We
2591 * now set last_par_line to the new end of the paragraph, update
2592 * fileage, set current_x. Also, edit_refresh() needs the line
2593 * numbers to be right, so we renumber(). */
2594 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002595 if (first_mod_line != NULL) {
2596 if (first_mod_line->prev == NULL)
2597 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002598 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002599 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002600
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002601 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002602 edit_update(current, CENTER);
2603 else
2604 edit_refresh();
2605
Chris Allegretta9149e612000-11-27 00:23:41 +00002606 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002607 /* Change the shortcut list to display the unjustify code */
2608 shortcut_init(1);
2609 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002610 reset_cursor();
2611
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002613 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002614
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002615#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002616 /* If it was a mouse click, parse it with do_mouse() and it might
2617 * become the unjustify key. Else give it back to the input stream. */
2618 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002619 do_mouse();
2620 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002621 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002622#endif
Chris Allegretta5f071802001-05-06 02:34:31 +00002623
Chris Allegretta6df90f52002-07-19 01:08:59 +00002624 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2625 ungetch(i);
2626 /* Did we back up anything at all? */
2627 if (cutbuffer != cutbuffer_save)
2628 free_filestruct(cutbuffer);
2629 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002630 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002631 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002632 current = current_save;
2633 current_x = current_x_save;
2634 current_y = current_y_save;
2635 edittop = edittop_save;
2636 editbot = editbot_save;
2637 if (first_mod_line != NULL) {
2638 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002639
Chris Allegretta6df90f52002-07-19 01:08:59 +00002640 /* Splice the cutbuffer back into the file. */
2641 cutbottom->next = last_par_line->next;
2642 cutbottom->next->prev = cutbottom;
2643 /* The line numbers after the end of the paragraph have
2644 * been changed, so we change them back. */
2645 renumber(cutbottom->next);
2646 if (first_mod_line->prev != NULL) {
2647 cutbuffer->prev = first_mod_line->prev;
2648 cutbuffer->prev->next = cutbuffer;
2649 } else
2650 fileage = cutbuffer;
2651 cutbuffer = NULL;
2652
2653 last_par_line->next = NULL;
2654 free_filestruct(first_mod_line);
2655
2656 /* Restore global variables from before justify */
2657 totsize = totsize_save;
2658 totlines = filebot->lineno;
2659#ifndef NANO_SMALL
2660 mark_beginbuf = mark_beginbuf_save;
2661 mark_beginx = mark_beginx_save;
2662#endif
2663 flags = flags_save;
2664 if (!ISSET(MODIFIED)) {
2665 titlebar(NULL);
2666 wrefresh(topwin);
2667 }
2668 }
2669 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002670 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002671 cutbuffer = cutbuffer_save;
2672 blank_statusbar_refresh();
2673 /* display shortcut list without UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002674 shortcut_init(0);
2675 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002676
Chris Allegretta6df90f52002-07-19 01:08:59 +00002677 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002678#endif
2679}
2680
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002681int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002682{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002683 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002684
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002685 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002686
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002687#ifdef ENABLE_MULTIBUFFER
2688 if (!close_open_file()) {
2689 display_main_list();
2690 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002691 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002692 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002693#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002694 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002695 }
2696
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002697 if (ISSET(TEMP_OPT)) {
2698 i = 1;
2699 } else {
2700 i = do_yesno(0, 0,
2701 _
2702 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2703 }
2704
2705#ifdef DEBUG
2706 dump_buffer(fileage);
2707#endif
2708
2709 if (i == 1) {
2710 if (do_writeout(filename, 1, 0) > 0) {
2711
2712#ifdef ENABLE_MULTIBUFFER
2713 if (!close_open_file()) {
2714 display_main_list();
2715 return 1;
2716 }
2717 else
2718#endif
2719 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002720 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002721 } else if (i == 0) {
2722
2723#ifdef ENABLE_MULTIBUFFER
2724 if (!close_open_file()) {
2725 display_main_list();
2726 return 1;
2727 }
2728 else
2729#endif
2730 finish(0);
2731 } else
2732 statusbar(_("Cancelled"));
2733
2734 display_main_list();
2735 return 1;
2736}
2737
2738void signal_init(void)
2739{
2740#ifdef _POSIX_VDISABLE
2741 struct termios term;
2742#endif
2743
2744 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2745 memset(&act, 0, sizeof(struct sigaction));
2746 act.sa_handler = SIG_IGN;
2747 sigaction(SIGINT, &act, NULL);
2748
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002749 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2750 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002751 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002752 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002753
2754#ifndef NANO_SMALL
2755 act.sa_handler = handle_sigwinch;
2756 sigaction(SIGWINCH, &act, NULL);
2757#endif
2758
2759#ifdef _POSIX_VDISABLE
2760 tcgetattr(0, &term);
2761
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002762 /* Ignore ^S, much to Chris' chagrin */
Chris Allegrettae42df732002-10-15 00:27:55 +00002763 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2764
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002765#ifdef VDSUSP
2766 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2767#endif /* VDSUSP */
2768
2769#endif /* _POSIX_VDISABLE */
2770
2771 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002772 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002773#ifdef _POSIX_VDISABLE
2774 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2775#else
2776 act.sa_handler = SIG_IGN;
2777 sigaction(SIGTSTP, &act, NULL);
2778#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002779 } else {
2780 /* If we don't do this, it seems other stuff interrupts the
2781 suspend handler! Try using nano with mutt without this
2782 line. */
2783 sigfillset(&act.sa_mask);
2784
2785 act.sa_handler = do_suspend;
2786 sigaction(SIGTSTP, &act, NULL);
2787
2788 act.sa_handler = do_cont;
2789 sigaction(SIGCONT, &act, NULL);
2790 }
2791
2792#ifdef _POSIX_VDISABLE
2793 tcsetattr(0, TCSANOW, &term);
2794#endif
2795}
2796
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002797/* Handler for SIGHUP and SIGTERM */
2798RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002799{
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002800 die(_("Received SIGHUP or SIGTERM"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002801}
2802
2803/* What do we do when we catch the suspend signal */
2804RETSIGTYPE do_suspend(int signal)
2805{
2806 endwin();
2807 printf("\n\n\n\n\nUse \"fg\" to return to nano\n");
2808 fflush(stdout);
2809
2810 /* Restore the terminal settings for the disabled keys */
2811 tcsetattr(0, TCSANOW, &oldterm);
2812
2813 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002814 then we could be (and were) interrupted in the middle of the call.
2815 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002816 kill(0, SIGSTOP);
2817}
2818
2819/* Restore the suspend handler when we come back into the prog */
2820RETSIGTYPE do_cont(int signal)
2821{
2822 /* Now we just update the screen instead of having to reenable the
2823 SIGTSTP handler. */
2824
2825 doupdate();
2826 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2827 start suspending again. */
2828 signal_init();
2829
2830#ifndef NANO_SMALL
2831 /* Perhaps the user resized the window while we slept. */
2832 handle_sigwinch(0);
2833#endif
2834}
2835
2836#ifndef NANO_SMALL
2837void handle_sigwinch(int s)
2838{
2839 const char *tty = ttyname(0);
2840 int fd;
2841 int result = 0;
2842 struct winsize win;
2843
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002844 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002845 return;
2846 fd = open(tty, O_RDWR);
2847 if (fd == -1)
2848 return;
2849 result = ioctl(fd, TIOCGWINSZ, &win);
2850 close(fd);
2851 if (result == -1)
2852 return;
2853
2854 /* Could check whether the COLS or LINES changed, and return
2855 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2856 * variables, and in some cases ncurses has already updated them.
2857 * But not in all cases, argh. */
2858 COLS = win.ws_col;
2859 LINES = win.ws_row;
2860 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
2861 die_too_small();
2862
2863#ifndef DISABLE_WRAPJUSTIFY
2864 fill = wrap_at;
2865 if (fill <= 0)
2866 fill += COLS;
2867 if (fill < MIN_FILL_LENGTH)
2868 die_too_small();
2869#endif
2870
2871 hblank = nrealloc(hblank, COLS + 1);
2872 memset(hblank, ' ', COLS);
2873 hblank[COLS] = '\0';
2874
2875#ifdef HAVE_RESIZETERM
2876 resizeterm(LINES, COLS);
2877#ifdef HAVE_WRESIZE
2878 if (wresize(topwin, 2, COLS) == ERR)
2879 die(_("Cannot resize top win"));
2880 if (mvwin(topwin, 0, 0) == ERR)
2881 die(_("Cannot move top win"));
2882 if (wresize(edit, editwinrows, COLS) == ERR)
2883 die(_("Cannot resize edit win"));
2884 if (mvwin(edit, 2, 0) == ERR)
2885 die(_("Cannot move edit win"));
2886 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2887 die(_("Cannot resize bottom win"));
2888 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2889 die(_("Cannot move bottom win"));
2890#endif /* HAVE_WRESIZE */
2891#endif /* HAVE_RESIZETERM */
2892
2893 fix_editbot();
2894
2895 if (current_y > editwinrows - 1)
2896 edit_update(editbot, CENTER);
2897 erase();
2898
2899 /* Do these b/c width may have changed... */
2900 refresh();
2901 titlebar(NULL);
2902 edit_refresh();
2903 display_main_list();
2904 blank_statusbar();
2905 total_refresh();
2906
2907 /* Turn cursor back on for sure */
2908 curs_set(1);
2909
2910 /* Jump back to main loop */
2911 siglongjmp(jmpbuf, 1);
2912}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002913#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002914
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002915/* If the NumLock key has made the keypad go awry, print an error
2916 message; hopefully we can address it later. */
2917void print_numlock_warning(void)
2918{
2919 static int didmsg = 0;
2920 if (!didmsg) {
2921 statusbar(_
2922 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2923 didmsg = 1;
2924 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002925}
2926
Chris Allegrettadab017e2002-04-23 10:56:06 +00002927#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002928void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002929{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002930 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002931
Chris Allegretta658399a2001-06-14 02:54:22 +00002932 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002933 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002934
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002935 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002936 case TOGGLE_PICOMODE_KEY:
Chris Allegretta07798352000-11-27 22:58:23 +00002937 shortcut_init(0);
Chris Allegrettac1049ac2001-08-17 00:03:46 +00002938 SET(CLEAR_BACKUPSTRING);
Chris Allegretta756f2202000-09-01 13:32:47 +00002939 display_main_list();
2940 break;
2941 case TOGGLE_SUSPEND_KEY:
2942 signal_init();
2943 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002944#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00002945 case TOGGLE_MOUSE_KEY:
2946 mouse_init();
2947 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002948#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002949 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002950 wclear(bottomwin);
2951 wrefresh(bottomwin);
2952 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002953 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002954 edit_refresh();
2955 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002956 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002957 case TOGGLE_DOS_KEY:
2958 UNSET(MAC_FILE);
2959 break;
2960 case TOGGLE_MAC_KEY:
2961 UNSET(DOS_FILE);
2962 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002963#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002964 case TOGGLE_SYNTAX_KEY:
2965 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002966 break;
2967#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002968 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002969
Chris Allegretta6df90f52002-07-19 01:08:59 +00002970 /* We are assuming here that shortcut_init() above didn't free and
2971 * reallocate the toggles. */
2972 enabled = ISSET(which->flag);
2973 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2974 enabled = !enabled;
2975 statusbar("%s %s", which->desc,
2976 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002977}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002978#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002979
Chris Allegretta1748cd12001-01-13 17:22:54 +00002980/* This function returns the correct keystroke, given the A,B,C or D
2981 input key. This is a common sequence of many terms which send
2982 Esc-O-[A-D] or Esc-[-[A-D]. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002983int abcd(int input)
Chris Allegretta1748cd12001-01-13 17:22:54 +00002984{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002985 switch (input) {
2986 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002987 case 'a':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002988 return KEY_UP;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002989 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002990 case 'b':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002991 return KEY_DOWN;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002992 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002993 case 'c':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002994 return KEY_RIGHT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002995 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002996 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002997 return KEY_LEFT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002998 default:
2999 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00003000 }
3001}
3002
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003003int main(int argc, char *argv[])
3004{
3005 int optchr;
3006 int kbinput; /* Input from keyboard */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003007 int startline = 0; /* Line to try and start at */
Chris Allegretta08020882001-01-29 23:37:54 +00003008 int keyhandled; /* Have we handled the keystroke yet? */
Chris Allegretta9caa1932002-02-15 20:08:05 +00003009 int modify_control_seq;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003010 const char *argv0;
3011 const shortcut *s;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003012#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003013 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003014#endif
Chris Allegretta0357c4d2001-09-19 02:59:25 +00003015
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003016#ifdef _POSIX_VDISABLE
3017 struct termios term;
3018#endif
3019
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003020#ifdef HAVE_GETOPT_LONG
3021 int option_index = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003022 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003023 {"help", 0, 0, 'h'},
3024#ifdef ENABLE_MULTIBUFFER
3025 {"multibuffer", 0, 0, 'F'},
3026#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003027#ifdef ENABLE_NANORC
3028 {"ignorercfiles", 0, 0, 'I'},
3029#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003030 {"keypad", 0, 0, 'K'},
3031#ifndef DISABLE_JUSTIFY
3032 {"quotestr", 1, 0, 'Q'},
3033#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003034#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003035 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003036#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003037 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003038 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003039#ifdef ENABLE_COLOR
3040 {"syntax", 1, 0, 'Y'},
3041#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003042 {"const", 0, 0, 'c'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003043 {"nofollow", 0, 0, 'l'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003044#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003045 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003046#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003047#ifndef DISABLE_OPERATINGDIR
3048 {"operatingdir", 1, 0, 'o'},
3049#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003050 {"pico", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003051#ifndef DISABLE_WRAPJUSTIFY
3052 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003053#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003054#ifndef DISABLE_SPELLER
3055 {"speller", 1, 0, 's'},
3056#endif
3057 {"tempfile", 0, 0, 't'},
3058 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003059#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003060 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003061#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003062 {"nohelp", 0, 0, 'x'},
3063 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003064#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003065 {"backup", 0, 0, 'B'},
3066 {"dos", 0, 0, 'D'},
3067 {"mac", 0, 0, 'M'},
3068 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003069 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003070 {"autoindent", 0, 0, 'i'},
3071 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003072#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003073 {0, 0, 0, 0}
3074 };
3075#endif
3076
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003077#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003078 setlocale(LC_ALL, "");
3079 bindtextdomain(PACKAGE, LOCALEDIR);
3080 textdomain(PACKAGE);
3081#endif
3082
Chris Allegretta8d8e0122001-04-18 04:28:54 +00003083#ifdef ENABLE_NANORC
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003084 {
3085 /* scan through the options and handle -I/--ignorercfiles
3086 first, so that it's handled before we call do_rcfile() and
3087 read the other options; don't use getopt()/getopt_long()
3088 here, because there's no way to reset it properly
3089 afterward */
3090 int i;
3091 for (i = 1; i < argc; i++) {
3092 if (!strcmp(argv[i], "--"))
3093 break;
3094 else if (!strcmp(argv[i], "-I"))
3095 SET(NO_RCFILE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003096#ifdef HAVE_GETOPT_LONG
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003097 else if (!strcmp(argv[i], "--ignorercfiles"))
3098 SET(NO_RCFILE);
Chris Allegretta6df90f52002-07-19 01:08:59 +00003099#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003100 }
3101 }
Chris Allegretta5beed502003-01-05 20:41:21 +00003102
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003103 if (!ISSET(NO_RCFILE))
3104 do_rcfile();
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003105#else
3106#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3107 /* if we don't have rcfile support, we're root, and
3108 --disable-wrapping-as-root is used, turn wrapping off */
3109 if (geteuid() == 0)
3110 SET(NO_WRAP);
3111#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003112#endif /* ENABLE_NANORC */
3113
3114#ifdef HAVE_GETOPT_LONG
3115 while ((optchr = getopt_long(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz",
3116 long_options, &option_index)) != EOF) {
3117#else
3118 while ((optchr =
3119 getopt(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != EOF) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003120#endif
3121
3122 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003123
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003124 case 'h':
3125 case '?':
3126 usage();
3127 exit(0);
3128 case 'a':
3129 case 'b':
3130 case 'e':
3131 case 'f':
3132 case 'g':
3133 case 'j':
3134 /* Pico compatibility flags */
3135 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003136#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003137 case 'B':
3138 SET(BACKUP_FILE);
3139 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003140 case 'D':
3141 SET(DOS_FILE);
3142 break;
3143#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003144#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003145 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003146 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003147 break;
3148#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003149#ifdef ENABLE_NANORC
Chris Allegretta6df90f52002-07-19 01:08:59 +00003150 case 'I':
3151 break;
3152#endif
Chris Allegretta48bd3782002-01-03 21:26:34 +00003153 case 'K':
3154 SET(ALT_KEYPAD);
3155 break;
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003156#ifndef NANO_SMALL
3157 case 'M':
3158 SET(MAC_FILE);
3159 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003160 case 'N':
3161 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003162 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003163#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003164#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003165 case 'Q':
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003166 quotestr = optarg;
3167 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003168#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003169#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003170 case 'R':
3171 SET(USE_REGEXP);
3172 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003173#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003174#ifndef NANO_SMALL
3175 case 'S':
3176 SET(SMOOTHSCROLL);
3177 break;
3178#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003179 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003180 {
3181 int i;
3182 char *first_error;
3183
3184 /* Using strtol instead of atoi lets us accept 0 while
3185 * checking other errors. */
3186 i = (int)strtol(optarg, &first_error, 10);
3187 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3188 usage();
3189 exit(1);
3190 } else
3191 tabsize = i;
3192 if (tabsize <= 0) {
3193 fprintf(stderr, _("Tab size is too small for nano...\n"));
3194 exit(1);
3195 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003196 }
3197 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003198 case 'V':
3199 version();
3200 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003201#ifdef ENABLE_COLOR
3202 case 'Y':
3203 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3204 break;
3205#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003206 case 'c':
3207 SET(CONSTUPDATE);
3208 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003209#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003210 case 'i':
3211 SET(AUTOINDENT);
3212 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003213 case 'k':
3214 SET(CUT_TO_END);
3215 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003216#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003217 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003218 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003219 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003220#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003221 case 'm':
3222 SET(USE_MOUSE);
3223 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003224#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003225#ifndef DISABLE_OPERATINGDIR
3226 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003227 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003228 break;
3229#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003230 case 'p':
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003231 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003232 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003233#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003234 case 'r':
3235 {
3236 int i;
3237 char *first_error;
3238
3239 /* Using strtol instead of atoi lets us accept 0 while
3240 * checking other errors. */
3241 i = (int)strtol(optarg, &first_error, 10);
3242 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0') {
3243 usage();
3244 exit(1);
3245 } else
3246 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003247 }
3248 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003249#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003250#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003251 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003252 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003253 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003254#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003255 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003256 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003257 break;
3258 case 'v':
3259 SET(VIEW_MODE);
3260 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003261#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003262 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003263 SET(NO_WRAP);
3264 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003265#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003266 case 'x':
3267 SET(NO_HELP);
3268 break;
3269 case 'z':
3270 SET(SUSPEND);
3271 break;
3272 default:
3273 usage();
Chris Allegretta4da1fc62000-06-21 03:00:43 +00003274 exit(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003275 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003276 }
3277
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003278#ifndef DISABLE_OPERATINGDIR
3279 /* Set up the operating directory. This entails chdir()ing there, so
3280 that file reads and writes will be based there. */
3281 init_operating_dir();
3282#endif
3283
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003284 /* Clear the filename we'll be using */
3285 filename = charalloc(1);
3286 filename[0] = '\0';
3287
3288 /* See if we were invoked with the name "pico" */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003289 argv0 = strrchr(argv[0], '/');
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003290 if ((argv0 != NULL && strstr(argv0, "pico") != NULL)
3291 || (argv0 == NULL && strstr(argv[0], "pico") != NULL))
Chris Allegrettabf9a8cc2000-11-17 01:37:39 +00003292 SET(PICO_MODE);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003293
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003294 /* See if there's a non-option in argv (first non-option is the
3295 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003296 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003297 /* Look for the +line flag... */
3298 if (argv[optind][0] == '+') {
3299 startline = atoi(&argv[optind][1]);
3300 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003301 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003302 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003303 } else
3304 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003305 }
3306
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003307 /* First back up the old settings so they can be restored, duh */
3308 tcgetattr(0, &oldterm);
3309
3310#ifdef _POSIX_VDISABLE
3311 term = oldterm;
3312 term.c_cc[VINTR] = _POSIX_VDISABLE;
3313 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3314 term.c_lflag &= ~IEXTEN;
3315 tcsetattr(0, TCSANOW, &term);
3316#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003317
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003318 /* now ncurses init stuff... */
3319 initscr();
3320 savetty();
3321 nonl();
3322 cbreak();
3323 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003324
3325 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003326 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003327 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003328 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003329
3330#ifdef DEBUG
3331 fprintf(stderr, _("Main: set up windows\n"));
3332#endif
3333
Chris Allegretta2a42af12000-09-12 23:02:49 +00003334 window_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003335#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00003336 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003337#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003338
Chris Allegretta48bd3782002-01-03 21:26:34 +00003339 if (!ISSET(ALT_KEYPAD)) {
3340 keypad(edit, TRUE);
3341 keypad(bottomwin, TRUE);
3342 }
3343
Chris Allegretta5beed502003-01-05 20:41:21 +00003344#ifndef NANO_SMALL
3345 history_init();
3346#endif
3347
Chris Allegretta08893e02001-11-29 02:42:27 +00003348#ifdef ENABLE_COLOR
3349 do_colorinit();
Chris Allegretta08893e02001-11-29 02:42:27 +00003350#endif /* ENABLE_COLOR */
3351
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003352#ifdef DEBUG
3353 fprintf(stderr, _("Main: bottom win\n"));
3354#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003355 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003356 display_main_list();
3357
3358#ifdef DEBUG
3359 fprintf(stderr, _("Main: open file\n"));
3360#endif
3361
Chris Allegretta31c76662000-11-21 06:20:20 +00003362 /* Now we check to see if argv[optind] is non-null to determine if
3363 we're dealing with a new file or not, not argc == 1... */
3364 if (argv[optind] == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003365 new_file();
3366 else
3367 open_file(filename, 0, 0);
3368
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003369 titlebar(NULL);
3370
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003371 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003372 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003373 else
Chris Allegretta234a34d2000-07-29 04:33:38 +00003374 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003375
Chris Allegretta08020882001-01-29 23:37:54 +00003376 /* return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003377 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003378
3379 /* Fix clobber-age */
3380 kbinput = 0;
3381 keyhandled = 0;
3382 modify_control_seq = 0;
3383
Robert Siemborski6967eec2000-07-08 14:23:32 +00003384 edit_refresh();
3385 reset_cursor();
3386
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003387 while (1) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003388
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003389#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003390 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003391#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003392
Chris Allegretta9239d742000-09-06 15:19:18 +00003393#ifndef _POSIX_VDISABLE
3394 /* We're going to have to do it the old way, i.e. on cygwin */
3395 raw();
3396#endif
3397
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003398 kbinput = wgetch(edit);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003399#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003400 fprintf(stderr, _("AHA! %c (%d)\n"), kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003401#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003402 if (kbinput == 27) { /* Grab Alt-key stuff first */
3403 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003404 /* Alt-O, suddenly very important ;) */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003405 case 'O':
Chris Allegretta16e41682000-09-11 22:33:54 +00003406 kbinput = wgetch(edit);
Chris Allegretta316e4d92001-04-28 16:31:19 +00003407 if ((kbinput <= 'D' && kbinput >= 'A') ||
3408 (kbinput <= 'd' && kbinput >= 'a'))
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003409 kbinput = abcd(kbinput);
Chris Allegretta201d9bf2001-01-14 03:17:53 +00003410 else if (kbinput <= 'z' && kbinput >= 'j')
3411 print_numlock_warning();
3412 else if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003413 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00003414#ifdef DEBUG
3415 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003416 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
3417 kbinput, kbinput);
3418 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003419 }
3420#endif
3421 break;
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003422 case 27:
3423 /* If we get Alt-Alt, the next keystroke should be the same as a
3424 control sequence */
3425 modify_control_seq = 1;
3426 keyhandled = 1;
3427 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003428 case '[':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003429 switch (kbinput = wgetch(edit)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003430 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00003431 kbinput = wgetch(edit);
3432 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003433 kbinput = KEY_F(kbinput - 48);
3434 wgetch(edit);
3435 } else if (kbinput >= '7' && kbinput <= '9') {
3436 kbinput = KEY_F(kbinput - 49);
3437 wgetch(edit);
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003438 } else if (kbinput == '~')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003439 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00003440#ifdef DEBUG
3441 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003442 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
3443 kbinput, kbinput);
3444 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003445 }
3446#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003447 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003448 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00003449 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00003450 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003451 case '0':
3452 kbinput = KEY_F(9);
3453 wgetch(edit);
3454 break;
3455 case '1':
3456 kbinput = KEY_F(10);
3457 wgetch(edit);
3458 break;
3459 case '3':
3460 kbinput = KEY_F(11);
3461 wgetch(edit);
3462 break;
3463 case '4':
3464 kbinput = KEY_F(12);
3465 wgetch(edit);
3466 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003467 case '~':
3468 goto do_insertkey;
Chris Allegretta16e41682000-09-11 22:33:54 +00003469#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003470 default:
3471 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
3472 kbinput, kbinput);
3473 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003474#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003475 }
3476 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003477 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003478 kbinput = NANO_DELETE_KEY;
3479 wgetch(edit);
3480 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003481 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003482 kbinput = NANO_END_KEY;
3483 wgetch(edit);
3484 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003485 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00003486 kbinput = KEY_PPAGE;
3487 wgetch(edit);
3488 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003489 case 'V': /* Alt-[-V = Page Up in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003490 case 'I': /* Alt-[-I = Page Up - FreeBSD Console */
3491 kbinput = KEY_PPAGE;
3492 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003493 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00003494 kbinput = KEY_NPAGE;
3495 wgetch(edit);
3496 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003497 case 'U': /* Alt-[-U = Page Down in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003498 case 'G': /* Alt-[-G = Page Down - FreeBSD Console */
3499 kbinput = KEY_NPAGE;
3500 break;
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003501 case '7':
3502 kbinput = KEY_HOME;
3503 wgetch(edit);
3504 break;
3505 case '8':
3506 kbinput = KEY_END;
3507 wgetch(edit);
3508 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003509 case '9': /* Alt-[-9 = Delete in Hurd Console */
3510 kbinput = KEY_DC;
3511 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003512 case '@': /* Alt-[-@ = Insert in Hurd Console */
3513 case 'L': /* Alt-[-L = Insert - FreeBSD Console */
3514 goto do_insertkey;
3515 case '[': /* Alt-[-[-[A-E], F1-F5 in Linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00003516 kbinput = wgetch(edit);
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003517 if (kbinput >= 'A' && kbinput <= 'E')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003518 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00003519 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003520 case 'A':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003521 case 'B':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003522 case 'C':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003523 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003524 case 'a':
3525 case 'b':
3526 case 'c':
3527 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003528 kbinput = abcd(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003529 break;
3530 case 'H':
3531 kbinput = KEY_HOME;
3532 break;
3533 case 'F':
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003534 case 'Y': /* End Key in Hurd Console */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003535 kbinput = KEY_END;
3536 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003537 default:
3538#ifdef DEBUG
3539 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
3540 kbinput, kbinput);
3541#endif
3542 break;
3543 }
3544 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003545
Chris Allegretta355fbe52001-07-14 19:32:47 +00003546#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003547 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003548 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003549 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003550 keyhandled = 1;
3551 break;
3552 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003553 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003554 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003555 keyhandled = 1;
3556 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003557#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003558 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003559 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003560 for (s = main_list; s != NULL; s = s->next)
3561 if (kbinput == s->altval ||
Chris Allegretta6232d662002-05-12 19:52:15 +00003562 kbinput == s->altval - 32) {
3563 if (ISSET(VIEW_MODE) && !s->viewok)
3564 print_view_warning();
3565 else
3566 s->func();
3567 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003568 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003569 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003570#ifndef NANO_SMALL
3571 /* And for toggle switches */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003572 for (t = toggles; t != NULL && !keyhandled; t = t->next)
3573 if (kbinput == t->val ||
3574 (t->val > 'a' &&
3575 kbinput == t->val - 32)) {
3576 do_toggle(t);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003577 keyhandled = 1;
3578 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00003579 }
3580#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003581#ifdef DEBUG
3582 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
3583 kbinput);
3584#endif
3585 break;
3586 }
3587 }
Chris Allegrettacf287c82002-07-20 13:57:41 +00003588 /* If modify_control_seq is set, we received an Alt-Alt
3589 sequence before this, so we make this key a control sequence
3590 by subtracting 32, 64, or 96, depending on its value. */
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003591 if (!keyhandled && modify_control_seq) {
Chris Allegrettacf287c82002-07-20 13:57:41 +00003592 if (kbinput == ' ')
3593 kbinput -= 32;
3594 else if (kbinput >= 'A' && kbinput < 'a')
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003595 kbinput -= 64;
3596 else if (kbinput >= 'a' && kbinput <= 'z')
3597 kbinput -= 96;
3598
3599 modify_control_seq = 0;
3600 }
3601
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003602 /* Look through the main shortcut list to see if we've hit a
3603 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003604
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003605#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003606 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003607#else
3608 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3609#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003610 if (kbinput == s->val ||
3611 (s->misc1 && kbinput == s->misc1) ||
3612 (s->misc2 && kbinput == s->misc2)) {
3613 if (ISSET(VIEW_MODE) && !s->viewok)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003614 print_view_warning();
3615 else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003616 s->func();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003617 keyhandled = 1;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003618 /* rarely, the value of s can change after s->func(),
3619 leading to problems; get around this by breaking out
3620 explicitly once we successfully handle a shortcut */
3621 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003622 }
3623 }
Chris Allegrettae42df732002-10-15 00:27:55 +00003624
3625#ifdef _POSIX_VDISABLE
3626 /* Don't even think about changing this string */
3627 if (kbinput == 19)
3628 statusbar(_("XOFF ignored, mumble mumble."));
3629#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003630 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3631 Control-S and Control-Q */
Chris Allegretta9239d742000-09-06 15:19:18 +00003632 if (kbinput == 17 || kbinput == 19)
3633 keyhandled = 1;
3634
Chris Allegretta9caa1932002-02-15 20:08:05 +00003635 /* Catch ^Z by hand when triggered also
3636 407 == ^Z in Linux console when keypad() is used? */
3637 if (kbinput == 26 || kbinput == 407) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003638 if (ISSET(SUSPEND))
3639 do_suspend(0);
3640 keyhandled = 1;
3641 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003642
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003643 /* Hack, make insert key do something useful, like insert file */
3644 if (kbinput == KEY_IC) {
3645 do_insertkey:
3646
3647#ifdef ENABLE_MULTIBUFFER
Chris Allegretta32da4562002-01-02 15:12:21 +00003648 /* do_insertfile_void() contains the logic needed to
3649 handle view mode with the view mode/multibuffer
3650 exception, so use it here */
3651 do_insertfile_void();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003652#else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003653 if (!ISSET(VIEW_MODE))
3654 do_insertfile_void();
3655 else
3656 print_view_warning();
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003657#endif
3658
Chris Allegretta1c27d3e2001-10-02 02:56:45 +00003659 keyhandled = 1;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003660 }
3661
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003662 /* Last gasp, stuff that's not in the main lists */
3663 if (!keyhandled)
3664 switch (kbinput) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003665#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003666 case KEY_MOUSE:
3667 do_mouse();
3668 break;
3669#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003670
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003671 case 0: /* Erg */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003672 case -1: /* Stuff that we don't want to do squat */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003673 case 410: /* Must ignore this, it gets sent when we resize */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003674 case 29: /* Ctrl-] */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003675#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003676 case 541: /* ???? */
3677 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00003678 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003679 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00003680 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003681#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003682
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003683 break;
3684 default:
3685#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003686 fprintf(stderr, _("I got %c (%d)!\n"), kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003687#endif
3688 /* We no longer stop unhandled sequences so that people with
3689 odd character sets can type... */
3690
3691 if (ISSET(VIEW_MODE)) {
3692 print_view_warning();
3693 break;
3694 }
3695 do_char(kbinput);
3696 }
Chris Allegretta7fdbd052001-10-02 00:55:38 +00003697 if (ISSET(DISABLE_CURPOS))
3698 UNSET(DISABLE_CURPOS);
3699 else if (ISSET(CONSTUPDATE))
Chris Allegretta2084acc2001-11-29 03:43:08 +00003700 do_cursorpos(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003701
3702 reset_cursor();
3703 wrefresh(edit);
3704 keyhandled = 0;
3705 }
3706
3707 getchar();
3708 finish(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003709}