blob: e20378f2875101fd8d6f51ae5fb6ce0fab5dfa86 [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * nano.c *
4 * *
Chris Allegrettad757e252003-01-15 19:33:27 +00005 * Copyright (C) 1999-2003 Chris Allegretta *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00006 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
Chris Allegretta3a24f3f2001-10-24 11:33:54 +00008 * the Free Software Foundation; either version 2, or (at your option) *
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00009 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdio.h>
25#include <stdlib.h>
26#include <stdarg.h>
27#include <signal.h>
Chris Allegretta08020882001-01-29 23:37:54 +000028#include <setjmp.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000029#include <unistd.h>
30#include <string.h>
31#include <fcntl.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/param.h>
Chris Allegretta27eb13f2000-11-05 16:52:21 +000035#include <sys/types.h>
36#include <sys/wait.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000037#include <errno.h>
38#include <ctype.h>
39#include <locale.h>
40#include <limits.h>
Adam Rogoyski77f36de2000-06-07 03:56:54 +000041#include <assert.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#include "proto.h"
43#include "nano.h"
44
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000045#ifdef HAVE_TERMIOS_H
46#include <termios.h>
47#endif
48
49#ifdef HAVE_TERMIO_H
50#include <termio.h>
51#endif
52
53#ifdef HAVE_GETOPT_H
54#include <getopt.h>
55#endif
56
Chris Allegretta6fe61492001-05-21 12:56:25 +000057#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +000058static int fill = 0; /* Fill - where to wrap lines, basically */
Chris Allegretta6fe61492001-05-21 12:56:25 +000059#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +000060
Chris Allegretta6df90f52002-07-19 01:08:59 +000061static struct termios oldterm; /* The user's original term settings */
Chris Allegretta88520c92001-05-05 17:45:54 +000062static struct sigaction act; /* For all our fun signal handlers */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000063
Chris Allegretta08020882001-01-29 23:37:54 +000064static sigjmp_buf jmpbuf; /* Used to return to mainloop after SIGWINCH */
65
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000066/* What we do when we're all set to exit */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +000067RETSIGTYPE finish(int sigage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000068{
Chris Allegretta5beed502003-01-05 20:41:21 +000069
70#ifndef NANO_SMALL
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{
Chris Allegretta908f7702003-01-15 11:18:58 +0000263 size_t allocsize = 1; /* space needed for help_text */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000264 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 "
Chris Allegretta37d594c2003-01-05 22:00:41 +0000278 "The previous search string will be shown in brackets after "
279 "the Search: prompt. Hitting Enter without entering any text "
280 "will perform the previous search.\n\n The following function "
281 "keys are available in Search mode:\n\n");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000282 else if (currshortcut == goto_list)
283 ptr = _("Go To Line Help Text\n\n "
284 "Enter the line number that you wish to go to and hit "
285 "Enter. If there are fewer lines of text than the "
286 "number you entered, you will be brought to the last line "
287 "of the file.\n\n The following function keys are "
288 "available in Go To Line mode:\n\n");
289 else if (currshortcut == insertfile_list)
290 ptr = _("Insert File Help Text\n\n "
291 "Type in the name of a file to be inserted into the current "
292 "file buffer at the current cursor location.\n\n "
293 "If you have compiled nano with multiple file buffer "
294 "support, and enable multiple buffers with the -F "
295 "or --multibuffer command line flags, the Meta-F toggle, or "
296 "a nanorc file, inserting a file will cause it to be "
297 "loaded into a separate buffer (use Meta-< and > to switch "
298 "between file buffers).\n\n If you need another blank "
299 "buffer, do not enter any filename, or type in a "
300 "nonexistent filename at the prompt and press "
301 "Enter.\n\n The following function keys are "
302 "available in Insert File mode:\n\n");
303 else if (currshortcut == writefile_list)
304 ptr = _("Write File Help Text\n\n "
305 "Type the name that you wish to save the current file "
306 "as and hit Enter to save the file.\n\n If you have "
307 "selected text with Ctrl-^, you will be prompted to "
308 "save only the selected portion to a separate file. To "
309 "reduce the chance of overwriting the current file with "
310 "just a portion of it, the current filename is not the "
311 "default in this mode.\n\n The following function keys "
312 "are available in Write File mode:\n\n");
313#ifndef DISABLE_BROWSER
314 else if (currshortcut == browser_list)
315 ptr = _("File Browser Help Text\n\n "
316 "The file browser is used to visually browse the "
317 "directory structure to select a file for reading "
318 "or writing. You may use the arrow keys or Page Up/"
319 "Down to browse through the files, and S or Enter to "
320 "choose the selected file or enter the selected "
321 "directory. To move up one level, select the directory "
322 "called \"..\" at the top of the file list.\n\n The "
323 "following function keys are available in the file "
324 "browser:\n\n");
325 else if (currshortcut == gotodir_list)
326 ptr = _("Browser Go To Directory Help Text\n\n "
327 "Enter the name of the directory you would like to "
328 "browse to.\n\n If tab completion has not been disabled, "
329 "you can use the TAB key to (attempt to) automatically "
330 "complete the directory name.\n\n The following function "
331 "keys are available in Browser Go To Directory mode:\n\n");
332#endif
333 else if (currshortcut == spell_list)
334 ptr = _("Spell Check Help Text\n\n "
335 "The spell checker checks the spelling of all text "
336 "in the current file. When an unknown word is "
337 "encountered, it is highlighted and a replacement can "
338 "be edited. It will then prompt to replace every "
339 "instance of the given misspelled word in the "
340 "current file.\n\n The following other functions are "
341 "available in Spell Check mode:\n\n");
342#ifndef NANO_SMALL
343 else if (currshortcut == extcmd_list)
344 ptr = _("External Command Help Text\n\n "
345 "This menu allows you to insert the output of a command "
346 "run by the shell into the current buffer (or a new "
347 "buffer in multibuffer mode).\n\n The following keys are "
348 "available in this mode:\n\n");
349#endif
350 else /* Default to the main help list */
351 ptr = _(" nano help text\n\n "
352 "The nano editor is designed to emulate the functionality and "
353 "ease-of-use of the UW Pico text editor. There are four main "
354 "sections of the editor: The top line shows the program "
355 "version, the current filename being edited, and whether "
356 "or not the file has been modified. Next is the main editor "
357 "window showing the file being edited. The status line is "
358 "the third line from the bottom and shows important messages. "
359 "The bottom two lines show the most commonly used shortcuts "
360 "in the editor.\n\n "
361 "The notation for shortcuts is as follows: Control-key "
362 "sequences are notated with a caret (^) symbol and are entered "
363 "with the Control (Ctrl) key. Escape-key sequences are notated "
364 "with the Meta (M) symbol and can be entered using either the "
365 "Esc, Alt or Meta key depending on your keyboard setup. The "
366 "following keystrokes are available in the main editor window. "
367 "Alternative keys are shown in parentheses:\n\n");
368
Chris Allegretta908f7702003-01-15 11:18:58 +0000369 allocsize += strlen(ptr);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000370
371 /* The space needed for the shortcut lists, at most COLS characters,
372 * plus '\n'. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000373 allocsize += (COLS + 1) * length_of_list(currshortcut);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000374
375#ifndef NANO_SMALL
376 /* If we're on the main list, we also count the toggle help text.
377 * Each line has "M-%c\t\t\t", which fills 24 columns, plus at most
378 * COLS - 24 characters, plus '\n'.*/
379 if (currshortcut == main_list)
380 for (t = toggles; t != NULL; t = t->next)
Chris Allegretta908f7702003-01-15 11:18:58 +0000381 allocsize += COLS - 17;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000382#endif /* !NANO_SMALL */
383
384 /* help_text has been freed and set to NULL unless the user resized
385 * while in the help screen. */
386 free(help_text);
387
388 /* Allocate space for the help text */
Chris Allegretta908f7702003-01-15 11:18:58 +0000389 help_text = charalloc(allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000390
391 /* Now add the text we want */
392 strcpy(help_text, ptr);
393 ptr = help_text + strlen(help_text);
394
395 /* Now add our shortcut info */
396 for (s = currshortcut; s != NULL; s = s->next) {
397 /* true if the character in s->altval is shown in first column */
398 int meta_shortcut = 0;
399
400 if (s->val > 0 && s->val < 32)
401 ptr += sprintf(ptr, "^%c", s->val + 64);
402#ifndef NANO_SMALL
403 else if (s->val == NANO_CONTROL_SPACE)
404 ptr += sprintf(ptr, "^%.6s", _("Space"));
405 else if (s->altval == NANO_ALT_SPACE) {
406 meta_shortcut = 1;
407 ptr += sprintf(ptr, "M-%.5s", _("Space"));
Chris Allegretta7662c862003-01-13 01:35:15 +0000408 } else if (s->val == KEY_UP)
409 ptr += sprintf(ptr, "%.2s", _("Up"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000410#endif
411 else if (s->altval > 0) {
412 meta_shortcut = 1;
413 ptr += sprintf(ptr, "M-%c", s->altval -
414 (('A' <= s->altval && s->altval <= 'Z') ||
415 'a' <= s->altval ? 32 : 0));
416 }
417 /* Hack */
418 else if (s->val >= 'a') {
419 meta_shortcut = 1;
420 ptr += sprintf(ptr, "M-%c", s->val - 32);
421 }
422
423 *(ptr++) = '\t';
424
425 if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64))
426 ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0);
427
428 *(ptr++) = '\t';
429
430 if (!meta_shortcut && s->altval > 0)
431 ptr += sprintf(ptr, "(M-%c)", s->altval -
432 (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval
433 ? 32 : 0));
434
435 *(ptr++) = '\t';
436
437 assert(s->help != NULL);
438 ptr += sprintf(ptr, "%.*s\n", COLS - 24, s->help);
439 }
440
441#ifndef NANO_SMALL
442 /* And the toggles... */
443 if (currshortcut == main_list)
444 for (t = toggles; t != NULL; t = t->next) {
445 ptr += sprintf(ptr, "M-%c\t\t\t", t->val - 32);
446 assert(t->desc != NULL);
447 ptr += sprintf(ptr, _("%.*s enable/disable\n"), COLS - 24, t->desc);
448 }
449#endif /* !NANO_SMALL */
450
451 /* If all went well, we didn't overwrite the allocated space for
452 help_text. */
Chris Allegretta908f7702003-01-15 11:18:58 +0000453 assert(strlen(help_text) < allocsize);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000454}
455#endif
456
457/* Create a new filestruct node. Note that we specifically do not set
458 * prevnode->next equal to the new line. */
459filestruct *make_new_node(filestruct *prevnode)
460{
461 filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
462
463 newnode->data = NULL;
464 newnode->prev = prevnode;
465 newnode->next = NULL;
466 newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1;
467
468 return newnode;
469}
470
David Lawrence Ramseyc5967552002-06-21 03:20:06 +0000471/* Make a copy of a node to a pointer (space will be malloc()ed). */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000472filestruct *copy_node(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000473{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000474 filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000475
Chris Allegretta6df90f52002-07-19 01:08:59 +0000476 assert(src != NULL);
477
Chris Allegretta88b09152001-05-17 11:35:43 +0000478 dst->data = charalloc(strlen(src->data) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000479 dst->next = src->next;
480 dst->prev = src->prev;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000481 strcpy(dst->data, src->data);
482 dst->lineno = src->lineno;
483
484 return dst;
485}
486
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000487/* Splice a node into an existing filestruct. */
488void splice_node(filestruct *begin, filestruct *newnode, filestruct *end)
489{
490 if (newnode != NULL) {
491 newnode->next = end;
492 newnode->prev = begin;
493 }
494 if (begin != NULL)
495 begin->next = newnode;
496 if (end != NULL)
497 end->prev = newnode;
498}
499
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000500/* Unlink a node from the rest of the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000501void unlink_node(const filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000502{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000503 assert(fileptr != NULL);
504
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000505 if (fileptr->prev != NULL)
506 fileptr->prev->next = fileptr->next;
507
508 if (fileptr->next != NULL)
509 fileptr->next->prev = fileptr->prev;
510}
511
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000512/* Delete a node from the filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000513void delete_node(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000514{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000515 if (fileptr != NULL) {
516 if (fileptr->data != NULL)
517 free(fileptr->data);
518 free(fileptr);
519 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000520}
521
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000522/* Okay, now let's duplicate a whole struct! */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000523filestruct *copy_filestruct(const filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000524{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000525 filestruct *head; /* copy of src, top of the copied list */
526 filestruct *prev; /* temp that traverses the list */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000527
Chris Allegretta6df90f52002-07-19 01:08:59 +0000528 assert(src != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000529
Chris Allegretta6df90f52002-07-19 01:08:59 +0000530 prev = copy_node(src);
531 prev->prev = NULL;
532 head = prev;
533 src = src->next;
534 while (src != NULL) {
535 prev->next = copy_node(src);
536 prev->next->prev = prev;
537 prev = prev->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000538
Chris Allegretta6df90f52002-07-19 01:08:59 +0000539 src = src->next;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000540 }
541
Chris Allegretta6df90f52002-07-19 01:08:59 +0000542 prev->next = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000543 return head;
544}
545
Chris Allegrettaf2387fb2002-04-10 02:31:20 +0000546/* Frees a filestruct. */
Chris Allegretta6df90f52002-07-19 01:08:59 +0000547void free_filestruct(filestruct *src)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000548{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000549 if (src != NULL) {
550 while (src->next != NULL) {
551 src = src->next;
552 delete_node(src->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000553#ifdef DEBUG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000554 fprintf(stderr, _("delete_node(): free'd a node, YAY!\n"));
555#endif
556 }
557 delete_node(src);
558#ifdef DEBUG
559 fprintf(stderr, _("delete_node(): free'd last node.\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000560#endif
561 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000562}
563
Chris Allegretta6df90f52002-07-19 01:08:59 +0000564void renumber_all(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000565{
566 filestruct *temp;
Chris Allegrettabef12972002-03-06 03:30:40 +0000567 int i = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000568
Chris Allegretta6df90f52002-07-19 01:08:59 +0000569 assert(fileage == NULL || fileage != fileage->next);
570 for (temp = fileage; temp != NULL; temp = temp->next)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000571 temp->lineno = i++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000572}
573
Chris Allegretta6df90f52002-07-19 01:08:59 +0000574void renumber(filestruct *fileptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000575{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000576 if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000577 renumber_all();
Chris Allegretta6df90f52002-07-19 01:08:59 +0000578 else {
579 int lineno = fileptr->prev->lineno;
580
581 assert(fileptr != fileptr->next);
582 for (; fileptr != NULL; fileptr = fileptr->next)
583 fileptr->lineno = ++lineno;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000584 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000585}
586
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000587/* Print one usage string to the screen, removes lots of duplicate
Chris Allegretta6df90f52002-07-19 01:08:59 +0000588 * strings to translate and takes out the parts that shouldn't be
589 * translatable (the flag names). */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000590void print1opt(const char *shortflag, const char *longflag,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000591 const char *desc)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000592{
593 printf(" %s\t", shortflag);
594 if (strlen(shortflag) < 8)
595 printf("\t");
596
597#ifdef HAVE_GETOPT_LONG
598 printf("%s\t", longflag);
599 if (strlen(longflag) < 8)
600 printf("\t\t");
601 else if (strlen(longflag) < 16)
602 printf("\t");
603#endif
604
605 printf("%s\n", desc);
606}
607
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000608void usage(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000609{
610#ifdef HAVE_GETOPT_LONG
Chris Allegretta6df90f52002-07-19 01:08:59 +0000611 printf(_("Usage: nano [+LINE] [GNU long option] [option] [file]\n\n"));
612 printf(_("Option\t\tLong option\t\tMeaning\n"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000613#else
Chris Allegretta6df90f52002-07-19 01:08:59 +0000614 printf(_("Usage: nano [+LINE] [option] [file]\n\n"));
615 printf(_("Option\t\tMeaning\n"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000616#endif /* HAVE_GETOPT_LONG */
617
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000618 print1opt("-h, -?", "--help", _("Show this message"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000619 print1opt(_("+LINE"), "", _("Start at line number LINE"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000620#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000621 print1opt("-B", "--backup", _("Backup existing files on save"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000622 print1opt("-D", "--dos", _("Write file in DOS format"));
Chris Allegretta7004c282001-09-22 00:42:10 +0000623#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +0000624#ifdef ENABLE_MULTIBUFFER
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000625 print1opt("-F", "--multibuffer", _("Enable multiple file buffers"));
Chris Allegretta355fbe52001-07-14 19:32:47 +0000626#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +0000627#ifdef ENABLE_NANORC
628 print1opt("-I", "--ignorercfiles", _("Don't look at nanorc files"));
629#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000630 print1opt("-K", "--keypad", _("Use alternate keypad routines"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000631#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000632 print1opt("-M", "--mac", _("Write file in Mac format"));
633 print1opt("-N", "--noconvert", _("Don't convert files from DOS/Mac format"));
Chris Allegretta8fa1e282001-09-22 04:20:25 +0000634#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000635#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +0000636 print1opt(_("-Q [str]"), _("--quotestr=[str]"), _("Quoting string, default \"> \""));
Chris Allegrettae4f940d2002-03-03 22:36:36 +0000637#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +0000638#ifdef HAVE_REGEX_H
639 print1opt("-R", "--regexp", _("Do regular expression searches"));
640#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000641#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000642 print1opt("-S", "--smooth", _("Smooth scrolling"));
Chris Allegretta3e3ae942001-09-22 19:02:04 +0000643#endif
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000644 print1opt(_("-T [num]"), _("--tabsize=[num]"), _("Set width of a tab to num"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000645 print1opt("-V", "--version", _("Print version information and exit"));
Chris Allegretta09900ff2002-05-04 04:23:30 +0000646#ifdef ENABLE_COLOR
647 print1opt(_("-Y [str]"), _("--syntax [str]"), _("Syntax definition to use"));
648#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000649 print1opt("-c", "--const", _("Constantly show cursor position"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000650#ifndef NANO_SMALL
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000651 print1opt("-i", "--autoindent", _("Automatically indent new lines"));
652 print1opt("-k", "--cut", _("Let ^K cut from cursor to end of line"));
Chris Allegrettad19e9912000-07-12 18:14:51 +0000653#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000654 print1opt("-l", "--nofollow", _("Don't follow symbolic links, overwrite"));
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000655#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000656 print1opt("-m", "--mouse", _("Enable mouse"));
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000657#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000658#ifndef DISABLE_OPERATINGDIR
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000659 print1opt(_("-o [dir]"), _("--operatingdir=[dir]"), _("Set operating directory"));
Chris Allegrettae1f14522001-09-19 03:19:43 +0000660#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +0000661 print1opt(_("-p"), _("--preserve"), _("Preserve XON (^Q) and XOFF (^S) keys"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000662#ifndef DISABLE_WRAPJUSTIFY
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000663 print1opt(_("-r [#cols]"), _("--fill=[#cols]"), _("Set fill cols to (wrap lines at) #cols"));
Chris Allegretta6fe61492001-05-21 12:56:25 +0000664#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000665#ifndef DISABLE_SPELLER
Chris Allegrettad1ec7b02002-03-09 20:05:26 +0000666 print1opt(_("-s [prog]"), _("--speller=[prog]"), _("Enable alternate speller"));
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000667#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000668 print1opt("-t", "--tempfile", _("Auto save on exit, don't prompt"));
669 print1opt("-v", "--view", _("View (read only) mode"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000670#ifndef DISABLE_WRAPPING
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000671 print1opt("-w", "--nowrap", _("Don't wrap long lines"));
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000672#endif
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000673 print1opt("-x", "--nohelp", _("Don't show help window"));
674 print1opt("-z", "--suspend", _("Enable suspend"));
Chris Allegretta6df90f52002-07-19 01:08:59 +0000675
676 /* this is a special case */
677 printf(" %s\t\t\t%s\n","-a, -b, -e, -f, -g, -j", _("(ignored, for Pico compatibility)"));
Chris Allegretta3fc5d572002-03-09 18:51:58 +0000678
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000679 exit(0);
680}
681
David Lawrence Ramsey0341b582002-08-21 16:10:37 +0000682void version(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000683{
Chris Allegrettac46dd812001-02-14 14:28:27 +0000684 printf(_(" GNU nano version %s (compiled %s, %s)\n"),
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000685 VERSION, __TIME__, __DATE__);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000686 printf(_
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000687 (" Email: nano@nano-editor.org Web: http://www.nano-editor.org/"));
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000688 printf(_("\n Compiled options:"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000689
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000690#ifdef DEBUG
691 printf(" --enable-debug");
692#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000693#ifdef NANO_EXTRA
694 printf(" --enable-extra");
Jordi Mallach5285ca92002-01-17 12:40:33 +0000695#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +0000696#ifdef NANO_SMALL
697 printf(" --enable-tiny");
698#else
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000699#ifdef DISABLE_BROWSER
Chris Allegretta6636dc32001-01-05 05:41:07 +0000700 printf(" --disable-browser");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000701#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000702#ifdef DISABLE_HELP
703 printf(" --disable-help");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000704#endif
705#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +0000706 printf(" --disable-justify");
Chris Allegretta6b58acd2001-04-12 03:01:53 +0000707#endif
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000708#if defined(DISABLE_MOUSE) || !defined(NCURSES_MOUSE_VERSION)
Chris Allegretta84de5522001-04-12 14:51:48 +0000709 printf(" --disable-mouse");
Chris Allegrettab7d00ef2000-12-18 05:36:51 +0000710#endif
Chris Allegretta2a15c582002-10-25 01:51:13 +0000711#ifndef ENABLE_NLS
712 printf(" --disable-nls");
713#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +0000714#ifdef DISABLE_OPERATINGDIR
715 printf(" --disable-operatingdir");
716#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000717#ifdef DISABLE_SPELLER
718 printf(" --disable-speller");
719#endif
720#ifdef DISABLE_TABCOMP
721 printf(" --disable-tabcomp");
722#endif
Chris Allegretta84de5522001-04-12 14:51:48 +0000723#endif /* NANO_SMALL */
Chris Allegrettacef7fbb2001-04-02 05:36:08 +0000724#ifdef DISABLE_WRAPPING
725 printf(" --disable-wrapping");
726#endif
David Lawrence Ramseydc60b722002-10-25 16:08:53 +0000727#ifdef DISABLE_ROOTWRAP
728 printf(" --disable-wrapping-as-root");
729#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000730#ifdef ENABLE_COLOR
731 printf(" --enable-color");
732#endif
733#ifdef ENABLE_MULTIBUFFER
734 printf(" --enable-multibuffer");
735#endif
736#ifdef ENABLE_NANORC
737 printf(" --enable-nanorc");
738#endif
Chris Allegretta8a0de3b2000-11-24 20:45:14 +0000739#ifdef USE_SLANG
740 printf(" --with-slang");
741#endif
742 printf("\n");
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000743}
744
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000745/* Stuff we do when we abort from programs and want to clean up the
746 * screen. This doesn't do much right now. */
747void do_early_abort(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000748{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000749 blank_statusbar_refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000750}
751
752int no_help(void)
753{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000754 return ISSET(NO_HELP) ? 2 : 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000755}
756
Chris Allegrettad865da12002-07-29 23:46:38 +0000757#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL)
Chris Allegrettaff269f82000-12-01 18:46:01 +0000758void nano_disabled_msg(void)
759{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000760 statusbar(_("Sorry, support for this function has been disabled"));
Chris Allegrettaff269f82000-12-01 18:46:01 +0000761}
Chris Allegretta4eb7aa02000-12-01 18:57:11 +0000762#endif
Chris Allegrettaff269f82000-12-01 18:46:01 +0000763
Chris Allegretta6cd143d2003-01-05 23:35:44 +0000764void do_preserve_msg(void)
765{
Chris Allegretta7662c862003-01-13 01:35:15 +0000766 fprintf(stderr, _("\nThe -p flag now invokes the Pico \"preserve\" flag. The Pico\n"));
767 fprintf(stderr, _("compatibility flag has been removed as nano is now fully Pico\n"));
768 fprintf(stderr, _("compatible. Please see the nano FAQ for more info on this change...\n\n"));
Chris Allegretta6cd143d2003-01-05 23:35:44 +0000769 fprintf(stderr, _("Press return to continue\n"));
770 while (getchar() != '\n');
771}
772
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000773#ifndef NANO_SMALL
774static int pid; /* This is the PID of the newly forked process
775 * below. It must be global since the signal
776 * handler needs it. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000777RETSIGTYPE cancel_fork(int signal)
778{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000779 if (kill(pid, SIGKILL) == -1)
780 nperror("kill");
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000781}
782
783int open_pipe(const char *command)
784{
785 int fd[2];
786 FILE *f;
787 struct sigaction oldaction, newaction;
788 /* original and temporary handlers for SIGINT */
789#ifdef _POSIX_VDISABLE
790 struct termios term, newterm;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000791#endif /* _POSIX_VDISABLE */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000792 int cancel_sigs = 0;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000793 /* cancel_sigs == 1 means that sigaction() failed without changing
794 * the signal handlers. cancel_sigs == 2 means the signal handler
795 * was changed, but the tcsetattr didn't succeed.
796 *
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000797 * I use this variable since it is important to put things back when
798 * we finish, even if we get errors. */
799
800 /* Make our pipes. */
801
802 if (pipe(fd) == -1) {
803 statusbar(_("Could not pipe"));
804 return 1;
805 }
806
807 /* Fork a child. */
808
809 if ((pid = fork()) == 0) {
810 close(fd[0]);
811 dup2(fd[1], fileno(stdout));
812 dup2(fd[1], fileno(stderr));
813 /* If execl() returns at all, there was an error. */
814
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000815 execl("/bin/sh", "sh", "-c", command, 0);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000816 exit(0);
817 }
818
819 /* Else continue as parent. */
820
821 close(fd[1]);
822
823 if (pid == -1) {
824 close(fd[0]);
825 statusbar(_("Could not fork"));
826 return 1;
827 }
828
829 /* Before we start reading the forked command's output, we set
830 * things up so that ^C will cancel the new process. */
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000831 if (sigaction(SIGINT, NULL, &newaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000832 cancel_sigs = 1;
833 nperror("sigaction");
834 } else {
835 newaction.sa_handler = cancel_fork;
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000836 if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000837 cancel_sigs = 1;
838 nperror("sigaction");
839 }
840 }
841 /* Note that now oldaction is the previous SIGINT signal handler,
842 * to be restored later. */
843
844 /* See if the platform supports disabling individual control
845 * characters. */
846#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000847 if (cancel_sigs == 0 && tcgetattr(0, &term) == -1) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000848 cancel_sigs = 2;
849 nperror("tcgetattr");
850 }
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000851 if (cancel_sigs == 0) {
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000852 newterm = term;
853 /* Grab oldterm's VINTR key :-) */
854 newterm.c_cc[VINTR] = oldterm.c_cc[VINTR];
855 if (tcsetattr(0, TCSANOW, &newterm) == -1) {
856 cancel_sigs = 2;
857 nperror("tcsetattr");
858 }
859 }
860#endif /* _POSIX_VDISABLE */
861
862 f = fdopen(fd[0], "rb");
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000863 if (f == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000864 nperror("fdopen");
865
866 read_file(f, "stdin", 0);
867 /* if multibuffer mode is on, we could be here in view mode; if so,
868 don't set the modification flag */
869 if (!ISSET(VIEW_MODE))
870 set_modified();
871
872 if (wait(NULL) == -1)
873 nperror("wait");
874
875#ifdef _POSIX_VDISABLE
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000876 if (cancel_sigs == 0 && tcsetattr(0, TCSANOW, &term) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000877 nperror("tcsetattr");
878#endif /* _POSIX_VDISABLE */
879
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +0000880 if (cancel_sigs != 1 && sigaction(SIGINT, &oldaction, NULL) == -1)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000881 nperror("sigaction");
882
883 return 0;
884}
885#endif /* NANO_SMALL */
886
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +0000887#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000888void do_mouse(void)
889{
890 MEVENT mevent;
891 int currslen;
892 const shortcut *s = currshortcut;
893
894 if (getmouse(&mevent) == ERR)
895 return;
896
897 /* If mouse not in edit or bottom window, return */
898 if (wenclose(edit, mevent.y, mevent.x)) {
899
900 /* Don't let people screw with the marker when they're in a
901 * subfunction. */
902 if (currshortcut != main_list)
903 return;
904
905 /* Subtract out size of topwin. Perhaps we need a constant
906 * somewhere? */
907 mevent.y -= 2;
908
909 /* Selecting where the cursor is sets the mark. Selecting
910 * beyond the line length with the cursor at the end of the line
911 * sets the mark as well. */
912 if ((mevent.y == current_y) &&
913 ((mevent.x == current_x) || (current_x == strlen(current->data)
914 && (mevent.x >
915 strlen(current->data))))) {
916 if (ISSET(VIEW_MODE)) {
917 print_view_warning();
918 return;
919 }
920 do_mark();
921 } else if (mevent.y > current_y) {
922 while (mevent.y > current_y) {
923 if (current->next != NULL)
924 current = current->next;
925 else
926 break;
927 current_y++;
928 }
929 } else if (mevent.y < current_y) {
930 while (mevent.y < current_y) {
931 if (current->prev != NULL)
932 current = current->prev;
933 else
934 break;
935 current_y--;
936 }
937 }
938 current_x = actual_x(current, mevent.x);
939 placewewant = current_x;
940 update_cursor();
941 edit_refresh();
942 } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) {
943 int i, k;
944
945 if (currshortcut == main_list)
946 currslen = MAIN_VISIBLE;
947 else
948 currslen = length_of_list(currshortcut);
949
950 if (currslen < 2)
951 k = COLS / 6;
952 else
953 k = COLS / ((currslen + (currslen %2)) / 2);
954
955 /* Determine what shortcut list was clicked */
956 mevent.y -= (editwinrows + 3);
957
958 if (mevent.y < 0) /* They clicked on the statusbar */
959 return;
960
961 /* Don't select stuff beyond list length */
962 if (mevent.x / k >= currslen)
963 return;
964
965 for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++)
966 s = s->next;
967
968 /* And ungetch that value */
969 ungetch(s->val);
970
971 /* And if it's an alt-key sequence, we should probably send alt
972 too ;-) */
973 if (s->val >= 'a' && s->val <= 'z')
974 ungetch(27);
975 }
976}
977#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +0000978
Chris Allegretta6df90f52002-07-19 01:08:59 +0000979/* The user typed a printable character; add it to the edit buffer. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000980void do_char(char ch)
981{
Chris Allegretta6df90f52002-07-19 01:08:59 +0000982 size_t current_len = strlen(current->data);
983#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
984 int refresh = 0;
985 /* Do we have to run edit_refresh(), or can we get away with
986 * update_line()? */
987#endif
988
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000989 /* magic-line: when a character is inserted on the current magic line,
990 * it means we need a new one! */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000991 if (filebot == current && current->data[0] == '\0') {
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000992 new_magicline();
Chris Allegretta28a0f892000-07-05 22:47:54 +0000993 fix_editbot();
Robert Siemborski63b3d7e2000-07-04 22:15:39 +0000994 }
995
Chris Allegretta6df90f52002-07-19 01:08:59 +0000996 /* more dangerousness fun =) */
997 current->data = nrealloc(current->data, current_len + 2);
998 assert(current_x <= current_len);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000999 memmove(&current->data[current_x + 1],
1000 &current->data[current_x],
Chris Allegretta6df90f52002-07-19 01:08:59 +00001001 current_len - current_x + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001002 current->data[current_x] = ch;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001003 totsize++;
1004 set_modified();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001005
Chris Allegretta6df90f52002-07-19 01:08:59 +00001006#ifndef NANO_SMALL
1007 /* note that current_x has not yet been incremented */
1008 if (current == mark_beginbuf && current_x < mark_beginx)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001009 mark_beginx++;
Chris Allegrettab2cd10d2002-01-20 00:54:42 +00001010#endif
1011
Chris Allegretta6df90f52002-07-19 01:08:59 +00001012 do_right();
1013
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001014#ifndef DISABLE_WRAPPING
Chris Allegrettadffa2072002-07-24 01:02:26 +00001015 if (!ISSET(NO_WRAP) && ch != '\t')
Chris Allegretta6df90f52002-07-19 01:08:59 +00001016 refresh = do_wrap(current);
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001017#endif
1018
Chris Allegretta6df90f52002-07-19 01:08:59 +00001019#ifdef ENABLE_COLOR
1020 refresh = 1;
1021#endif
1022
1023#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR)
1024 if (refresh)
1025 edit_refresh();
1026#endif
1027
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001028 check_statblank();
1029 UNSET(KEEP_CUTBUFFER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001030}
1031
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001032int do_backspace(void)
1033{
1034 int refresh = 0;
1035 if (current_x > 0) {
1036 assert(current_x <= strlen(current->data));
1037 /* Let's get dangerous */
1038 memmove(&current->data[current_x - 1], &current->data[current_x],
1039 strlen(current->data) - current_x + 1);
1040#ifdef DEBUG
1041 fprintf(stderr, _("current->data now = \"%s\"\n"), current->data);
1042#endif
1043 align(&current->data);
1044#ifndef NANO_SMALL
1045 if (current_x <= mark_beginx && mark_beginbuf == current)
1046 mark_beginx--;
1047#endif
1048 do_left();
1049#ifdef ENABLE_COLOR
1050 refresh = 1;
1051#endif
1052 } else {
1053 filestruct *previous;
1054 const filestruct *tmp;
1055
1056 if (current == fileage)
1057 return 0; /* Can't delete past top of file */
1058
1059 previous = current->prev;
1060 current_x = strlen(previous->data);
1061 placewewant = strlenpt(previous->data);
1062#ifndef NANO_SMALL
1063 if (current == mark_beginbuf) {
1064 mark_beginx += current_x;
1065 mark_beginbuf = previous;
1066 }
1067#endif
1068 previous->data = nrealloc(previous->data,
1069 current_x + strlen(current->data) + 1);
1070 strcpy(previous->data + current_x, current->data);
1071
1072 unlink_node(current);
1073 delete_node(current);
1074 tmp = current;
1075 current = (previous->next ? previous->next : previous);
1076 renumber(current);
1077 /* We had to renumber before doing update_line. */
1078 if (tmp == edittop)
1079 page_up();
1080
1081 /* Ooops, sanity check */
1082 if (tmp == filebot) {
1083 filebot = current;
1084 editbot = current;
1085
1086 /* Recreate the magic line if we're deleting it AND if the
1087 line we're on now is NOT blank. if it is blank we
1088 can just use IT for the magic line. This is how Pico
1089 appears to do it, in any case. */
1090 if (current->data[0] != '\0') {
1091 new_magicline();
1092 fix_editbot();
1093 }
1094 }
1095
1096 current = previous;
1097 if (current_y > 0)
1098 current_y--;
1099 totlines--;
1100#ifdef DEBUG
1101 fprintf(stderr, _("After, data = \"%s\"\n"), current->data);
1102#endif
1103 UNSET(KEEP_CUTBUFFER);
1104 refresh = 1;
1105 }
1106
1107 totsize--;
1108 set_modified();
1109 if (refresh)
1110 edit_refresh();
1111 return 1;
1112}
1113
1114int do_delete(void)
1115{
1116 int refresh = 0;
1117
1118 /* blbf -> blank line before filebot (see below) */
1119 int blbf = 0;
1120
1121 if (current->next == filebot && current->data[0] == '\0')
1122 blbf = 1;
1123
1124 placewewant = xplustabs();
1125
1126 if (current_x != strlen(current->data)) {
1127 /* Let's get dangerous */
1128 memmove(&current->data[current_x], &current->data[current_x + 1],
1129 strlen(current->data) - current_x);
1130
1131 align(&current->data);
1132#ifdef ENABLE_COLOR
1133 refresh = 1;
1134#endif
1135 } else if (current->next != NULL && (current->next != filebot || blbf)) {
1136 /* We can delete the line before filebot only if it is blank: it
1137 becomes the new magic line then. */
1138
1139 filestruct *foo;
1140
1141 current->data = nrealloc(current->data,
1142 strlen(current->data) +
1143 strlen(current->next->data) + 1);
1144 strcat(current->data, current->next->data);
1145
1146 foo = current->next;
1147 if (filebot == foo) {
1148 filebot = current;
1149 editbot = current;
1150 }
1151
1152 unlink_node(foo);
1153 delete_node(foo);
1154 renumber(current);
1155 totlines--;
1156 refresh = 1;
1157 } else
1158 return 0;
1159
1160 totsize--;
1161 set_modified();
1162 UNSET(KEEP_CUTBUFFER);
1163 update_line(current, current_x);
1164 if (refresh)
1165 edit_refresh();
1166 return 1;
1167}
1168
1169int do_tab(void)
1170{
1171 do_char('\t');
1172 return 1;
1173}
1174
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001175/* Someone hits return *gasp!* */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001176int do_enter(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001177{
Chris Allegrettae3167732001-03-18 16:59:34 +00001178 filestruct *newnode;
Chris Allegretta68532c32001-09-17 13:49:33 +00001179 char *tmp;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001180
Chris Allegretta6df90f52002-07-19 01:08:59 +00001181 newnode = make_new_node(current);
1182 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001183 tmp = &current->data[current_x];
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001184
Chris Allegrettaff989832001-09-17 13:48:00 +00001185#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001186 /* Do auto-indenting, like the neolithic Turbo Pascal editor. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001187 if (ISSET(AUTOINDENT)) {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001188 int extra = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001189 const char *spc = current->data;
1190
1191 while (*spc == ' ' || *spc == '\t') {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001192 extra++;
1193 spc++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001194 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001195 /* If current_x < extra, then we are breaking the line in the
1196 * indentation. Autoindenting should add only current_x
1197 * characters of indentation. */
Chris Allegrettadab017e2002-04-23 10:56:06 +00001198 if (current_x < extra)
1199 extra = current_x;
1200 else
1201 current_x = extra;
1202 totsize += extra;
1203
1204 newnode->data = charalloc(strlen(tmp) + extra + 1);
1205 strncpy(newnode->data, current->data, extra);
1206 strcpy(&newnode->data[extra], tmp);
Chris Allegrettaff989832001-09-17 13:48:00 +00001207 } else
1208#endif
1209 {
Chris Allegrettadab017e2002-04-23 10:56:06 +00001210 current_x = 0;
Chris Allegretta88b09152001-05-17 11:35:43 +00001211 newnode->data = charalloc(strlen(tmp) + 1);
Chris Allegrettae3167732001-03-18 16:59:34 +00001212 strcpy(newnode->data, tmp);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001213 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001214 *tmp = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001215
Chris Allegretta6df90f52002-07-19 01:08:59 +00001216 if (current->next == NULL) {
Chris Allegrettae3167732001-03-18 16:59:34 +00001217 filebot = newnode;
1218 editbot = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001219 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001220 splice_node(current, newnode, current->next);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001221
1222 totsize++;
1223 renumber(current);
Chris Allegrettae3167732001-03-18 16:59:34 +00001224 current = newnode;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001225 align(&current->data);
1226
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001227 /* The logic here is as follows:
1228 * -> If we are at the bottom of the buffer, we want to recenter
Chris Allegretta88520c92001-05-05 17:45:54 +00001229 * (read: rebuild) the screen and forcibly move the cursor.
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001230 * -> otherwise, we want simply to redraw the screen and update
1231 * where we think the cursor is.
1232 */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001233 if (current_y == editwinrows - 1) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001234#ifndef NANO_SMALL
1235 if (ISSET(SMOOTHSCROLL))
1236 edit_update(current, NONE);
1237 else
1238#endif
1239 edit_update(current, CENTER);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00001240 reset_cursor();
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001241 } else {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001242 current_y++;
Robert Siemborskidd53ec22000-07-04 02:35:19 +00001243 edit_refresh();
1244 update_cursor();
1245 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001246
1247 totlines++;
1248 set_modified();
1249
Chris Allegrettab0ae3932000-06-15 23:39:14 +00001250 placewewant = xplustabs();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001251 return 1;
1252}
1253
Chris Allegrettaad3f4782001-10-02 03:54:13 +00001254#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001255int do_next_word(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001256{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001257 filestruct *old = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001258
Chris Allegretta6df90f52002-07-19 01:08:59 +00001259 assert(current != NULL && current->data != NULL);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001260
Chris Allegretta6df90f52002-07-19 01:08:59 +00001261 /* Skip letters in this word first. */
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 for (; current != NULL; current = current->next) {
1267 while (current->data[current_x] != '\0' &&
1268 !isalnum((int)current->data[current_x]))
1269 current_x++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001270
Chris Allegretta6df90f52002-07-19 01:08:59 +00001271 if (current->data[current_x] != '\0')
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001272 break;
1273
Chris Allegretta6df90f52002-07-19 01:08:59 +00001274 current_x = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001275 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00001276 if (current == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001277 current = filebot;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001278
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001279 placewewant = xplustabs();
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001280
Chris Allegrettad865da12002-07-29 23:46:38 +00001281 if (current->lineno >= editbot->lineno) {
1282 /* If we're on the last line, don't center the screen. */
1283 if (current->lineno == filebot->lineno)
1284 edit_refresh();
1285 else
1286 edit_update(current, CENTER);
1287 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001288 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001289 /* If we've jumped lines, refresh the old line. We can't just
1290 use current->prev here, because we may have skipped over some
1291 blank lines, in which case the previous line is the wrong
1292 one. */
1293 if (current != old) {
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001294 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001295 /* If the mark was set, then the lines between old and
1296 current have to be updated too. */
1297 if (ISSET(MARK_ISSET)) {
1298 while (old->next != current) {
1299 old = old->next;
1300 update_line(old, 0);
1301 }
1302 }
1303 }
Chris Allegretta9e2934f2000-12-01 23:49:48 +00001304 update_line(current, current_x);
1305 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001306 return 0;
1307}
1308
Chris Allegretta6df90f52002-07-19 01:08:59 +00001309/* The same thing for backwards. */
1310int do_prev_word(void)
Chris Allegretta76e291b2001-10-14 19:05:10 +00001311{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001312 filestruct *old = current;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001313
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001314 assert(current != NULL && current->data != NULL);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001315
Chris Allegretta6df90f52002-07-19 01:08:59 +00001316 /* Skip letters in this word first. */
1317 while (current_x >= 0 && isalnum((int)current->data[current_x]))
1318 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001319
Chris Allegretta6df90f52002-07-19 01:08:59 +00001320 for (; current != NULL; current = current->prev) {
1321 while (current_x >= 0 && !isalnum((int)current->data[current_x]))
1322 current_x--;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001323
Chris Allegretta6df90f52002-07-19 01:08:59 +00001324 if (current_x >= 0)
1325 break;
Chris Allegretta76e291b2001-10-14 19:05:10 +00001326
Chris Allegretta6df90f52002-07-19 01:08:59 +00001327 if (current->prev != NULL)
1328 current_x = strlen(current->prev->data);
Chris Allegretta76e291b2001-10-14 19:05:10 +00001329 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001330
Chris Allegretta6df90f52002-07-19 01:08:59 +00001331 if (current != NULL) {
1332 while (current_x > 0 && isalnum((int)current->data[current_x - 1]))
1333 current_x--;
1334 } else {
1335 current = fileage;
1336 current_x = 0;
1337 }
1338
Chris Allegretta76e291b2001-10-14 19:05:10 +00001339 placewewant = xplustabs();
1340
Chris Allegrettad865da12002-07-29 23:46:38 +00001341 if (current->lineno <= edittop->lineno) {
1342 /* If we're on the first line, don't center the screen. */
1343 if (current->lineno == fileage->lineno)
1344 edit_refresh();
1345 else
1346 edit_update(current, CENTER);
1347 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001348 else {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001349 /* If we've jumped lines, refresh the old line. We can't just
1350 use current->prev here, because we may have skipped over some
1351 blank lines, in which case the previous line is the wrong
1352 one. */
1353 if (current != old) {
Chris Allegretta76e291b2001-10-14 19:05:10 +00001354 update_line(old, 0);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001355 /* If the mark was set, then the lines between old and
1356 current have to be updated too. */
1357 if (ISSET(MARK_ISSET)) {
1358 while (old->prev != current) {
1359 old = old->prev;
1360 update_line(old, 0);
1361 }
1362 }
1363 }
Chris Allegretta76e291b2001-10-14 19:05:10 +00001364 update_line(current, current_x);
1365 }
Chris Allegretta6232d662002-05-12 19:52:15 +00001366 return 0;
1367}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001368#endif /* !NANO_SMALL */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001369
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001370int do_mark(void)
1371{
1372#ifdef NANO_SMALL
1373 nano_disabled_msg();
1374#else
1375 if (!ISSET(MARK_ISSET)) {
1376 statusbar(_("Mark Set"));
1377 SET(MARK_ISSET);
1378 mark_beginbuf = current;
1379 mark_beginx = current_x;
1380 } else {
1381 statusbar(_("Mark UNset"));
1382 UNSET(MARK_ISSET);
1383 edit_refresh();
1384 }
1385#endif
1386 return 1;
1387}
1388
1389void wrap_reset(void)
1390{
1391 UNSET(SAMELINEWRAP);
1392}
1393
Chris Allegrettacef7fbb2001-04-02 05:36:08 +00001394#ifndef DISABLE_WRAPPING
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001395/* We wrap the given line. Precondition: we assume the cursor has been
Chris Allegretta6df90f52002-07-19 01:08:59 +00001396 * moved forward since the last typed character. Return value:
1397 * whether we wrapped. */
1398int do_wrap(filestruct *inptr)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001399{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001400 size_t len = strlen(inptr->data); /* length of the line we wrap */
1401 int i = 0; /* generic loop variable */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001402 int wrap_loc = -1; /* index of inptr->data where we wrap */
1403 int word_back = -1;
1404#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001405 const char *indentation = NULL;
1406 /* indentation to prepend to the new line */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001407 int indent_len = 0; /* strlen(indentation) */
1408#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001409 const char *after_break; /* text after the wrap point */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001410 int after_break_len; /* strlen(after_break) */
1411 int wrapping = 0; /* do we prepend to the next line? */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001412 const char *wrap_line = NULL;
1413 /* the next line, minus indentation */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001414 int wrap_line_len = 0; /* strlen(wrap_line) */
1415 char *newline = NULL; /* the line we create */
1416 int new_line_len = 0; /* eventual length of newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001417
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001418/* There are three steps. First, we decide where to wrap. Then, we
1419 * create the new wrap line. Finally, we clean up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001420
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001421/* Step 1, finding where to wrap. We are going to add a new-line
1422 * after a white-space character. In this step, we set wrap_loc as the
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001423 * location of this replacement.
1424 *
1425 * Where should we break the line? We need the last "legal wrap point"
1426 * such that the last word before it ended at or before fill. If there
1427 * is no such point, we settle for the first legal wrap point.
1428 *
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001429 * A "legal wrap point" is a white-space character that is not followed by
1430 * white-space.
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001431 *
1432 * If there is no legal wrap point or we found the last character of the
1433 * line, we should return without wrapping.
1434 *
1435 * Note that the initial indentation does not count as a legal wrap
1436 * point if we are going to auto-indent!
1437 *
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001438 * Note that the code below could be optimised, by not calling strnlenpt()
1439 * so often. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001440
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001441#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001442 if (ISSET(AUTOINDENT))
1443 i = indent_length(inptr->data);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001444#endif
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001445 wrap_line = inptr->data + i;
1446 for(; i < len; i++, wrap_line++) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001447 /* record where the last word ended */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001448 if (*wrap_line != ' ' && *wrap_line != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001449 word_back = i;
1450 /* if we have found a "legal wrap point" and the current word
1451 * extends too far, then we stop */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001452 if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill)
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001453 break;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001454 /* we record the latest "legal wrap point" */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001455 if (word_back != i && wrap_line[1] != ' ' && wrap_line[1] != '\t')
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001456 wrap_loc = i;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001457 }
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001458 if (wrap_loc < 0 || i == len)
Chris Allegretta6df90f52002-07-19 01:08:59 +00001459 return 0;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001460
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001461/* Step 2, making the new wrap line. It will consist of indentation +
1462 * after_break + " " + wrap_line (although indentation and wrap_line are
1463 * conditional on flags and #defines). */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001464
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001465 /* after_break is the text that will be moved to the next line. */
1466 after_break = inptr->data + wrap_loc + 1;
1467 after_break_len = len - wrap_loc - 1;
1468 assert(after_break_len == strlen(after_break));
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001469
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001470 /* new_line_len will later be increased by the lengths of indentation
1471 * and wrap_line. */
1472 new_line_len = after_break_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001473
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001474 /* We prepend the wrapped text to the next line, if the flag is set,
1475 * and there is a next line, and prepending would not make the line
1476 * too long. */
Adam Rogoyski0223d6f2000-06-17 20:36:35 +00001477 if (ISSET(SAMELINEWRAP) && inptr->next) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001478 wrap_line = inptr->next->data;
1479 wrap_line_len = strlen(wrap_line);
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001480
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001481 /* +1 for the space between after_break and wrap_line */
1482 if ((new_line_len + 1 + wrap_line_len) <= fill) {
1483 wrapping = 1;
1484 new_line_len += (1 + wrap_line_len);
1485 }
1486 }
Chris Allegretta56214c62001-09-27 02:46:53 +00001487
Chris Allegrettaff989832001-09-17 13:48:00 +00001488#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001489 if (ISSET(AUTOINDENT)) {
Chris Allegretta81dea022002-09-21 02:19:45 +00001490 /* Indentation comes from the next line if wrapping, else from
1491 * this line. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001492 indentation = (wrapping ? wrap_line : inptr->data);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001493 indent_len = indent_length(indentation);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001494 if (wrapping)
Chris Allegretta81dea022002-09-21 02:19:45 +00001495 /* The wrap_line text should not duplicate indentation.
1496 * Note in this case we need not increase new_line_len. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001497 wrap_line += indent_len;
1498 else
1499 new_line_len += indent_len;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001500 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001501#endif
Adam Rogoyski1e9183f2001-03-13 18:36:03 +00001502
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001503 /* Now we allocate the new line and copy into it. */
1504 newline = charalloc(new_line_len + 1); /* +1 for \0 */
1505 *newline = '\0';
1506
1507#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001508 if (ISSET(AUTOINDENT)) {
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001509 strncpy(newline, indentation, indent_len);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001510 newline[indent_len] = '\0';
1511 }
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001512#endif
1513 strcat(newline, after_break);
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001514 /* We end the old line after wrap_loc. Note this does not eat the
Chris Allegretta81dea022002-09-21 02:19:45 +00001515 * space. */
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001516 null_at(&inptr->data, wrap_loc + 1);
1517 totsize++;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001518 if (wrapping) {
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001519 /* In this case, totsize increases by 1 since we add a space
Chris Allegretta81dea022002-09-21 02:19:45 +00001520 * between after_break and wrap_line. If the line already ends
Chris Allegretta43000922002-09-21 15:41:33 +00001521 * in a tab or a space, we don't add a space and decrement
1522 * totsize to account for that. */
David Lawrence Ramsey7c4222c2002-09-26 22:49:56 +00001523 if (!isspace(newline[strlen(newline) - 1]))
Chris Allegretta81dea022002-09-21 02:19:45 +00001524 strcat(newline, " ");
1525 else
1526 totsize--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001527 strcat(newline, wrap_line);
1528 free(inptr->next->data);
1529 inptr->next->data = newline;
1530 } else {
1531 filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct));
Chris Allegretta6df90f52002-07-19 01:08:59 +00001532
Chris Allegretta67ca2aa2002-09-19 23:19:34 +00001533 /* In this case, the file size changes by +1 for the new line, and
Chris Allegretta81dea022002-09-21 02:19:45 +00001534 * +indent_len for the new indentation. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001535#ifndef NANO_SMALL
1536 totsize += indent_len;
1537#endif
1538 totlines++;
1539 temp->data = newline;
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001540 temp->prev = inptr;
1541 temp->next = inptr->next;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001542 temp->prev->next = temp;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001543 /* If temp->next is NULL, then temp is the last line of the
1544 * file, so we must set filebot. */
1545 if (temp->next != NULL)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001546 temp->next->prev = temp;
1547 else
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001548 filebot = temp;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001549 }
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001550
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001551/* Step 3, clean up. Here we reposition the cursor and mark, and do some
1552 * other sundry things. */
1553
1554 /* later wraps of this line will be prepended to the next line. */
1555 SET(SAMELINEWRAP);
1556
1557 /* Each line knows its line number. We recalculate these if we
1558 * inserted a new line. */
1559 if (!wrapping)
1560 renumber(inptr);
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001561
Chris Allegretta6df90f52002-07-19 01:08:59 +00001562 /* If the cursor was after the break point, we must move it. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001563 if (current_x > wrap_loc) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00001564 current = current->next;
1565 current_x -=
Chris Allegrettaff989832001-09-17 13:48:00 +00001566#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00001567 -indent_len +
Chris Allegrettaff989832001-09-17 13:48:00 +00001568#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00001569 wrap_loc + 1;
1570 wrap_reset();
1571 placewewant = xplustabs();
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001572 }
1573
Chris Allegretta6df90f52002-07-19 01:08:59 +00001574#ifndef NANO_SMALL
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001575 /* If the mark was on this line after the wrap point, we move it down.
Chris Allegretta6df90f52002-07-19 01:08:59 +00001576 * If it was on the next line and we wrapped, we must move it
1577 * right. */
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001578 if (mark_beginbuf == inptr && mark_beginx > wrap_loc) {
1579 mark_beginbuf = inptr->next;
Chris Allegrettadffa2072002-07-24 01:02:26 +00001580 mark_beginx -= wrap_loc - indent_len + 1;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001581 } else if (wrapping && mark_beginbuf == inptr->next)
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001582 mark_beginx += after_break_len;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001583#endif /* !NANO_SMALL */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001584
Chris Allegretta7162e3d2002-04-06 05:02:14 +00001585 /* Place the cursor. */
Adam Rogoyski77f36de2000-06-07 03:56:54 +00001586 reset_cursor();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001587
1588 return 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001589}
Chris Allegretta6df90f52002-07-19 01:08:59 +00001590#endif /* !DISABLE_WRAPPING */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001591
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001592#ifndef DISABLE_SPELLER
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001593int do_int_spell_fix(const char *word)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001594{
Chris Allegretta6df90f52002-07-19 01:08:59 +00001595 char *save_search;
1596 char *save_replace;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001597 filestruct *begin;
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001598 int i = 0, j = 0, beginx, beginx_top, reverse_search_set, case_sens_set;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001599#ifndef NANO_SMALL
1600 int mark_set;
1601#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001602
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001603 /* save where we are */
1604 begin = current;
1605 beginx = current_x + 1;
1606
Chris Allegretta23b74b22002-01-21 20:32:22 +00001607 /* Make sure Spell Check goes forward only */
1608 reverse_search_set = ISSET(REVERSE_SEARCH);
1609 UNSET(REVERSE_SEARCH);
1610
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001611 case_sens_set = ISSET(CASE_SENSITIVE);
1612 SET(CASE_SENSITIVE);
1613
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001614#ifndef NANO_SMALL
1615 /* Make sure the marking highlight is off during Spell Check */
1616 mark_set = ISSET(MARK_ISSET);
1617 UNSET(MARK_ISSET);
1618#endif
1619
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001620 /* save the current search/replace strings */
1621 search_init_globals();
Chris Allegretta6df90f52002-07-19 01:08:59 +00001622 save_search = last_search;
1623 save_replace = last_replace;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001624
1625 /* set search/replace strings to mis-spelt word */
Chris Allegretta6df90f52002-07-19 01:08:59 +00001626 last_search = mallocstrcpy(NULL, word);
1627 last_replace = mallocstrcpy(NULL, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001628
1629 /* start from the top of file */
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001630 current = fileage;
1631 current_x = beginx_top = -1;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001632
1633 search_last_line = FALSE;
1634
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001635 while (1) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001636 /* make sure word is still mis-spelt (i.e. when multi-errors) */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001637 if (findnextstr(TRUE, FALSE, fileage, beginx_top, word)) {
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001638
Chris Allegretta6df90f52002-07-19 01:08:59 +00001639 /* find whole words only */
1640 if (!is_whole_word(current_x, current->data, word))
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001641 continue;
Chris Allegrettad00e6df2000-11-29 04:33:26 +00001642
Chris Allegrettabfd2f562002-12-10 03:03:20 +00001643 edit_update(current, current_x);
Chris Allegretta6df90f52002-07-19 01:08:59 +00001644 do_replace_highlight(TRUE, word);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001645
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001646 /* allow replace word to be corrected */
Chris Allegretta7662c862003-01-13 01:35:15 +00001647 i = statusq(0, spell_list, last_replace,
1648#ifndef NANO_SMALL
1649 0,
1650#endif
1651 _("Edit a replacement"));
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001652
Chris Allegretta6df90f52002-07-19 01:08:59 +00001653 do_replace_highlight(FALSE, word);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001654
1655 /* start from the start of this line again */
1656 current = fileage;
1657 current_x = beginx_top;
1658
1659 search_last_line = FALSE;
1660
Chris Allegretta6df90f52002-07-19 01:08:59 +00001661 if (strcmp(word, answer)) {
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001662 j = i;
Chris Allegretta6df90f52002-07-19 01:08:59 +00001663 do_replace_loop(word, fileage, &beginx_top, TRUE, &j);
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001664 }
Chris Allegretta80838272001-12-02 06:03:22 +00001665 }
Chris Allegretta1bc0c7e2002-01-08 15:00:24 +00001666 break;
Rocco Corsi562964d2002-01-13 03:18:03 +00001667 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001668
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001669 /* restore the search/replace strings */
Chris Allegrettabef12972002-03-06 03:30:40 +00001670 free(last_search); last_search=save_search;
1671 free(last_replace); last_replace=save_replace;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001672
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001673 /* restore where we were */
1674 current = begin;
1675 current_x = beginx - 1;
1676
Chris Allegretta23b74b22002-01-21 20:32:22 +00001677 /* restore Search/Replace direction */
1678 if (reverse_search_set)
1679 SET(REVERSE_SEARCH);
1680
Chris Allegretta1d8fa1f2002-12-10 00:53:21 +00001681 if (!case_sens_set)
1682 UNSET(CASE_SENSITIVE);
1683
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001684#ifndef NANO_SMALL
1685 /* restore marking highlight */
1686 if (mark_set)
1687 SET(MARK_ISSET);
1688#endif
1689
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001690 if (i == -1)
1691 return FALSE;
1692
1693 return TRUE;
1694}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001695
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001696/* Integrated spell checking using 'spell' program. Return value: NULL
1697 * for normal termination, otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001698char *do_int_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001699{
Chris Allegretta271e9722000-11-10 18:15:43 +00001700 char *read_buff, *read_buff_ptr, *read_buff_word;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001701 size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001702 int spell_fd[2], sort_fd[2], uniq_fd[2], tempfile_fd = -1;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001703 pid_t pid_spell, pid_sort, pid_uniq;
1704 int spell_status, sort_status, uniq_status;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001705
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001706 /* Create all three pipes up front */
Chris Allegretta271e9722000-11-10 18:15:43 +00001707
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001708 if (pipe(spell_fd) == -1 || pipe(sort_fd) == -1 || pipe(uniq_fd) == -1)
1709 return _("Could not create pipe");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001710
Chris Allegretta2a7a9a22002-12-10 00:16:27 +00001711 statusbar(_("Creating misspelled word list, please wait..."));
Chris Allegretta271e9722000-11-10 18:15:43 +00001712 /* A new process to run spell in */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001713
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001714 if ((pid_spell = fork()) == 0) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001715
1716 /* Child continues, (i.e. future spell process) */
1717
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001718 close(spell_fd[0]);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001719
Chris Allegretta271e9722000-11-10 18:15:43 +00001720 /* replace the standard in with the tempfile */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001721 if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1)
1722 goto close_pipes_and_exit;
1723
1724 if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO)
1725 goto close_pipes_and_exit;
1726
Chris Allegretta271e9722000-11-10 18:15:43 +00001727 close(tempfile_fd);
1728
1729 /* send spell's standard out to the pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001730 if (dup2(spell_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1731 goto close_pipes_and_exit;
Chris Allegretta271e9722000-11-10 18:15:43 +00001732
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001733 close(spell_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001734
1735 /* Start spell program, we are using the PATH here!?!? */
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001736 execlp("spell", "spell", NULL);
1737
Chris Allegretta271e9722000-11-10 18:15:43 +00001738 /* Should not be reached, if spell is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001739 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001740 }
1741
1742 /* Parent continues here */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001743 close(spell_fd[1]);
1744
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001745 /* A new process to run sort in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001746 if ((pid_sort = fork()) == 0) {
1747
1748 /* Child continues, (i.e. future spell process) */
1749 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001750 if (dup2(spell_fd[0], STDIN_FILENO) != STDIN_FILENO)
1751 goto close_pipes_and_exit;
1752
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001753 close(spell_fd[0]);
1754
1755 /* send sort's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001756 if (dup2(sort_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1757 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001758
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001759 close(sort_fd[1]);
1760
1761 /* Start sort program. Use -f to remove mixed case without having
1762 to have ANOTHER pipe for tr. If this isn't portable, let me know. */
1763 execlp("sort", "sort", "-f", NULL);
1764
1765 /* Should not be reached, if sort is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001766 exit(1);
1767 }
1768
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001769 close(spell_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001770 close(sort_fd[1]);
1771
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001772 /* A new process to run uniq in */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001773 if ((pid_uniq = fork()) == 0) {
1774
1775 /* Child continues, (i.e. future uniq process) */
1776 /* replace the standard in with output of the old pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001777 if (dup2(sort_fd[0], STDIN_FILENO) != STDIN_FILENO)
1778 goto close_pipes_and_exit;
1779
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001780 close(sort_fd[0]);
1781
1782 /* send uniq's standard out to the new pipe */
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001783 if (dup2(uniq_fd[1], STDOUT_FILENO) != STDOUT_FILENO)
1784 goto close_pipes_and_exit;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001785
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001786 close(uniq_fd[1]);
1787
1788 /* Start uniq program, we are using PATH */
1789 execlp("uniq", "uniq", NULL);
1790
1791 /* Should not be reached, if uniq is found */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001792 exit(1);
1793 }
1794
Chris Allegretta2d5fc3a2003-01-16 03:11:23 +00001795 close(sort_fd[0]);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001796 close(uniq_fd[1]);
Chris Allegretta271e9722000-11-10 18:15:43 +00001797
1798 /* Child process was not forked successfully */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001799 if (pid_spell < 0 || pid_sort < 0 || pid_uniq < 0) {
1800 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001801 return _("Could not fork");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001802 }
1803
Chris Allegretta271e9722000-11-10 18:15:43 +00001804 /* Get system pipe buffer size */
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001805 if ((pipe_buff_size = fpathconf(uniq_fd[0], _PC_PIPE_BUF)) < 1) {
1806 close(uniq_fd[0]);
Chris Allegretta334a9402002-12-16 04:25:53 +00001807 return _("Could not get size of pipe buffer");
Chris Allegretta271e9722000-11-10 18:15:43 +00001808 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001809
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001810 /* Read-in the returned spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001811 read_buff_read = 0;
1812 read_buff_size = pipe_buff_size + 1;
1813 read_buff = read_buff_ptr = charalloc(read_buff_size);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001814
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001815 while ((bytesread = read(uniq_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001816 read_buff_read += bytesread;
1817 read_buff_size += pipe_buff_size;
1818 read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size);
1819 read_buff_ptr += read_buff_read;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001820
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001821 }
Chris Allegretta271e9722000-11-10 18:15:43 +00001822
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001823 *read_buff_ptr = (char)NULL;
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001824 close(uniq_fd[0]);
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001825
1826 /* Process the spelling errors */
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001827 read_buff_word = read_buff_ptr = read_buff;
1828
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001829 while (*read_buff_ptr != '\0') {
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001830
1831 if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001832 *read_buff_ptr = (char)NULL;
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001833 if (read_buff_word != read_buff_ptr) {
1834 if (!do_int_spell_fix(read_buff_word)) {
1835 read_buff_word = read_buff_ptr;
1836 break;
1837 }
1838 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001839 read_buff_word = read_buff_ptr + 1;
1840 }
Chris Allegrettaf21f3fc2002-03-25 03:26:27 +00001841 read_buff_ptr++;
1842 }
1843
1844 /* special case where last word doesn't end with \n or \r */
1845 if (read_buff_word != read_buff_ptr)
1846 do_int_spell_fix(read_buff_word);
1847
Chris Allegretta271e9722000-11-10 18:15:43 +00001848 free(read_buff);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001849 replace_abort();
Chris Allegretta35908f82002-12-10 00:55:32 +00001850 edit_update(current, current_x);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001851
Chris Allegretta271e9722000-11-10 18:15:43 +00001852 /* Process end of spell process */
1853
Chris Allegretta334a9402002-12-16 04:25:53 +00001854 waitpid(pid_spell, &spell_status, 0);
1855 waitpid(pid_sort, &sort_status, 0);
1856 waitpid(pid_uniq, &uniq_status, 0);
Chris Allegretta5ad92ac2002-12-09 00:58:51 +00001857
Chris Allegretta334a9402002-12-16 04:25:53 +00001858 if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status))
1859 return _("Error invoking \"spell\"");
Chris Allegretta271e9722000-11-10 18:15:43 +00001860
Chris Allegretta334a9402002-12-16 04:25:53 +00001861 if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status))
1862 return _("Error invoking \"sort -f\"");
1863
1864 if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status))
1865 return _("Error invoking \"uniq\"");
1866
1867 /* Otherwise... */
1868 return NULL;
Chris Allegretta3f1b6852003-01-12 23:54:05 +00001869
1870close_pipes_and_exit:
1871
1872 /* Don't leak any handles */
1873 close(tempfile_fd);
1874 close(spell_fd[0]);
1875 close(spell_fd[1]);
1876 close(sort_fd[0]);
1877 close(sort_fd[1]);
1878 close(uniq_fd[0]);
1879 close(uniq_fd[1]);
1880 exit(1);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001881}
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001882
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001883/* External spell checking. Return value: NULL for normal termination,
1884 * otherwise the error string. */
Chris Allegretta334a9402002-12-16 04:25:53 +00001885char *do_alt_speller(char *tempfile_name)
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001886{
Chris Allegrettab3655b42001-10-22 03:15:31 +00001887 int alt_spell_status, lineno_cur = current->lineno;
1888 int x_cur = current_x, y_cur = current_y, pww_cur = placewewant;
Chris Allegretta271e9722000-11-10 18:15:43 +00001889 pid_t pid_spell;
Chris Allegretta169ee842001-01-26 01:57:32 +00001890 char *ptr;
1891 static int arglen = 3;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001892 static char **spellargs = (char **)NULL;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001893#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001894 int mark_set = ISSET(MARK_ISSET);
1895 int mbb_lineno_cur = 0;
1896 /* We're going to close the current file, and open the output of
1897 the alternate spell command. The line that mark_beginbuf
1898 points to will be freed, so we save the line number and restore
1899 afterwards. */
1900
1901 if (mark_set) {
1902 mbb_lineno_cur = mark_beginbuf->lineno;
1903 UNSET(MARK_ISSET);
1904 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001905#endif
1906
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001907 endwin();
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001908
Chris Allegrettae434b452001-01-27 19:25:00 +00001909 /* Set up an argument list to pass the execvp function */
1910 if (spellargs == NULL) {
1911 spellargs = nmalloc(arglen * sizeof(char *));
Chris Allegretta271e9722000-11-10 18:15:43 +00001912
Chris Allegrettae434b452001-01-27 19:25:00 +00001913 spellargs[0] = strtok(alt_speller, " ");
1914 while ((ptr = strtok(NULL, " ")) != NULL) {
1915 arglen++;
1916 spellargs = nrealloc(spellargs, arglen * sizeof(char *));
1917 spellargs[arglen - 3] = ptr;
Chris Allegretta169ee842001-01-26 01:57:32 +00001918 }
Chris Allegrettae434b452001-01-27 19:25:00 +00001919 spellargs[arglen - 1] = NULL;
1920 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001921 spellargs[arglen - 2] = tempfile_name;
Chris Allegrettae434b452001-01-27 19:25:00 +00001922
1923 /* Start a new process for the alternate speller */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001924 if ((pid_spell = fork()) == 0) {
Chris Allegretta88520c92001-05-05 17:45:54 +00001925 /* Start alternate spell program; we are using the PATH here!?!? */
Chris Allegretta169ee842001-01-26 01:57:32 +00001926 execvp(spellargs[0], spellargs);
Chris Allegretta271e9722000-11-10 18:15:43 +00001927
1928 /* Should not be reached, if alternate speller is found!!! */
Chris Allegretta271e9722000-11-10 18:15:43 +00001929 exit(1);
1930 }
1931
1932 /* Could not fork?? */
Chris Allegretta271e9722000-11-10 18:15:43 +00001933 if (pid_spell < 0)
Chris Allegretta334a9402002-12-16 04:25:53 +00001934 return _("Could not fork");
Chris Allegretta271e9722000-11-10 18:15:43 +00001935
1936 /* Wait for alternate speller to complete */
1937
1938 wait(&alt_spell_status);
Chris Allegretta334a9402002-12-16 04:25:53 +00001939 if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) {
1940 char *altspell_error = NULL;
1941 char *invoke_error = _("Could not invoke \"%s\"");
1942 int msglen = strlen(invoke_error) + strlen(alt_speller) + 2;
1943
1944 altspell_error = charalloc(msglen);
1945 snprintf(altspell_error, msglen, invoke_error, alt_speller);
1946 return altspell_error;
1947 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001948
Chris Allegretta8f6c0692000-07-19 01:16:18 +00001949 refresh();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001950 free_filestruct(fileage);
Chris Allegretta56214c62001-09-27 02:46:53 +00001951 global_init(1);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00001952 open_file(tempfile_name, 0, 1);
Rocco Corsi4dfaf932001-04-20 01:59:55 +00001953
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001954#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001955 if (mark_set) {
1956 do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0);
1957 mark_beginbuf = current;
1958 mark_beginx = current_x;
1959 /* In case the line got shorter, assign mark_beginx. */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001960 SET(MARK_ISSET);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00001961 }
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00001962#endif
1963
Chris Allegretta1b3381b2001-09-28 21:59:01 +00001964 /* go back to the old position, mark the file as modified, and make
1965 sure that the titlebar is refreshed */
1966 do_gotopos(lineno_cur, x_cur, y_cur, pww_cur);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001967 set_modified();
Chris Allegrettae1f14522001-09-19 03:19:43 +00001968 clearok(topwin, FALSE);
1969 titlebar(NULL);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00001970
Chris Allegretta334a9402002-12-16 04:25:53 +00001971 return NULL;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001972}
1973#endif
1974
1975int do_spell(void)
1976{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00001977#ifdef DISABLE_SPELLER
Chris Allegrettaff269f82000-12-01 18:46:01 +00001978 nano_disabled_msg();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00001979 return TRUE;
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001980#else
Chris Allegretta334a9402002-12-16 04:25:53 +00001981 char *temp, *spell_msg = _("Generic error");
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001982
Chris Allegrettaa8c22572002-02-15 19:17:02 +00001983 if ((temp = safe_tempnam(0, "nano.")) == NULL) {
Chris Allegretta271e9722000-11-10 18:15:43 +00001984 statusbar(_("Could not create a temporary filename: %s"),
Chris Allegretta6b58acd2001-04-12 03:01:53 +00001985 strerror(errno));
Chris Allegretta271e9722000-11-10 18:15:43 +00001986 return 0;
1987 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001988
Chris Allegrettaecc3d7f2001-06-05 23:24:55 +00001989 if (write_file(temp, 1, 0, 0) == -1) {
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001990 statusbar(_("Spell checking failed: unable to write temp file!"));
Chris Allegrettabef12972002-03-06 03:30:40 +00001991 free(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00001992 return 0;
Chris Allegretta3dbb2782000-12-02 04:36:50 +00001993 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00001994
Chris Allegrettae1f14522001-09-19 03:19:43 +00001995#ifdef ENABLE_MULTIBUFFER
1996 /* update the current open_files entry before spell-checking, in case
Chris Allegretta4dc03d52002-05-11 03:04:44 +00001997 any problems occur */
Chris Allegretta48b06702002-02-22 04:30:50 +00001998 add_open_file(1);
Chris Allegrettae1f14522001-09-19 03:19:43 +00001999#endif
2000
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002001 if (alt_speller != NULL)
Chris Allegretta334a9402002-12-16 04:25:53 +00002002 spell_msg = do_alt_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002003 else
Chris Allegretta334a9402002-12-16 04:25:53 +00002004 spell_msg = do_int_speller(temp);
Chris Allegretta271e9722000-11-10 18:15:43 +00002005 remove(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002006
Chris Allegretta334a9402002-12-16 04:25:53 +00002007 if (spell_msg == NULL) {
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002008 statusbar(_("Finished checking spelling"));
Chris Allegretta334a9402002-12-16 04:25:53 +00002009 return 1;
2010 } else {
2011 statusbar(_("Spell checking failed: %s"), spell_msg);
2012 return 0;
2013 }
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002014
Chris Allegrettabef12972002-03-06 03:30:40 +00002015 free(temp);
Chris Allegretta27eb13f2000-11-05 16:52:21 +00002016
Chris Allegrettadbc12b22000-07-03 03:10:14 +00002017#endif
Chris Allegretta67105eb2000-07-03 03:18:32 +00002018}
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002019
Chris Allegrettad865da12002-07-29 23:46:38 +00002020#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002021/* The "indentation" of a line is the white-space between the quote part
2022 * and the non-white-space of the line. */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002023size_t indent_length(const char *line)
2024{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002025 size_t len = 0;
2026
2027 assert(line != NULL);
2028 while (*line == ' ' || *line == '\t') {
2029 line++;
2030 len++;
2031 }
2032 return len;
2033}
Chris Allegrettadffa2072002-07-24 01:02:26 +00002034#endif /* !DISABLE_WRAPPING && !NANO_SMALL || !DISABLE_JUSTIFY */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002035
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002036#ifndef DISABLE_JUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00002037/* justify_format() replaces Tab by Space and multiple spaces by 1 (except
2038 * it maintains 2 after a . ! or ?). Note the terminating \0
2039 * counts as a space.
2040 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002041 * If !changes_allowed and justify_format() needs to make a change, it
Chris Allegretta6df90f52002-07-19 01:08:59 +00002042 * returns 1, otherwise returns 0.
2043 *
2044 * If changes_allowed, justify_format() might make line->data
2045 * shorter, and change the actual pointer with null_at().
2046 *
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002047 * justify_format() will not look at the first skip characters of line.
Chris Allegretta6df90f52002-07-19 01:08:59 +00002048 * skip should be at most strlen(line->data). The skip+1st character must
2049 * not be whitespace. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002050int justify_format(int changes_allowed, filestruct *line, size_t skip)
2051{
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002052 const char *punct = ".?!";
2053 const char *brackets = "'\")}]>";
Chris Allegretta6df90f52002-07-19 01:08:59 +00002054 char *back, *front;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002055
Chris Allegretta6df90f52002-07-19 01:08:59 +00002056 /* These four asserts are assumptions about the input data. */
2057 assert(line != NULL);
2058 assert(line->data != NULL);
2059 assert(skip <= strlen(line->data));
2060 assert(line->data[skip] != ' ' && line->data[skip] != '\t');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002061
Chris Allegretta6df90f52002-07-19 01:08:59 +00002062 back = line->data + skip;
2063 front = back;
2064 for (; *front; front++) {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002065 int remove_space = 0;
2066 /* Do we want to remove this space? */
2067
Chris Allegretta6df90f52002-07-19 01:08:59 +00002068 if (*front == '\t') {
2069 if (!changes_allowed)
2070 return 1;
2071 *front = ' ';
2072 }
2073 /* these tests are safe since line->data + skip is not a space */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002074 if (*front == ' ' && *(front - 1) == ' ') {
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002075 const char *bob = front - 2;
2076
2077 remove_space = 1;
2078 for (bob = front - 2; bob >= line->data + skip; bob--) {
2079 if (strchr(punct, *bob) != NULL) {
2080 remove_space = 0;
2081 break;
2082 }
2083 if (strchr(brackets, *bob) == NULL)
2084 break;
2085 }
2086 }
2087
2088 if (remove_space) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00002089 /* Now *front is a space we want to remove. We do that by
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002090 * simply failing to assign it to *back. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002091 if (!changes_allowed)
2092 return 1;
2093#ifndef NANO_SMALL
2094 if (mark_beginbuf == line && back - line->data < mark_beginx)
2095 mark_beginx--;
2096#endif
2097 } else {
2098 *back = *front;
2099 back++;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002100 }
2101 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002102
2103 /* Remove spaces from the end of the line, except maintain 1 after a
2104 * sentence punctuation. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002105 while (line->data < back && *(back - 1) == ' ')
Chris Allegretta6df90f52002-07-19 01:08:59 +00002106 back--;
2107 if (line->data < back && *back == ' ' &&
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002108 strchr(punct, *(back - 1)) != NULL)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002109 back++;
2110 if (!changes_allowed && back != front)
2111 return 1;
2112
2113 /* This assert merely documents a fact about the loop above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002114 assert(changes_allowed != 0 || back == front);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002115
2116 /* Now back is the new end of line->data. */
2117 if (back != front) {
2118 totsize += back - line->data - strlen(line->data);
2119 null_at(&line->data, back - line->data);
2120#ifndef NANO_SMALL
2121 if (mark_beginbuf == line && back - line->data < mark_beginx)
2122 mark_beginx = back - line->data;
2123#endif
2124 }
2125 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002126}
Chris Allegretta6df90f52002-07-19 01:08:59 +00002127
2128/* The "quote part" of a line is the largest initial substring matching
2129 * the quote string. This function returns the length of the quote part
2130 * of the given line.
2131 *
2132 * Note that if !HAVE_REGEX_H then we match concatenated copies of
2133 * quotestr. */
2134#ifdef HAVE_REGEX_H
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002135size_t quote_length(const char *line, const regex_t *qreg)
2136{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002137 regmatch_t matches;
2138 int rc = regexec(qreg, line, 1, &matches, 0);
2139
2140 if (rc == REG_NOMATCH || matches.rm_so == (regoff_t) -1)
2141 return 0;
2142 /* matches.rm_so should be 0, since the quote string should start with
2143 * the caret ^. */
2144 return matches.rm_eo;
2145}
2146#else /* !HAVE_REGEX_H */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002147size_t quote_length(const char *line)
2148{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002149 size_t qdepth = 0;
2150 size_t qlen = strlen(quotestr);
2151
2152 /* Compute quote depth level */
2153 while (!strcmp(line + qdepth, quotestr))
2154 qdepth += qlen;
2155 return qdepth;
2156}
2157#endif /* !HAVE_REGEX_H */
2158
Chris Allegretta6df90f52002-07-19 01:08:59 +00002159/* a_line and b_line are lines of text. The quotation part of a_line is
2160 * the first a_quote characters. Check that the quotation part of
2161 * b_line is the same. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002162int quotes_match(const char *a_line, size_t a_quote,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002163 IFREG(const char *b_line, const regex_t *qreg))
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002164{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002165 /* Here is the assumption about a_quote: */
2166 assert(a_quote == quote_length(IFREG(a_line, qreg)));
Chris Allegrettad865da12002-07-29 23:46:38 +00002167 return a_quote == quote_length(IFREG(b_line, qreg)) &&
Chris Allegretta6df90f52002-07-19 01:08:59 +00002168 !strncmp(a_line, b_line, a_quote);
2169}
2170
2171/* We assume a_line and b_line have no quote part. Then, we return whether
2172 * b_line could follow a_line in a paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002173size_t indents_match(const char *a_line, size_t a_indent,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002174 const char *b_line, size_t b_indent)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002175{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002176 assert(a_indent == indent_length(a_line));
2177 assert(b_indent == indent_length(b_line));
2178
2179 return b_indent <= a_indent && !strncmp(a_line, b_line, b_indent);
2180}
2181
2182/* Put the next par_len lines, starting with first_line, in the cut
2183 * buffer. We assume there are enough lines after first_line. We leave
2184 * copies of the lines in place, too. We return the new copy of
2185 * first_line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002186filestruct *backup_lines(filestruct *first_line, size_t par_len,
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002187 size_t quote_len)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002188{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002189 /* We put the original lines, not copies, into the cut buffer, just
2190 * out of a misguided sense of consistency, so if you un-cut, you
2191 * get the actual same paragraph back, not a copy. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002192 filestruct *alice = first_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002193
2194 set_modified();
2195 cutbuffer = NULL;
2196 for(; par_len > 0; par_len--) {
Chris Allegretta908f7702003-01-15 11:18:58 +00002197 filestruct *bob = copy_node(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002198
Chris Allegretta908f7702003-01-15 11:18:58 +00002199 if (alice == first_line)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002200 first_line = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002201 if (alice == current)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002202 current = bob;
Chris Allegretta908f7702003-01-15 11:18:58 +00002203 if (alice == edittop)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002204 edittop = bob;
2205#ifndef NANO_SMALL
Chris Allegretta908f7702003-01-15 11:18:58 +00002206 if (alice == mark_beginbuf)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002207 mark_beginbuf = bob;
2208#endif
2209 justify_format(1, bob,
2210 quote_len + indent_length(bob->data + quote_len));
2211
Chris Allegretta908f7702003-01-15 11:18:58 +00002212 assert(alice != NULL && bob != NULL);
2213 add_to_cutbuffer(alice);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002214 splice_node(bob->prev, bob, bob->next);
Chris Allegretta908f7702003-01-15 11:18:58 +00002215 alice = bob->next;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002216 }
2217 return first_line;
2218}
2219
2220/* We are trying to break a chunk off line. We find the last space such
2221 * that the display length to there is at most goal + 1. If there is
2222 * no such space, and force is not 0, then we find the first space.
2223 * Anyway, we then take the last space in that group of spaces. The
2224 * terminating '\0' counts as a space. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002225int break_line(const char *line, int goal, int force)
2226{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002227 /* Note that we use int instead of size_t, since goal is at most COLS,
2228 * the screen width, which will always be reasonably small. */
2229 int space_loc = -1;
2230 /* Current tentative return value. Index of the last space we
2231 * found with short enough display width. */
2232 int cur_loc = 0;
2233 /* Current index in line */
2234
2235 assert(line != NULL);
2236 for(; *line != '\0' && goal >= 0; line++, cur_loc++) {
2237 if (*line == ' ')
2238 space_loc = cur_loc;
2239 assert(*line != '\t');
2240
Chris Allegrettacf287c82002-07-20 13:57:41 +00002241 if (is_cntrl_char(*line))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002242 goal -= 2;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002243 else
2244 goal--;
2245 }
2246 if (goal >= 0)
2247 /* In fact, the whole line displays shorter than goal. */
2248 return cur_loc;
2249 if (space_loc == -1) {
2250 /* No space found short enough. */
2251 if (force)
2252 for(; *line != '\0'; line++, cur_loc++)
2253 if (*line == ' ' && *(line + 1) != ' ')
2254 return cur_loc;
2255 return -1;
2256 }
2257 /* Perhaps the character after space_loc is a space. But because
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002258 * of justify_format(), there can be only two adjacent. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002259 if (*(line - cur_loc + space_loc + 1) == ' ' ||
2260 *(line - cur_loc + space_loc + 1) == '\0')
2261 space_loc++;
2262 return space_loc;
2263}
2264#endif /* !DISABLE_JUSTIFY */
2265
2266/* This function justifies the current paragraph. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002267int do_justify(void)
2268{
Rocco Corsiaf5c3022001-01-12 07:51:05 +00002269#ifdef DISABLE_JUSTIFY
Chris Allegrettaff269f82000-12-01 18:46:01 +00002270 nano_disabled_msg();
2271 return 1;
2272#else
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002273
Chris Allegretta6df90f52002-07-19 01:08:59 +00002274/* To explain the justifying algorithm, I first need to define some
2275 * phrases about paragraphs and quotation:
2276 * A line of text consists of a "quote part", followed by an
2277 * "indentation part", followed by text. The functions quote_length()
2278 * and indent_length() calculate these parts.
2279 *
2280 * A line is "part of a paragraph" if it has a part not in the quote
2281 * part or the indentation.
2282 *
2283 * A line is "the beginning of a paragraph" if it is part of a paragraph
2284 * and
2285 * 1) it is the top line of the file, or
2286 * 2) the line above it is not part of a paragraph, or
2287 * 3) the line above it does not have precisely the same quote
2288 * part, or
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002289 * 4) the indentation of this line is not an initial substring of the
Chris Allegretta6df90f52002-07-19 01:08:59 +00002290 * indentation of the previous line, or
2291 * 5) this line has no quote part and some indentation, and
2292 * AUTOINDENT is not set.
2293 * The reason for number 5) is that if AUTOINDENT is not set, then an
2294 * indented line is expected to start a paragraph, like in books. Thus,
2295 * nano can justify an indented paragraph only if AUTOINDENT is turned
2296 * on.
2297 *
2298 * A contiguous set of lines is a "paragraph" if each line is part of
2299 * a paragraph and only the first line is the beginning of a paragraph.
Chris Allegrettad4fa0d32002-03-05 19:55:55 +00002300 */
Robert Siemborski60cd6aa2001-01-21 23:23:48 +00002301
Chris Allegretta6df90f52002-07-19 01:08:59 +00002302 size_t quote_len;
2303 /* Length of the initial quotation of the paragraph we justify. */
2304 size_t par_len;
2305 /* Number of lines in that paragraph. */
2306 filestruct *first_mod_line = NULL;
2307 /* Will be the first line of the resulting justified paragraph
2308 * that differs from the original. For restoring after uncut. */
2309 filestruct *last_par_line = current;
2310 /* Will be the last line of the result, also for uncut. */
2311 filestruct *cutbuffer_save = cutbuffer;
2312 /* When the paragraph gets modified, all lines from the changed
2313 * one down are stored in the cut buffer. We back up the original
2314 * to restore it later. */
2315
2316 /* We save these global variables to be restored if the user
2317 * unjustifies. Note we don't need to save totlines. */
2318 int current_x_save = current_x;
2319 int current_y_save = current_y;
2320 filestruct *current_save = current;
2321 int flags_save = flags;
2322 long totsize_save = totsize;
2323 filestruct *edittop_save = edittop;
2324 filestruct *editbot_save = editbot;
2325#ifndef NANO_SMALL
2326 filestruct *mark_beginbuf_save = mark_beginbuf;
2327 int mark_beginx_save = mark_beginx;
2328#endif
2329
2330 size_t indent_len; /* generic indentation length */
2331 filestruct *line; /* generic line of text */
2332 size_t i; /* generic loop variable */
2333
2334#ifdef HAVE_REGEX_H
2335 regex_t qreg; /* qreg is the compiled quotation regexp.
Chris Allegrettad865da12002-07-29 23:46:38 +00002336 * We no longer care about quotestr. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002337 int rc = regcomp(&qreg, quotestr, REG_EXTENDED);
2338
2339 if (rc) {
2340 size_t size = regerror(rc, &qreg, NULL, 0);
2341 char *strerror = charalloc(size);
2342
2343 regerror(rc, &qreg, strerror, size);
2344 statusbar(_("Bad quote string %s: %s"), quotestr, strerror);
2345 free(strerror);
2346 return -1;
2347 }
2348#endif
2349
2350 /* Here is an assumption that is always true anyway. */
2351 assert(current != NULL);
2352
2353/* Here we find the first line of the paragraph to justify. If the
2354 * current line is in a paragraph, then we move back to the first line.
2355 * Otherwise we move down to the first line that is in a paragraph. */
2356 quote_len = quote_length(IFREG(current->data, &qreg));
2357 indent_len = indent_length(current->data + quote_len);
2358
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002359 current_x = 0;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002360 if (current->data[quote_len + indent_len] != '\0') {
2361 /* This line is part of a paragraph. So we must search back to
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002362 * the first line of this paragraph. First we check items 1) and
2363 * 3) above. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002364 while (current->prev != NULL && quotes_match(current->data,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002365 quote_len, IFREG(current->prev->data, &qreg))) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002366 size_t temp_id_len =
Chris Allegretta6df90f52002-07-19 01:08:59 +00002367 indent_length(current->prev->data + quote_len);
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002368 /* The indentation length of the previous line. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002369
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002370 /* Is this line the beginning of a paragraph, according to
2371 items 2), 5), or 4) above? If so, stop. */
2372 if (current->prev->data[quote_len + temp_id_len] == '\0' ||
2373 (quote_len == 0 && indent_len > 0
2374#ifndef NANO_SMALL
2375 && !ISSET(AUTOINDENT)
2376#endif
2377 ) ||
2378 !indents_match(current->prev->data + quote_len,
2379 temp_id_len, current->data + quote_len, indent_len))
2380 break;
2381 indent_len = temp_id_len;
2382 current = current->prev;
2383 current_y--;
Chris Allegretta7162e3d2002-04-06 05:02:14 +00002384 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002385 } else {
Chris Allegrettad865da12002-07-29 23:46:38 +00002386 /* This line is not part of a paragraph. Move down until we get
2387 * to a non "blank" line. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002388 do {
2389 /* There is no next paragraph, so nothing to justify. */
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002390 if (current->next == NULL) {
2391 placewewant = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002392 if (current_y > editwinrows - 1)
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002393 edit_update(current, CENTER);
2394 else
2395 edit_refresh();
Chris Allegretta6df90f52002-07-19 01:08:59 +00002396 return 0;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002397 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002398 current = current->next;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002399 current_y++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002400 quote_len = quote_length(IFREG(current->data, &qreg));
2401 indent_len = indent_length(current->data + quote_len);
2402 } while (current->data[quote_len + indent_len] == '\0');
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002403 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002404/* Now current is the first line of the paragraph, and quote_len
2405 * is the quotation length of that line. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002406
Chris Allegretta6df90f52002-07-19 01:08:59 +00002407/* Next step, compute par_len, the number of lines in this paragraph. */
2408 line = current;
2409 par_len = 1;
2410 indent_len = indent_length(line->data + quote_len);
2411
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002412 while (line->next != NULL && quotes_match(current->data, quote_len,
Chris Allegretta6df90f52002-07-19 01:08:59 +00002413 IFREG(line->next->data, &qreg))) {
2414 size_t temp_id_len = indent_length(line->next->data + quote_len);
2415
2416 if (!indents_match(line->data + quote_len, indent_len,
2417 line->next->data + quote_len, temp_id_len) ||
2418 line->next->data[quote_len + temp_id_len] == '\0' ||
2419 (quote_len == 0 && temp_id_len > 0
2420#ifndef NANO_SMALL
2421 && !ISSET(AUTOINDENT)
2422#endif
2423 ))
2424 break;
2425 indent_len = temp_id_len;
2426 line = line->next;
2427 par_len++;
2428 }
2429#ifdef HAVE_REGEX_H
2430 /* We no longer need to check quotation. */
2431 regfree(&qreg);
2432#endif
2433/* Now par_len is the number of lines in this paragraph. Should never
2434 * call quotes_match() or quote_length() again. */
2435
2436/* Next step, we loop through the lines of this paragraph, justifying
2437 * each one individually. */
2438 for(; par_len > 0; current_y++, par_len--) {
2439 size_t line_len;
2440 size_t display_len;
2441 /* The width of current in screen columns. */
2442 int break_pos;
2443 /* Where we will break the line. */
2444
2445 indent_len = indent_length(current->data + quote_len) +
2446 quote_len;
2447 /* justify_format() removes excess spaces from the line, and
2448 * changes tabs to spaces. The first argument, 0, means don't
2449 * change the line, just say whether there are changes to be
2450 * made. If there are, we do backup_lines(), which copies the
2451 * original paragraph to the cutbuffer for unjustification, and
David Lawrence Ramsey0084eaa2002-11-04 16:05:42 +00002452 * then calls justify_format() on the remaining lines. */
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002453 if (first_mod_line == NULL && justify_format(0, current, indent_len))
Chris Allegretta6df90f52002-07-19 01:08:59 +00002454 first_mod_line = backup_lines(current, par_len, quote_len);
2455
2456 line_len = strlen(current->data);
2457 display_len = strlenpt(current->data);
2458
2459 if (display_len > fill) {
2460 /* The line is too long. Try to wrap it to the next. */
2461 break_pos = break_line(current->data + indent_len,
2462 fill - strnlenpt(current->data, indent_len),
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002463 1);
Chris Allegretta6df90f52002-07-19 01:08:59 +00002464 if (break_pos == -1 || break_pos + indent_len == line_len)
2465 /* We can't break the line, or don't need to, so just go
2466 * on to the next. */
2467 goto continue_loc;
2468 break_pos += indent_len;
2469 assert(break_pos < line_len);
2470 /* If we haven't backed up the paragraph, do it now. */
2471 if (first_mod_line == NULL)
2472 first_mod_line = backup_lines(current, par_len, quote_len);
2473 if (par_len == 1) {
2474 /* There is no next line in this paragraph. We make a new
2475 * line and copy text after break_pos into it. */
2476 splice_node(current, make_new_node(current),
2477 current->next);
2478 current->next->data = charalloc(indent_len + line_len -
2479 break_pos);
2480 strncpy(current->next->data, current->data,
2481 indent_len);
2482 strcpy(current->next->data + indent_len,
2483 current->data + break_pos + 1);
2484 assert(strlen(current->next->data) ==
2485 indent_len + line_len - break_pos - 1);
2486 totlines++;
2487 totsize += indent_len;
2488 par_len++;
2489 } else {
2490 size_t next_line_len = strlen(current->next->data);
2491
2492 indent_len = quote_len +
2493 indent_length(current->next->data + quote_len);
2494 current->next->data = (char *)nrealloc(current->next->data,
2495 sizeof(char) * (next_line_len + line_len -
2496 break_pos + 1));
2497
2498 memmove(current->next->data + indent_len + line_len - break_pos,
2499 current->next->data + indent_len,
2500 next_line_len - indent_len + 1);
2501 strcpy(current->next->data + indent_len,
2502 current->data + break_pos + 1);
2503 current->next->data[indent_len + line_len - break_pos - 1]
2504 = ' ';
2505#ifndef NANO_SMALL
2506 if (mark_beginbuf == current->next) {
2507 if (mark_beginx < indent_len)
2508 mark_beginx = indent_len;
2509 mark_beginx += line_len - break_pos;
2510 }
2511#endif
2512 }
2513#ifndef NANO_SMALL
2514 if (mark_beginbuf == current && mark_beginx > break_pos) {
2515 mark_beginbuf = current->next;
2516 mark_beginx -= break_pos + 1 - indent_len;
2517 }
2518#endif
2519 null_at(&current->data, break_pos);
2520 current = current->next;
2521 } else if (display_len < fill && par_len > 1) {
2522 size_t next_line_len = strlen(current->next->data);
2523
2524 indent_len = quote_len +
2525 indent_length(current->next->data + quote_len);
2526 break_pos = break_line(current->next->data + indent_len,
2527 fill - display_len - 1, 0);
2528 if (break_pos == -1)
2529 /* We can't pull a word from the next line up to this one,
2530 * so just go on. */
2531 goto continue_loc;
2532
2533 /* If we haven't backed up the paragraph, do it now. */
2534 if (first_mod_line == NULL)
2535 first_mod_line = backup_lines(current, par_len, quote_len);
2536 current->data = (char *)nrealloc(current->data,
2537 line_len + break_pos + 2);
2538 current->data[line_len] = ' ';
2539 strncpy(current->data + line_len + 1,
2540 current->next->data + indent_len, break_pos);
2541 current->data[line_len + break_pos + 1] = '\0';
2542#ifndef NANO_SMALL
2543 if (mark_beginbuf == current->next) {
2544 if (mark_beginx < indent_len + break_pos) {
2545 mark_beginbuf = current;
2546 if (mark_beginx <= indent_len)
2547 mark_beginx = line_len + 1;
2548 else
2549 mark_beginx = line_len + 1 + mark_beginx - indent_len;
2550 } else
2551 mark_beginx -= break_pos + 1;
2552 }
2553#endif
2554 if (indent_len + break_pos == next_line_len) {
2555 line = current->next;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002556
2557 /* Don't destroy edittop! */
2558 if (line == edittop)
2559 edittop = current;
2560
Chris Allegretta6df90f52002-07-19 01:08:59 +00002561 unlink_node(line);
2562 delete_node(line);
2563 totlines--;
2564 totsize -= indent_len;
2565 current_y--;
2566 } else {
2567 memmove(current->next->data + indent_len,
2568 current->next->data + indent_len + break_pos + 1,
2569 next_line_len - break_pos - indent_len);
2570 null_at(&current->next->data,
2571 next_line_len - break_pos);
2572 current = current->next;
2573 }
2574 } else
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002575 continue_loc:
Chris Allegretta6df90f52002-07-19 01:08:59 +00002576 current = current->next;
2577 }
2578/* We are now done justifying the paragraph. There are cleanup things to
2579 * do, and we check for unjustify. */
2580
2581 /* totlines, totsize, and current_y have been maintained above. We
2582 * now set last_par_line to the new end of the paragraph, update
2583 * fileage, set current_x. Also, edit_refresh() needs the line
2584 * numbers to be right, so we renumber(). */
2585 last_par_line = current->prev;
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002586 if (first_mod_line != NULL) {
2587 if (first_mod_line->prev == NULL)
2588 fileage = first_mod_line;
Chris Allegretta6df90f52002-07-19 01:08:59 +00002589 renumber(first_mod_line);
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002590 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002591
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002592 if (current_y > editwinrows - 1)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002593 edit_update(current, CENTER);
2594 else
2595 edit_refresh();
2596
Chris Allegretta9149e612000-11-27 00:23:41 +00002597 statusbar(_("Can now UnJustify!"));
Chris Allegretta07798352000-11-27 22:58:23 +00002598 /* Change the shortcut list to display the unjustify code */
2599 shortcut_init(1);
2600 display_main_list();
Chris Allegretta9149e612000-11-27 00:23:41 +00002601 reset_cursor();
2602
Chris Allegretta6df90f52002-07-19 01:08:59 +00002603 /* Now get a keystroke and see if it's unjustify; if not, unget the
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002604 * keystroke and return. */
Chris Allegretta5f071802001-05-06 02:34:31 +00002605
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002606#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta6df90f52002-07-19 01:08:59 +00002607 /* If it was a mouse click, parse it with do_mouse() and it might
2608 * become the unjustify key. Else give it back to the input stream. */
2609 if ((i = wgetch(edit)) == KEY_MOUSE)
Chris Allegretta5f071802001-05-06 02:34:31 +00002610 do_mouse();
2611 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00002612 ungetch(i);
Chris Allegretta5f071802001-05-06 02:34:31 +00002613#endif
Chris Allegretta5f071802001-05-06 02:34:31 +00002614
Chris Allegretta6df90f52002-07-19 01:08:59 +00002615 if ((i = wgetch(edit)) != NANO_UNJUSTIFY_KEY) {
2616 ungetch(i);
2617 /* Did we back up anything at all? */
2618 if (cutbuffer != cutbuffer_save)
2619 free_filestruct(cutbuffer);
2620 placewewant = 0;
Chris Allegretta00ae5df2001-02-05 18:24:33 +00002621 } else {
Chris Allegretta9149e612000-11-27 00:23:41 +00002622 /* Else restore the justify we just did (ungrateful user!) */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002623 current = current_save;
2624 current_x = current_x_save;
2625 current_y = current_y_save;
2626 edittop = edittop_save;
2627 editbot = editbot_save;
2628 if (first_mod_line != NULL) {
2629 filestruct *cutbottom = get_cutbottom();
Chris Allegrettad022eac2000-11-27 02:50:49 +00002630
Chris Allegretta6df90f52002-07-19 01:08:59 +00002631 /* Splice the cutbuffer back into the file. */
2632 cutbottom->next = last_par_line->next;
2633 cutbottom->next->prev = cutbottom;
2634 /* The line numbers after the end of the paragraph have
2635 * been changed, so we change them back. */
2636 renumber(cutbottom->next);
2637 if (first_mod_line->prev != NULL) {
2638 cutbuffer->prev = first_mod_line->prev;
2639 cutbuffer->prev->next = cutbuffer;
2640 } else
2641 fileage = cutbuffer;
2642 cutbuffer = NULL;
2643
2644 last_par_line->next = NULL;
2645 free_filestruct(first_mod_line);
2646
2647 /* Restore global variables from before justify */
2648 totsize = totsize_save;
2649 totlines = filebot->lineno;
2650#ifndef NANO_SMALL
2651 mark_beginbuf = mark_beginbuf_save;
2652 mark_beginx = mark_beginx_save;
2653#endif
2654 flags = flags_save;
2655 if (!ISSET(MODIFIED)) {
2656 titlebar(NULL);
2657 wrefresh(topwin);
2658 }
2659 }
2660 edit_refresh();
Chris Allegretta9149e612000-11-27 00:23:41 +00002661 }
Chris Allegretta6df90f52002-07-19 01:08:59 +00002662 cutbuffer = cutbuffer_save;
2663 blank_statusbar_refresh();
2664 /* display shortcut list without UnCut */
Chris Allegretta4a9c8582000-11-27 22:59:40 +00002665 shortcut_init(0);
2666 display_main_list();
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002667
Chris Allegretta6df90f52002-07-19 01:08:59 +00002668 return 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002669#endif
2670}
2671
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002672int do_exit(void)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002673{
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002674 int i;
Chris Allegretta13fd44b2002-01-02 13:59:11 +00002675
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002676 if (!ISSET(MODIFIED)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002677
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002678#ifdef ENABLE_MULTIBUFFER
2679 if (!close_open_file()) {
2680 display_main_list();
2681 return 1;
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002682 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002683 else
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002684#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002685 finish(0);
Chris Allegretta756f2202000-09-01 13:32:47 +00002686 }
2687
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002688 if (ISSET(TEMP_OPT)) {
2689 i = 1;
2690 } else {
2691 i = do_yesno(0, 0,
2692 _
2693 ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? "));
2694 }
2695
2696#ifdef DEBUG
2697 dump_buffer(fileage);
2698#endif
2699
2700 if (i == 1) {
2701 if (do_writeout(filename, 1, 0) > 0) {
2702
2703#ifdef ENABLE_MULTIBUFFER
2704 if (!close_open_file()) {
2705 display_main_list();
2706 return 1;
2707 }
2708 else
2709#endif
2710 finish(0);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00002711 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002712 } else if (i == 0) {
2713
2714#ifdef ENABLE_MULTIBUFFER
2715 if (!close_open_file()) {
2716 display_main_list();
2717 return 1;
2718 }
2719 else
2720#endif
2721 finish(0);
2722 } else
2723 statusbar(_("Cancelled"));
2724
2725 display_main_list();
2726 return 1;
2727}
2728
2729void signal_init(void)
2730{
2731#ifdef _POSIX_VDISABLE
2732 struct termios term;
2733#endif
2734
2735 /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */
2736 memset(&act, 0, sizeof(struct sigaction));
2737 act.sa_handler = SIG_IGN;
2738 sigaction(SIGINT, &act, NULL);
2739
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002740 /* Trap SIGHUP and SIGTERM cuz we want to write the file out. */
2741 act.sa_handler = handle_hupterm;
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002742 sigaction(SIGHUP, &act, NULL);
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002743 sigaction(SIGTERM, &act, NULL);
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002744
2745#ifndef NANO_SMALL
2746 act.sa_handler = handle_sigwinch;
2747 sigaction(SIGWINCH, &act, NULL);
2748#endif
2749
2750#ifdef _POSIX_VDISABLE
2751 tcgetattr(0, &term);
2752
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002753 if (!ISSET(PRESERVE)) {
2754 /* Ignore ^S and ^Q, much to Chris' chagrin */
2755 term.c_cc[VSTOP] = _POSIX_VDISABLE;
2756 term.c_cc[VSTART] = _POSIX_VDISABLE;
2757 }
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002758#ifdef VDSUSP
2759 term.c_cc[VDSUSP] = _POSIX_VDISABLE;
2760#endif /* VDSUSP */
2761
2762#endif /* _POSIX_VDISABLE */
2763
2764 if (!ISSET(SUSPEND)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00002765 /* Insane! */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002766#ifdef _POSIX_VDISABLE
2767 term.c_cc[VSUSP] = _POSIX_VDISABLE;
2768#else
2769 act.sa_handler = SIG_IGN;
2770 sigaction(SIGTSTP, &act, NULL);
2771#endif
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002772 } else {
2773 /* If we don't do this, it seems other stuff interrupts the
2774 suspend handler! Try using nano with mutt without this
2775 line. */
2776 sigfillset(&act.sa_mask);
2777
2778 act.sa_handler = do_suspend;
2779 sigaction(SIGTSTP, &act, NULL);
2780
2781 act.sa_handler = do_cont;
2782 sigaction(SIGCONT, &act, NULL);
2783 }
2784
2785#ifdef _POSIX_VDISABLE
2786 tcsetattr(0, TCSANOW, &term);
2787#endif
2788}
2789
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002790/* Handler for SIGHUP and SIGTERM */
2791RETSIGTYPE handle_hupterm(int signal)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002792{
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00002793 die(_("Received SIGHUP or SIGTERM"));
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002794}
2795
2796/* What do we do when we catch the suspend signal */
2797RETSIGTYPE do_suspend(int signal)
2798{
2799 endwin();
2800 printf("\n\n\n\n\nUse \"fg\" to return to nano\n");
2801 fflush(stdout);
2802
2803 /* Restore the terminal settings for the disabled keys */
2804 tcsetattr(0, TCSANOW, &oldterm);
2805
2806 /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002807 then we could be (and were) interrupted in the middle of the call.
2808 So we do it the mutt way instead */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002809 kill(0, SIGSTOP);
2810}
2811
2812/* Restore the suspend handler when we come back into the prog */
2813RETSIGTYPE do_cont(int signal)
2814{
2815 /* Now we just update the screen instead of having to reenable the
2816 SIGTSTP handler. */
2817
2818 doupdate();
2819 /* The Hurd seems to need this, otherwise a ^Y after a ^Z will
2820 start suspending again. */
2821 signal_init();
2822
2823#ifndef NANO_SMALL
2824 /* Perhaps the user resized the window while we slept. */
2825 handle_sigwinch(0);
2826#endif
2827}
2828
2829#ifndef NANO_SMALL
2830void handle_sigwinch(int s)
2831{
2832 const char *tty = ttyname(0);
2833 int fd;
2834 int result = 0;
2835 struct winsize win;
2836
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002837 if (tty == NULL)
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002838 return;
2839 fd = open(tty, O_RDWR);
2840 if (fd == -1)
2841 return;
2842 result = ioctl(fd, TIOCGWINSZ, &win);
2843 close(fd);
2844 if (result == -1)
2845 return;
2846
2847 /* Could check whether the COLS or LINES changed, and return
2848 * otherwise. EXCEPT, that COLS and LINES are ncurses global
2849 * variables, and in some cases ncurses has already updated them.
2850 * But not in all cases, argh. */
2851 COLS = win.ws_col;
2852 LINES = win.ws_row;
2853 if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS)
2854 die_too_small();
2855
2856#ifndef DISABLE_WRAPJUSTIFY
2857 fill = wrap_at;
2858 if (fill <= 0)
2859 fill += COLS;
2860 if (fill < MIN_FILL_LENGTH)
2861 die_too_small();
2862#endif
2863
2864 hblank = nrealloc(hblank, COLS + 1);
2865 memset(hblank, ' ', COLS);
2866 hblank[COLS] = '\0';
2867
2868#ifdef HAVE_RESIZETERM
2869 resizeterm(LINES, COLS);
2870#ifdef HAVE_WRESIZE
2871 if (wresize(topwin, 2, COLS) == ERR)
2872 die(_("Cannot resize top win"));
2873 if (mvwin(topwin, 0, 0) == ERR)
2874 die(_("Cannot move top win"));
2875 if (wresize(edit, editwinrows, COLS) == ERR)
2876 die(_("Cannot resize edit win"));
2877 if (mvwin(edit, 2, 0) == ERR)
2878 die(_("Cannot move edit win"));
2879 if (wresize(bottomwin, 3 - no_help(), COLS) == ERR)
2880 die(_("Cannot resize bottom win"));
2881 if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR)
2882 die(_("Cannot move bottom win"));
2883#endif /* HAVE_WRESIZE */
2884#endif /* HAVE_RESIZETERM */
2885
2886 fix_editbot();
2887
2888 if (current_y > editwinrows - 1)
2889 edit_update(editbot, CENTER);
2890 erase();
2891
2892 /* Do these b/c width may have changed... */
2893 refresh();
2894 titlebar(NULL);
2895 edit_refresh();
2896 display_main_list();
2897 blank_statusbar();
2898 total_refresh();
2899
2900 /* Turn cursor back on for sure */
2901 curs_set(1);
2902
2903 /* Jump back to main loop */
2904 siglongjmp(jmpbuf, 1);
2905}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002906#endif /* !NANO_SMALL */
David Lawrence Ramseyc5967552002-06-21 03:20:06 +00002907
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00002908/* If the NumLock key has made the keypad go awry, print an error
2909 message; hopefully we can address it later. */
2910void print_numlock_warning(void)
2911{
2912 static int didmsg = 0;
2913 if (!didmsg) {
2914 statusbar(_
2915 ("NumLock glitch detected. Keypad will malfunction with NumLock off"));
2916 didmsg = 1;
2917 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002918}
2919
Chris Allegrettadab017e2002-04-23 10:56:06 +00002920#ifndef NANO_SMALL
David Lawrence Ramsey0341b582002-08-21 16:10:37 +00002921void do_toggle(const toggle *which)
Chris Allegretta756f2202000-09-01 13:32:47 +00002922{
Chris Allegretta6df90f52002-07-19 01:08:59 +00002923 int enabled;
Chris Allegrettaf0f63a82000-09-02 18:44:21 +00002924
Chris Allegretta658399a2001-06-14 02:54:22 +00002925 /* Even easier! */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002926 TOGGLE(which->flag);
Chris Allegretta2a42af12000-09-12 23:02:49 +00002927
Chris Allegrettaa8c22572002-02-15 19:17:02 +00002928 switch (which->val) {
Chris Allegretta756f2202000-09-01 13:32:47 +00002929 case TOGGLE_SUSPEND_KEY:
2930 signal_init();
2931 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002932#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00002933 case TOGGLE_MOUSE_KEY:
2934 mouse_init();
2935 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002936#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002937 case TOGGLE_NOHELP_KEY:
Chris Allegretta2a42af12000-09-12 23:02:49 +00002938 wclear(bottomwin);
2939 wrefresh(bottomwin);
2940 window_init();
Chris Allegrettaaffeda82000-12-18 04:03:48 +00002941 fix_editbot();
Chris Allegretta2a42af12000-09-12 23:02:49 +00002942 edit_refresh();
2943 display_main_list();
Chris Allegretta756f2202000-09-01 13:32:47 +00002944 break;
Chris Allegretta99e30e12001-09-23 02:45:27 +00002945 case TOGGLE_DOS_KEY:
2946 UNSET(MAC_FILE);
2947 break;
2948 case TOGGLE_MAC_KEY:
2949 UNSET(DOS_FILE);
2950 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002951#ifdef ENABLE_COLOR
Chris Allegretta1dd0bc92002-10-13 18:43:45 +00002952 case TOGGLE_SYNTAX_KEY:
2953 edit_refresh();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002954 break;
2955#endif
Chris Allegretta756f2202000-09-01 13:32:47 +00002956 }
Chris Allegretta2a42af12000-09-12 23:02:49 +00002957
Chris Allegretta6df90f52002-07-19 01:08:59 +00002958 /* We are assuming here that shortcut_init() above didn't free and
2959 * reallocate the toggles. */
2960 enabled = ISSET(which->flag);
2961 if (which->val == TOGGLE_NOHELP_KEY || which->val == TOGGLE_WRAP_KEY)
2962 enabled = !enabled;
2963 statusbar("%s %s", which->desc,
2964 enabled ? _("enabled") : _("disabled"));
Chris Allegretta756f2202000-09-01 13:32:47 +00002965}
Chris Allegrettadab017e2002-04-23 10:56:06 +00002966#endif /* !NANO_SMALL */
Chris Allegretta756f2202000-09-01 13:32:47 +00002967
Chris Allegretta1748cd12001-01-13 17:22:54 +00002968/* This function returns the correct keystroke, given the A,B,C or D
2969 input key. This is a common sequence of many terms which send
2970 Esc-O-[A-D] or Esc-[-[A-D]. */
Chris Allegretta908f7702003-01-15 11:18:58 +00002971int abcd(int input)
Chris Allegretta1748cd12001-01-13 17:22:54 +00002972{
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002973 switch (input) {
2974 case 'A':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002975 case 'a':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002976 return KEY_UP;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002977 case 'B':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002978 case 'b':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002979 return KEY_DOWN;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002980 case 'C':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002981 case 'c':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002982 return KEY_RIGHT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002983 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00002984 case 'd':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00002985 return KEY_LEFT;
Chris Allegretta6b58acd2001-04-12 03:01:53 +00002986 default:
2987 return 0;
Chris Allegretta1748cd12001-01-13 17:22:54 +00002988 }
2989}
2990
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002991int main(int argc, char *argv[])
2992{
2993 int optchr;
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00002994 int startline = 0; /* Line to try and start at */
Chris Allegretta9caa1932002-02-15 20:08:05 +00002995 int modify_control_seq;
Chris Allegretta7662c862003-01-13 01:35:15 +00002996 int fill_flag_used = 0; /* Was the fill option used? */
Chris Allegretta6df90f52002-07-19 01:08:59 +00002997 const shortcut *s;
Chris Allegretta6cd143d2003-01-05 23:35:44 +00002998#ifdef HAVE_GETOPT_LONG
2999 int preserveopt = 0; /* Did the cmdline include --preserve? */
3000#endif
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003001#ifndef NANO_SMALL
Chris Allegretta6df90f52002-07-19 01:08:59 +00003002 const toggle *t;
Chris Allegretta40ecbad2002-03-06 15:27:44 +00003003#endif
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003004#ifdef _POSIX_VDISABLE
3005 struct termios term;
3006#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003007#ifdef HAVE_GETOPT_LONG
3008 int option_index = 0;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003009 const struct option long_options[] = {
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003010 {"help", 0, 0, 'h'},
3011#ifdef ENABLE_MULTIBUFFER
3012 {"multibuffer", 0, 0, 'F'},
3013#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003014#ifdef ENABLE_NANORC
3015 {"ignorercfiles", 0, 0, 'I'},
3016#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003017 {"keypad", 0, 0, 'K'},
3018#ifndef DISABLE_JUSTIFY
3019 {"quotestr", 1, 0, 'Q'},
3020#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003021#ifdef HAVE_REGEX_H
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003022 {"regexp", 0, 0, 'R'},
Chris Allegretta47805612000-07-07 02:35:34 +00003023#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003024 {"tabsize", 1, 0, 'T'},
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003025 {"version", 0, 0, 'V'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003026#ifdef ENABLE_COLOR
3027 {"syntax", 1, 0, 'Y'},
3028#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003029 {"const", 0, 0, 'c'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003030 {"nofollow", 0, 0, 'l'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003031#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003032 {"mouse", 0, 0, 'm'},
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003033#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003034#ifndef DISABLE_OPERATINGDIR
3035 {"operatingdir", 1, 0, 'o'},
3036#endif
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003037 {"preserve", 0, 0, 'p'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003038#ifndef DISABLE_WRAPJUSTIFY
3039 {"fill", 1, 0, 'r'},
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003040#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003041#ifndef DISABLE_SPELLER
3042 {"speller", 1, 0, 's'},
3043#endif
3044 {"tempfile", 0, 0, 't'},
3045 {"view", 0, 0, 'v'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003046#ifndef DISABLE_WRAPPING
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003047 {"nowrap", 0, 0, 'w'},
David Lawrence Ramsey2ab03f62002-10-17 02:19:31 +00003048#endif
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003049 {"nohelp", 0, 0, 'x'},
3050 {"suspend", 0, 0, 'z'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003051#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003052 {"backup", 0, 0, 'B'},
3053 {"dos", 0, 0, 'D'},
3054 {"mac", 0, 0, 'M'},
3055 {"noconvert", 0, 0, 'N'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003056 {"smooth", 0, 0, 'S'},
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003057 {"autoindent", 0, 0, 'i'},
3058 {"cut", 0, 0, 'k'},
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003059#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003060 {0, 0, 0, 0}
3061 };
3062#endif
3063
Chris Allegretta8bc03b62001-02-09 02:57:52 +00003064#ifdef ENABLE_NLS
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003065 setlocale(LC_ALL, "");
3066 bindtextdomain(PACKAGE, LOCALEDIR);
3067 textdomain(PACKAGE);
3068#endif
3069
Chris Allegretta7662c862003-01-13 01:35:15 +00003070#ifdef HAVE_GETOPT_LONG
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003071 {
Chris Allegretta7662c862003-01-13 01:35:15 +00003072 /* Check for the --preserve flag, and report error if people are
3073 still using --pico. */
Chris Allegretta1c5c3382002-07-23 00:33:07 +00003074 int i;
3075 for (i = 1; i < argc; i++) {
Chris Allegretta7662c862003-01-13 01:35:15 +00003076 if (!strcmp(argv[i], "--preserve"))
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003077 preserveopt = 1;
3078 else if (!strcmp(argv[i], "--pico"))
3079 do_preserve_msg();
Chris Allegretta6df90f52002-07-19 01:08:59 +00003080 }
3081 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003082#endif
Chris Allegretta5beed502003-01-05 20:41:21 +00003083
Chris Allegretta7662c862003-01-13 01:35:15 +00003084#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
David Lawrence Ramseydc60b722002-10-25 16:08:53 +00003085 /* if we don't have rcfile support, we're root, and
3086 --disable-wrapping-as-root is used, turn wrapping off */
3087 if (geteuid() == 0)
3088 SET(NO_WRAP);
3089#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003090
3091#ifdef HAVE_GETOPT_LONG
Chris Allegretta908f7702003-01-15 11:18:58 +00003092 while ((optchr = getopt_long(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz",
Chris Allegretta7662c862003-01-13 01:35:15 +00003093 long_options, &option_index)) != -1) {
Chris Allegretta6df90f52002-07-19 01:08:59 +00003094#else
3095 while ((optchr =
Chris Allegretta908f7702003-01-15 11:18:58 +00003096 getopt(argc, argv, "h?BDFIKMNQ:RST:VY:abcefgijklmo:pr:s:tvwxz")) != -1) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003097#endif
3098
3099 switch (optchr) {
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003100
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003101 case 'a':
3102 case 'b':
3103 case 'e':
3104 case 'f':
3105 case 'g':
3106 case 'j':
3107 /* Pico compatibility flags */
3108 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003109#ifndef NANO_SMALL
David Lawrence Ramsey5db0cdc2002-06-28 22:45:14 +00003110 case 'B':
3111 SET(BACKUP_FILE);
3112 break;
Chris Allegretta7004c282001-09-22 00:42:10 +00003113 case 'D':
3114 SET(DOS_FILE);
3115 break;
3116#endif
Chris Allegretta355fbe52001-07-14 19:32:47 +00003117#ifdef ENABLE_MULTIBUFFER
Chris Allegretta307d4c82001-07-15 20:25:33 +00003118 case 'F':
Chris Allegretta355fbe52001-07-14 19:32:47 +00003119 SET(MULTIBUFFER);
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003120 break;
3121#endif
Chris Allegretta6df90f52002-07-19 01:08:59 +00003122#ifdef ENABLE_NANORC
Chris Allegretta6df90f52002-07-19 01:08:59 +00003123 case 'I':
Chris Allegretta7662c862003-01-13 01:35:15 +00003124 SET(NO_RCFILE);
3125 break;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003126#endif
Chris Allegretta48bd3782002-01-03 21:26:34 +00003127 case 'K':
3128 SET(ALT_KEYPAD);
3129 break;
Chris Allegretta8fa1e282001-09-22 04:20:25 +00003130#ifndef NANO_SMALL
3131 case 'M':
3132 SET(MAC_FILE);
3133 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003134 case 'N':
3135 SET(NO_CONVERT);
Chris Allegretta6724a7e2000-06-19 23:19:07 +00003136 break;
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003137#endif
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003138#ifndef DISABLE_JUSTIFY
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003139 case 'Q':
Chris Allegretta7662c862003-01-13 01:35:15 +00003140 quotestr = mallocstrcpy(quotestr, optarg);
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003141 break;
Chris Allegrettae4f940d2002-03-03 22:36:36 +00003142#endif
Chris Allegretta805c26d2000-09-06 13:39:17 +00003143#ifdef HAVE_REGEX_H
Chris Allegretta9fc8d432000-07-07 01:49:52 +00003144 case 'R':
3145 SET(USE_REGEXP);
3146 break;
Chris Allegretta47805612000-07-07 02:35:34 +00003147#endif
Chris Allegretta3e3ae942001-09-22 19:02:04 +00003148#ifndef NANO_SMALL
3149 case 'S':
3150 SET(SMOOTHSCROLL);
3151 break;
3152#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003153 case 'T':
Chris Allegretta6df90f52002-07-19 01:08:59 +00003154 {
3155 int i;
3156 char *first_error;
3157
Chris Allegretta7662c862003-01-13 01:35:15 +00003158 /* Using strtol() instead of atoi() lets us accept 0
3159 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003160 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003161 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003162 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003163 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003164 tabsize = i;
3165 if (tabsize <= 0) {
3166 fprintf(stderr, _("Tab size is too small for nano...\n"));
3167 exit(1);
3168 }
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003169 }
3170 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003171 case 'V':
3172 version();
3173 exit(0);
Chris Allegretta09900ff2002-05-04 04:23:30 +00003174#ifdef ENABLE_COLOR
3175 case 'Y':
3176 syntaxstr = mallocstrcpy(syntaxstr, optarg);
3177 break;
3178#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003179 case 'c':
3180 SET(CONSTUPDATE);
3181 break;
Chris Allegrettaff989832001-09-17 13:48:00 +00003182#ifndef NANO_SMALL
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003183 case 'i':
3184 SET(AUTOINDENT);
3185 break;
Chris Allegretta627de192000-07-12 02:09:17 +00003186 case 'k':
3187 SET(CUT_TO_END);
3188 break;
Chris Allegrettad19e9912000-07-12 18:14:51 +00003189#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003190 case 'l':
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003191 SET(NOFOLLOW_SYMLINKS);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003192 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003193#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003194 case 'm':
3195 SET(USE_MOUSE);
3196 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003197#endif
Chris Allegrettae1f14522001-09-19 03:19:43 +00003198#ifndef DISABLE_OPERATINGDIR
3199 case 'o':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003200 operating_dir = mallocstrcpy(operating_dir, optarg);
Chris Allegrettae1f14522001-09-19 03:19:43 +00003201 break;
3202#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003203 case 'p':
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003204 SET(PRESERVE);
3205#ifdef HAVE_GETOPT_LONG
3206 if (!preserveopt)
3207 do_preserve_msg();
3208#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003209 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003210#ifndef DISABLE_WRAPJUSTIFY
Chris Allegretta6df90f52002-07-19 01:08:59 +00003211 case 'r':
3212 {
3213 int i;
3214 char *first_error;
3215
Chris Allegretta7662c862003-01-13 01:35:15 +00003216 /* Using strtol() instead of atoi() lets us accept 0
3217 * while checking other errors. */
Chris Allegretta6df90f52002-07-19 01:08:59 +00003218 i = (int)strtol(optarg, &first_error, 10);
Chris Allegretta7662c862003-01-13 01:35:15 +00003219 if (errno == ERANGE || *optarg == '\0' || *first_error != '\0')
Chris Allegretta6df90f52002-07-19 01:08:59 +00003220 usage();
Chris Allegretta7662c862003-01-13 01:35:15 +00003221 else
Chris Allegretta6df90f52002-07-19 01:08:59 +00003222 wrap_at = i;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003223 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003224 fill_flag_used = 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003225 break;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003226#endif
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003227#ifndef DISABLE_SPELLER
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003228 case 's':
Chris Allegretta7c27be42002-05-05 23:03:54 +00003229 alt_speller = mallocstrcpy(alt_speller, optarg);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003230 break;
Rocco Corsiaf5c3022001-01-12 07:51:05 +00003231#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003232 case 't':
Chris Allegretta30885552000-07-14 01:20:12 +00003233 SET(TEMP_OPT);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003234 break;
3235 case 'v':
3236 SET(VIEW_MODE);
3237 break;
David Lawrence Ramsey95e0cf52003-01-02 16:32:20 +00003238#ifndef DISABLE_WRAPPING
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003239 case 'w':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003240 SET(NO_WRAP);
3241 break;
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003242#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003243 case 'x':
3244 SET(NO_HELP);
3245 break;
3246 case 'z':
3247 SET(SUSPEND);
3248 break;
3249 default:
3250 usage();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003251 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003252 }
3253
Chris Allegretta7662c862003-01-13 01:35:15 +00003254/* We've read through the command line options. Now back up the flags
3255 and values that are set, and read the rcfile(s). If the values
3256 haven't changed afterward, restore the backed-up values. */
3257#ifdef ENABLE_NANORC
3258 if (!ISSET(NO_RCFILE)) {
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003259#ifndef DISABLE_OPERATINGDIR
Chris Allegretta7662c862003-01-13 01:35:15 +00003260 char *operating_dir_cpy = operating_dir;
3261#endif
3262#ifndef DISABLE_WRAPPING
3263 int wrap_at_cpy = wrap_at;
3264#endif
3265#ifndef DISABLE_JUSTIFY
3266 char *quotestr_cpy = quotestr;
3267#endif
3268#ifndef DISABLE_SPELLER
3269 char *alt_speller_cpy = alt_speller;
3270#endif
3271 int tabsize_cpy = tabsize;
3272 long flags_cpy = flags;
3273
3274 operating_dir = NULL;
3275 quotestr = NULL;
3276 alt_speller = NULL;
3277
3278 do_rcfile();
3279
3280#ifndef DISABLE_OPERATINGDIR
3281 if (operating_dir_cpy != NULL) {
3282 free(operating_dir);
3283 operating_dir = operating_dir_cpy;
3284 }
3285#endif
3286#ifndef DISABLE_WRAPPING
3287 if (fill_flag_used)
3288 wrap_at = wrap_at_cpy;
3289#endif
3290#ifndef DISABLE_JUSTIFY
3291 if (quotestr_cpy != NULL) {
3292 free(quotestr);
3293 quotestr = quotestr_cpy;
3294 }
3295#endif
3296#ifndef DISABLE_SPELLER
3297 if (alt_speller_cpy != NULL) {
3298 free(alt_speller);
3299 alt_speller = alt_speller_cpy;
3300 }
3301#endif
3302 if (tabsize_cpy > 0)
3303 tabsize = tabsize_cpy;
3304 flags |= flags_cpy;
3305 }
3306#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
3307 else if (geteuid() == 0)
3308 SET(NO_WRAP);
3309#endif
3310#endif /* ENABLE_NANORC */
3311
3312#ifndef DISABLE_OPERATINGDIR
3313 /* Set up the operating directory. This entails chdir()ing there,
3314 so that file reads and writes will be based there. */
David Lawrence Ramseye21adfa2002-09-13 18:14:04 +00003315 init_operating_dir();
3316#endif
3317
Chris Allegretta7662c862003-01-13 01:35:15 +00003318#ifndef DISABLE_JUSTIFY
3319 if (quotestr == NULL)
3320#ifdef HAVE_REGEX_H
3321 quotestr = mallocstrcpy(NULL, "^([ \t]*[|>:}#])+");
3322#else
3323 quotestr = mallocstrcpy(NULL, "> ");
3324#endif
3325#endif /* !DISABLE_JUSTIFY */
3326 if (tabsize == -1)
3327 tabsize = 8;
3328
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003329 /* Clear the filename we'll be using */
3330 filename = charalloc(1);
3331 filename[0] = '\0';
3332
Chris Allegretta7662c862003-01-13 01:35:15 +00003333 /* If there's a +LINE flag, it is the first non-option argument. */
3334 if (0 < optind && optind < argc && argv[optind][0] == '+') {
3335 startline = atoi(&argv[optind][1]);
3336 optind++;
3337 }
3338 if (0 < optind && optind < argc)
3339 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003340
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003341 /* See if there's a non-option in argv (first non-option is the
3342 filename, if +LINE is not given) */
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003343 if (argc > 1 && argc > optind) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003344 /* Look for the +line flag... */
3345 if (argv[optind][0] == '+') {
3346 startline = atoi(&argv[optind][1]);
3347 optind++;
Chris Allegretta6df90f52002-07-19 01:08:59 +00003348 if (argc > optind)
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003349 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegretta1a6e9042000-12-14 13:56:28 +00003350 } else
3351 filename = mallocstrcpy(filename, argv[optind]);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003352 }
3353
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003354 /* First back up the old settings so they can be restored, duh */
3355 tcgetattr(0, &oldterm);
3356
3357#ifdef _POSIX_VDISABLE
3358 term = oldterm;
3359 term.c_cc[VINTR] = _POSIX_VDISABLE;
3360 term.c_cc[VQUIT] = _POSIX_VDISABLE;
3361 term.c_lflag &= ~IEXTEN;
3362 tcsetattr(0, TCSANOW, &term);
3363#endif
Chris Allegretta6ca01b12002-03-29 15:38:17 +00003364
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003365 /* now ncurses init stuff... */
3366 initscr();
3367 savetty();
3368 nonl();
3369 cbreak();
3370 noecho();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003371
3372 /* Set up some global variables */
Chris Allegretta56214c62001-09-27 02:46:53 +00003373 global_init(0);
Chris Allegretta07798352000-11-27 22:58:23 +00003374 shortcut_init(0);
Chris Allegretta9b4055c2002-03-29 16:00:59 +00003375 signal_init();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003376
3377#ifdef DEBUG
3378 fprintf(stderr, _("Main: set up windows\n"));
3379#endif
3380
Chris Allegretta2a42af12000-09-12 23:02:49 +00003381 window_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003382#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegretta756f2202000-09-01 13:32:47 +00003383 mouse_init();
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003384#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003385
Chris Allegretta48bd3782002-01-03 21:26:34 +00003386 if (!ISSET(ALT_KEYPAD)) {
3387 keypad(edit, TRUE);
3388 keypad(bottomwin, TRUE);
3389 }
3390
Chris Allegretta5beed502003-01-05 20:41:21 +00003391#ifndef NANO_SMALL
3392 history_init();
3393#endif
3394
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003395#ifdef DEBUG
3396 fprintf(stderr, _("Main: bottom win\n"));
3397#endif
Chris Allegretta88520c92001-05-05 17:45:54 +00003398 /* Set up bottom of window */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003399 display_main_list();
3400
3401#ifdef DEBUG
3402 fprintf(stderr, _("Main: open file\n"));
3403#endif
3404
Chris Allegretta7662c862003-01-13 01:35:15 +00003405 open_file(filename, 1, 1);
3406#ifdef ENABLE_MULTIBUFFER
3407 /* If we're using multibuffers and more than one file is specified
3408 on the command line, load them all and switch to the first one
3409 afterward */
3410 if (ISSET(MULTIBUFFER) && optind + 1 < argc) {
3411 for (optind++; optind < argc; optind++) {
3412 add_open_file(1);
3413 new_file();
3414 filename = mallocstrcpy(filename, argv[optind]);
3415 open_file(filename, 0, 0);
3416 load_file(0);
3417 }
3418 open_nextfile_void();
3419 }
3420#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003421
Chris Allegretta4dc03d52002-05-11 03:04:44 +00003422 titlebar(NULL);
3423
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003424 if (startline > 0)
Chris Allegretta2d7893d2001-07-11 02:08:33 +00003425 do_gotoline(startline, 0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003426
Chris Allegretta7662c862003-01-13 01:35:15 +00003427 /* Return here after a sigwinch */
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003428 sigsetjmp(jmpbuf, 1);
Chris Allegretta08020882001-01-29 23:37:54 +00003429
Chris Allegretta7662c862003-01-13 01:35:15 +00003430 /* This variable should be initialized after the sigsetjmp(), so we
3431 can't do Esc-Esc then quickly resize and muck things up. */
Chris Allegretta08020882001-01-29 23:37:54 +00003432 modify_control_seq = 0;
3433
Robert Siemborski6967eec2000-07-08 14:23:32 +00003434 edit_refresh();
3435 reset_cursor();
3436
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003437 while (1) {
Chris Allegretta7662c862003-01-13 01:35:15 +00003438 int keyhandled = 0; /* Have we handled the keystroke yet? */
3439 int kbinput; /* Input from keyboard */
Chris Allegretta9239d742000-09-06 15:19:18 +00003440
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003441#if !defined(DISABLE_BROWSER) || !defined(DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003442 currshortcut = main_list;
Chris Allegretta6fe61492001-05-21 12:56:25 +00003443#endif
Chris Allegretta6b58acd2001-04-12 03:01:53 +00003444
Chris Allegretta9239d742000-09-06 15:19:18 +00003445#ifndef _POSIX_VDISABLE
3446 /* We're going to have to do it the old way, i.e. on cygwin */
3447 raw();
3448#endif
3449
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003450 kbinput = wgetch(edit);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003451#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003452 fprintf(stderr, _("AHA! %c (%d)\n"), kbinput, kbinput);
Chris Allegrettac08f50d2001-01-06 18:12:43 +00003453#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003454 if (kbinput == 27) { /* Grab Alt-key stuff first */
Chris Allegretta7662c862003-01-13 01:35:15 +00003455 kbinput = wgetch(edit);
3456 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003457 /* Alt-O, suddenly very important ;) */
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003458 case 'O':
Chris Allegretta16e41682000-09-11 22:33:54 +00003459 kbinput = wgetch(edit);
Chris Allegretta7662c862003-01-13 01:35:15 +00003460 /* Shift or Ctrl + Arrows are Alt-O-[2,5,6]-[A,B,C,D] on some terms */
3461 if (kbinput == '2' || kbinput == '5' || kbinput == '6')
3462 kbinput = wgetch(edit);
Chris Allegretta316e4d92001-04-28 16:31:19 +00003463 if ((kbinput <= 'D' && kbinput >= 'A') ||
3464 (kbinput <= 'd' && kbinput >= 'a'))
Chris Allegretta908f7702003-01-15 11:18:58 +00003465 kbinput = abcd(kbinput);
Chris Allegretta201d9bf2001-01-14 03:17:53 +00003466 else if (kbinput <= 'z' && kbinput >= 'j')
3467 print_numlock_warning();
3468 else if (kbinput <= 'S' && kbinput >= 'P')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003469 kbinput = KEY_F(kbinput - 79);
Chris Allegretta16e41682000-09-11 22:33:54 +00003470#ifdef DEBUG
3471 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003472 fprintf(stderr, _("I got Alt-O-%c! (%d)\n"),
3473 kbinput, kbinput);
3474 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003475 }
3476#endif
3477 break;
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003478 case 27:
3479 /* If we get Alt-Alt, the next keystroke should be the same as a
3480 control sequence */
3481 modify_control_seq = 1;
3482 keyhandled = 1;
3483 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003484 case '[':
Chris Allegretta7662c862003-01-13 01:35:15 +00003485 kbinput = wgetch(edit);
3486 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003487 case '1': /* Alt-[-1-[0-5,7-9] = F1-F8 in X at least */
Chris Allegretta16e41682000-09-11 22:33:54 +00003488 kbinput = wgetch(edit);
3489 if (kbinput >= '1' && kbinput <= '5') {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003490 kbinput = KEY_F(kbinput - 48);
3491 wgetch(edit);
3492 } else if (kbinput >= '7' && kbinput <= '9') {
3493 kbinput = KEY_F(kbinput - 49);
3494 wgetch(edit);
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003495 } else if (kbinput == '~')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003496 kbinput = KEY_HOME;
Chris Allegretta16e41682000-09-11 22:33:54 +00003497#ifdef DEBUG
3498 else {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003499 fprintf(stderr, _("I got Alt-[-1-%c! (%d)\n"),
3500 kbinput, kbinput);
3501 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003502 }
3503#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003504 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003505 case '2': /* Alt-[-2-[0,1,3,4] = F9-F12 in many terms */
Chris Allegretta16e41682000-09-11 22:33:54 +00003506 kbinput = wgetch(edit);
Chris Allegretta16e41682000-09-11 22:33:54 +00003507 switch (kbinput) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003508 case '0':
3509 kbinput = KEY_F(9);
3510 wgetch(edit);
3511 break;
3512 case '1':
3513 kbinput = KEY_F(10);
3514 wgetch(edit);
3515 break;
3516 case '3':
3517 kbinput = KEY_F(11);
3518 wgetch(edit);
3519 break;
3520 case '4':
3521 kbinput = KEY_F(12);
3522 wgetch(edit);
3523 break;
Chris Allegrettace78c1e2001-09-23 01:18:03 +00003524 case '~':
Chris Allegretta7662c862003-01-13 01:35:15 +00003525 kbinput = NANO_INSERTFILE_KEY;
3526 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003527#ifdef DEBUG
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003528 default:
3529 fprintf(stderr, _("I got Alt-[-2-%c! (%d)\n"),
3530 kbinput, kbinput);
3531 break;
Chris Allegretta16e41682000-09-11 22:33:54 +00003532#endif
Chris Allegretta16e41682000-09-11 22:33:54 +00003533 }
3534 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003535 case '3': /* Alt-[-3 = Delete? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003536 kbinput = NANO_DELETE_KEY;
3537 wgetch(edit);
3538 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003539 case '4': /* Alt-[-4 = End? */
Chris Allegretta16e41682000-09-11 22:33:54 +00003540 kbinput = NANO_END_KEY;
3541 wgetch(edit);
3542 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003543 case '5': /* Alt-[-5 = Page Up */
Chris Allegretta16e41682000-09-11 22:33:54 +00003544 kbinput = KEY_PPAGE;
3545 wgetch(edit);
3546 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003547 case 'V': /* Alt-[-V = Page Up in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003548 case 'I': /* Alt-[-I = Page Up - FreeBSD Console */
3549 kbinput = KEY_PPAGE;
3550 break;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003551 case '6': /* Alt-[-6 = Page Down */
Chris Allegretta16e41682000-09-11 22:33:54 +00003552 kbinput = KEY_NPAGE;
3553 wgetch(edit);
3554 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003555 case 'U': /* Alt-[-U = Page Down in Hurd Console */
Chris Allegretta7bf72742001-10-28 04:29:55 +00003556 case 'G': /* Alt-[-G = Page Down - FreeBSD Console */
3557 kbinput = KEY_NPAGE;
3558 break;
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003559 case '7':
3560 kbinput = KEY_HOME;
3561 wgetch(edit);
3562 break;
3563 case '8':
3564 kbinput = KEY_END;
3565 wgetch(edit);
3566 break;
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003567 case '9': /* Alt-[-9 = Delete in Hurd Console */
3568 kbinput = KEY_DC;
3569 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003570 case '@': /* Alt-[-@ = Insert in Hurd Console */
3571 case 'L': /* Alt-[-L = Insert - FreeBSD Console */
Chris Allegretta7662c862003-01-13 01:35:15 +00003572 kbinput = NANO_INSERTFILE_KEY;
3573 break;
Chris Allegretta32da4562002-01-02 15:12:21 +00003574 case '[': /* Alt-[-[-[A-E], F1-F5 in Linux console */
Chris Allegretta16e41682000-09-11 22:33:54 +00003575 kbinput = wgetch(edit);
Chris Allegrettab26ecb52001-07-04 16:27:05 +00003576 if (kbinput >= 'A' && kbinput <= 'E')
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003577 kbinput = KEY_F(kbinput - 64);
Chris Allegretta16e41682000-09-11 22:33:54 +00003578 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003579 case 'A':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003580 case 'B':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003581 case 'C':
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003582 case 'D':
Chris Allegretta316e4d92001-04-28 16:31:19 +00003583 case 'a':
3584 case 'b':
3585 case 'c':
3586 case 'd':
Chris Allegretta908f7702003-01-15 11:18:58 +00003587 kbinput = abcd(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003588 break;
3589 case 'H':
3590 kbinput = KEY_HOME;
3591 break;
3592 case 'F':
Chris Allegretta9b8b3702001-11-19 05:09:15 +00003593 case 'Y': /* End Key in Hurd Console */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003594 kbinput = KEY_END;
3595 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003596 default:
3597#ifdef DEBUG
3598 fprintf(stderr, _("I got Alt-[-%c! (%d)\n"),
3599 kbinput, kbinput);
3600#endif
3601 break;
3602 }
3603 break;
Chris Allegretta355fbe52001-07-14 19:32:47 +00003604#ifdef ENABLE_MULTIBUFFER
Chris Allegretta819e3db2001-07-11 02:37:19 +00003605 case NANO_OPENPREV_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003606 case NANO_OPENPREV_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003607 open_prevfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003608 keyhandled = 1;
3609 break;
3610 case NANO_OPENNEXT_KEY:
Chris Allegretta180a5692002-01-02 14:30:33 +00003611 case NANO_OPENNEXT_ALTKEY:
Chris Allegretta6df90f52002-07-19 01:08:59 +00003612 open_nextfile_void();
Chris Allegretta819e3db2001-07-11 02:37:19 +00003613 keyhandled = 1;
3614 break;
Chris Allegretta9cf9e062001-07-11 12:06:13 +00003615#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003616 default:
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003617 /* Check for the altkey defs.... */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003618 for (s = main_list; s != NULL; s = s->next)
Chris Allegretta7662c862003-01-13 01:35:15 +00003619 if (kbinput == s->altval || (kbinput >= 'A' &&
3620 kbinput <= 'Z' && kbinput == s->altval - 32)) {
Chris Allegretta6232d662002-05-12 19:52:15 +00003621 if (ISSET(VIEW_MODE) && !s->viewok)
3622 print_view_warning();
3623 else
3624 s->func();
3625 keyhandled = 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003626 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003627 }
Chris Allegretta756f2202000-09-01 13:32:47 +00003628#ifndef NANO_SMALL
3629 /* And for toggle switches */
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003630 for (t = toggles; t != NULL && !keyhandled; t = t->next)
Chris Allegretta7662c862003-01-13 01:35:15 +00003631 if (kbinput == t->val || (t->val >= 'a' &&
3632 t->val <= 'z' && kbinput == t->val - 32)) {
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003633 do_toggle(t);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003634 keyhandled = 1;
3635 break;
Chris Allegretta756f2202000-09-01 13:32:47 +00003636 }
3637#endif
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003638#ifdef DEBUG
3639 fprintf(stderr, _("I got Alt-%c! (%d)\n"), kbinput,
3640 kbinput);
3641#endif
3642 break;
3643 }
3644 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003645 /* Hack, make insert key do something useful, like insert file */
3646 else if (kbinput == KEY_IC)
3647 kbinput = NANO_INSERTFILE_KEY;
3648
Chris Allegrettacf287c82002-07-20 13:57:41 +00003649 /* If modify_control_seq is set, we received an Alt-Alt
3650 sequence before this, so we make this key a control sequence
3651 by subtracting 32, 64, or 96, depending on its value. */
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003652 if (!keyhandled && modify_control_seq) {
Chris Allegrettacf287c82002-07-20 13:57:41 +00003653 if (kbinput == ' ')
3654 kbinput -= 32;
3655 else if (kbinput >= 'A' && kbinput < 'a')
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003656 kbinput -= 64;
3657 else if (kbinput >= 'a' && kbinput <= 'z')
3658 kbinput -= 96;
3659
3660 modify_control_seq = 0;
3661 }
3662
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003663 /* Look through the main shortcut list to see if we've hit a
3664 shortcut key */
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003665
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003666#if !defined(DISABLE_BROWSER) || !defined (DISABLE_HELP) || (!defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION))
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003667 for (s = currshortcut; s != NULL && !keyhandled; s = s->next) {
Chris Allegrettaf5de33a2002-02-27 04:14:16 +00003668#else
3669 for (s = main_list; s != NULL && !keyhandled; s = s->next) {
3670#endif
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003671 if (kbinput == s->val ||
3672 (s->misc1 && kbinput == s->misc1) ||
3673 (s->misc2 && kbinput == s->misc2)) {
3674 if (ISSET(VIEW_MODE) && !s->viewok)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003675 print_view_warning();
3676 else
Chris Allegrettaa8c22572002-02-15 19:17:02 +00003677 s->func();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003678 keyhandled = 1;
Chris Allegretta7662c862003-01-13 01:35:15 +00003679 /* Rarely, the value of s can change after s->func(),
David Lawrence Ramseyad40fdb2002-09-06 20:35:28 +00003680 leading to problems; get around this by breaking out
3681 explicitly once we successfully handle a shortcut */
3682 break;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003683 }
3684 }
Chris Allegrettae42df732002-10-15 00:27:55 +00003685
3686#ifdef _POSIX_VDISABLE
3687 /* Don't even think about changing this string */
3688 if (kbinput == 19)
3689 statusbar(_("XOFF ignored, mumble mumble."));
Chris Allegretta6cd143d2003-01-05 23:35:44 +00003690 if (kbinput == 17)
3691 statusbar(_("XON ignored, mumble mumble."));
Chris Allegrettae42df732002-10-15 00:27:55 +00003692#endif
Chris Allegretta51b3eec2000-12-18 02:23:50 +00003693 /* If we're in raw mode or using Alt-Alt-x, we have to catch
3694 Control-S and Control-Q */
Chris Allegretta9239d742000-09-06 15:19:18 +00003695 if (kbinput == 17 || kbinput == 19)
3696 keyhandled = 1;
3697
Chris Allegretta7662c862003-01-13 01:35:15 +00003698 /* Catch ^Z by hand when triggered also
Chris Allegretta9caa1932002-02-15 20:08:05 +00003699 407 == ^Z in Linux console when keypad() is used? */
3700 if (kbinput == 26 || kbinput == 407) {
Chris Allegretta9239d742000-09-06 15:19:18 +00003701 if (ISSET(SUSPEND))
3702 do_suspend(0);
3703 keyhandled = 1;
3704 }
Chris Allegretta9239d742000-09-06 15:19:18 +00003705
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003706 /* Last gasp, stuff that's not in the main lists */
3707 if (!keyhandled)
3708 switch (kbinput) {
David Lawrence Ramsey9b13ff32002-12-22 16:30:00 +00003709#if !defined(DISABLE_MOUSE) && defined(NCURSES_MOUSE_VERSION)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003710 case KEY_MOUSE:
3711 do_mouse();
3712 break;
3713#endif
Chris Allegrettaad3f4782001-10-02 03:54:13 +00003714
Chris Allegrettad757e252003-01-15 19:33:27 +00003715 case -1: /* Stuff that we don't want to do squat */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003716 case 0: /* Erg */
Chris Allegrettab3655b42001-10-22 03:15:31 +00003717 case 29: /* Ctrl-] */
Chris Allegretta7662c862003-01-13 01:35:15 +00003718 case 410: /* Must ignore this, it's sent when we resize */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003719#ifdef PDCURSES
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003720 case 541: /* ???? */
3721 case 542: /* Control and alt in Windows *shrug* */
Chris Allegretta72623582000-11-29 23:43:28 +00003722 case 543: /* Right ctrl key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003723 case 544:
Chris Allegretta72623582000-11-29 23:43:28 +00003724 case 545: /* Right alt key */
Chris Allegrettaad1dacc2000-09-21 04:25:45 +00003725#endif
Chris Allegrettabd9e7c32000-10-26 01:44:42 +00003726
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003727 break;
3728 default:
3729#ifdef DEBUG
David Lawrence Ramseyf21cd102002-06-13 00:40:19 +00003730 fprintf(stderr, _("I got %c (%d)!\n"), kbinput, kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003731#endif
3732 /* We no longer stop unhandled sequences so that people with
3733 odd character sets can type... */
3734
Chris Allegretta7662c862003-01-13 01:35:15 +00003735 if (ISSET(VIEW_MODE))
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003736 print_view_warning();
Chris Allegretta7662c862003-01-13 01:35:15 +00003737 else
3738 do_char(kbinput);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003739 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003740
Chris Allegretta7fdbd052001-10-02 00:55:38 +00003741 if (ISSET(DISABLE_CURPOS))
3742 UNSET(DISABLE_CURPOS);
3743 else if (ISSET(CONSTUPDATE))
Chris Allegretta7662c862003-01-13 01:35:15 +00003744 do_cursorpos(1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003745
3746 reset_cursor();
3747 wrefresh(edit);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003748 }
Chris Allegretta7662c862003-01-13 01:35:15 +00003749 assert(0);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00003750}